| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <zephyr/zephyr.h> |
| #include <zephyr/sys/printk.h> |
| #include <zephyr/sys/util.h> |
| |
| #include <zephyr/shell/shell.h> |
| #include <zephyr/settings/settings.h> |
| |
| #include <zephyr/bluetooth/bluetooth.h> |
| #include <zephyr/bluetooth/mesh.h> |
| #include <zephyr/bluetooth/mesh/shell.h> |
| |
| /* Private includes for raw Network & Transport layer access */ |
| #include "mesh.h" |
| #include "net.h" |
| #include "rpl.h" |
| #include "transport.h" |
| #include "foundation.h" |
| #include "settings.h" |
| #include "access.h" |
| |
| #define CID_NVAL 0xffff |
| |
| static const struct shell *ctx_shell; |
| |
| #define shell_print_ctx(_ft, ...) \ |
| do { \ |
| if (ctx_shell != NULL) { \ |
| shell_print(ctx_shell, _ft, ##__VA_ARGS__); \ |
| } \ |
| } while (0) |
| |
| /* Default net, app & dev key values, unless otherwise specified */ |
| static const uint8_t default_key[16] = { |
| 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, |
| 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, |
| }; |
| |
| static struct { |
| uint16_t local; |
| uint16_t dst; |
| uint16_t net_idx; |
| uint16_t app_idx; |
| } net = { |
| .local = BT_MESH_ADDR_UNASSIGNED, |
| .dst = BT_MESH_ADDR_UNASSIGNED, |
| }; |
| |
| static uint8_t cur_faults[BT_MESH_SHELL_CUR_FAULTS_MAX]; |
| static uint8_t reg_faults[BT_MESH_SHELL_CUR_FAULTS_MAX * 2]; |
| |
| static void get_faults(uint8_t *faults, uint8_t faults_size, uint8_t *dst, uint8_t *count) |
| { |
| uint8_t i, limit = *count; |
| |
| for (i = 0U, *count = 0U; i < faults_size && *count < limit; i++) { |
| if (faults[i]) { |
| *dst++ = faults[i]; |
| (*count)++; |
| } |
| } |
| } |
| |
| static int fault_get_cur(struct bt_mesh_model *model, uint8_t *test_id, |
| uint16_t *company_id, uint8_t *faults, uint8_t *fault_count) |
| { |
| shell_print_ctx("Sending current faults"); |
| |
| *test_id = 0x00; |
| *company_id = BT_COMP_ID_LF; |
| |
| get_faults(cur_faults, sizeof(cur_faults), faults, fault_count); |
| |
| return 0; |
| } |
| |
| static int fault_get_reg(struct bt_mesh_model *model, uint16_t cid, |
| uint8_t *test_id, uint8_t *faults, uint8_t *fault_count) |
| { |
| if (cid != CONFIG_BT_COMPANY_ID) { |
| shell_print_ctx("Faults requested for unknown Company ID" |
| " 0x%04x", cid); |
| return -EINVAL; |
| } |
| |
| shell_print_ctx("Sending registered faults"); |
| |
| *test_id = 0x00; |
| |
| get_faults(reg_faults, sizeof(reg_faults), faults, fault_count); |
| |
| return 0; |
| } |
| |
| static int fault_clear(struct bt_mesh_model *model, uint16_t cid) |
| { |
| if (cid != CONFIG_BT_COMPANY_ID) { |
| return -EINVAL; |
| } |
| |
| (void)memset(reg_faults, 0, sizeof(reg_faults)); |
| |
| return 0; |
| } |
| |
| static int fault_test(struct bt_mesh_model *model, uint8_t test_id, |
| uint16_t cid) |
| { |
| if (cid != CONFIG_BT_COMPANY_ID) { |
| return -EINVAL; |
| } |
| |
| if (test_id != 0x00) { |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| static const struct bt_mesh_health_srv_cb health_srv_cb = { |
| .fault_get_cur = fault_get_cur, |
| .fault_get_reg = fault_get_reg, |
| .fault_clear = fault_clear, |
| .fault_test = fault_test, |
| }; |
| |
| struct bt_mesh_health_srv bt_mesh_shell_health_srv = { |
| .cb = &health_srv_cb, |
| }; |
| |
| #if defined(CONFIG_BT_MESH_HEALTH_CLI) |
| static void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) |
| { |
| size_t i; |
| |
| if (!fault_count) { |
| shell_print_ctx("Health Test ID 0x%02x Company ID " |
| "0x%04x: no faults", test_id, cid); |
| return; |
| } |
| |
| shell_print_ctx("Health Test ID 0x%02x Company ID 0x%04x Fault " |
| "Count %zu:", test_id, cid, fault_count); |
| |
| for (i = 0; i < fault_count; i++) { |
| shell_print_ctx("\t0x%02x", faults[i]); |
| } |
| } |
| |
| static void health_current_status(struct bt_mesh_health_cli *cli, uint16_t addr, |
| uint8_t test_id, uint16_t cid, uint8_t *faults, |
| size_t fault_count) |
| { |
| shell_print_ctx("Health Current Status from 0x%04x", addr); |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| static void health_fault_status(struct bt_mesh_health_cli *cli, uint16_t addr, |
| uint8_t test_id, uint16_t cid, uint8_t *faults, |
| size_t fault_count) |
| { |
| shell_print_ctx("Health Fault Status from 0x%04x", addr); |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| static void health_attention_status(struct bt_mesh_health_cli *cli, |
| uint16_t addr, uint8_t attention) |
| { |
| shell_print_ctx("Health Attention Status from 0x%04x: %u", addr, attention); |
| } |
| |
| static void health_period_status(struct bt_mesh_health_cli *cli, uint16_t addr, |
| uint8_t period) |
| { |
| shell_print_ctx("Health Fast Period Divisor Status from 0x%04x: %u", addr, period); |
| } |
| |
| struct bt_mesh_health_cli bt_mesh_shell_health_cli = { |
| .current_status = health_current_status, |
| .fault_status = health_fault_status, |
| .attention_status = health_attention_status, |
| .period_status = health_period_status, |
| }; |
| #endif /* CONFIG_BT_MESH_HEALTH_CLI */ |
| |
| static uint8_t dev_uuid[16] = { 0xdd, 0xdd }; |
| |
| static void prov_complete(uint16_t net_idx, uint16_t addr) |
| { |
| |
| shell_print_ctx("Local node provisioned, net_idx 0x%04x address " |
| "0x%04x", net_idx, addr); |
| |
| net.local = addr; |
| net.net_idx = net_idx, |
| net.dst = addr; |
| } |
| |
| static void prov_node_added(uint16_t net_idx, uint8_t uuid[16], uint16_t addr, |
| uint8_t num_elem) |
| { |
| shell_print_ctx("Node provisioned, net_idx 0x%04x address " |
| "0x%04x elements %d", net_idx, addr, num_elem); |
| |
| net.net_idx = net_idx, |
| net.dst = addr; |
| } |
| |
| static void prov_input_complete(void) |
| { |
| shell_print_ctx("Input complete"); |
| } |
| |
| static void prov_reset(void) |
| { |
| shell_print_ctx("The local node has been reset and needs " |
| "reprovisioning"); |
| } |
| |
| static int output_number(bt_mesh_output_action_t action, uint32_t number) |
| { |
| shell_print_ctx("OOB Number: %u", number); |
| return 0; |
| } |
| |
| static int output_string(const char *str) |
| { |
| shell_print_ctx("OOB String: %s", str); |
| return 0; |
| } |
| |
| static bt_mesh_input_action_t input_act; |
| static uint8_t input_size; |
| |
| static int cmd_input_num(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| uint32_t val; |
| |
| if (input_act != BT_MESH_ENTER_NUMBER) { |
| shell_print(shell, "A number hasn't been requested!"); |
| return 0; |
| } |
| |
| if (strlen(argv[1]) < input_size) { |
| shell_print(shell, "Too short input (%u digits required)", |
| input_size); |
| return 0; |
| } |
| |
| val = shell_strtoul(argv[1], 10, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_input_number(val); |
| if (err) { |
| shell_error(shell, "Numeric input failed (err %d)", err); |
| return 0; |
| } |
| |
| input_act = BT_MESH_NO_INPUT; |
| return 0; |
| } |
| |
| static int cmd_input_str(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err; |
| |
| if (input_act != BT_MESH_ENTER_STRING) { |
| shell_print(shell, "A string hasn't been requested!"); |
| return 0; |
| } |
| |
| if (strlen(argv[1]) < input_size) { |
| shell_print(shell, "Too short input (%u characters required)", |
| input_size); |
| return 0; |
| } |
| |
| err = bt_mesh_input_string(argv[1]); |
| if (err) { |
| shell_error(shell, "String input failed (err %d)", err); |
| return 0; |
| } |
| |
| input_act = BT_MESH_NO_INPUT; |
| return 0; |
| } |
| |
| static int input(bt_mesh_input_action_t act, uint8_t size) |
| { |
| |
| switch (act) { |
| case BT_MESH_ENTER_NUMBER: |
| shell_print_ctx("Enter a number (max %u digits) with: " |
| "input-num <num>", size); |
| break; |
| case BT_MESH_ENTER_STRING: |
| shell_print_ctx("Enter a string (max %u chars) with: " |
| "input-str <str>", size); |
| break; |
| default: |
| if (ctx_shell != NULL) { |
| shell_error(ctx_shell, "Unknown input action %u (size %u) " |
| "requested!", act, size); |
| } |
| return -EINVAL; |
| } |
| |
| input_act = act; |
| input_size = size; |
| return 0; |
| } |
| |
| static const char *bearer2str(bt_mesh_prov_bearer_t bearer) |
| { |
| switch (bearer) { |
| case BT_MESH_PROV_ADV: |
| return "PB-ADV"; |
| case BT_MESH_PROV_GATT: |
| return "PB-GATT"; |
| default: |
| return "unknown"; |
| } |
| } |
| |
| static void link_open(bt_mesh_prov_bearer_t bearer) |
| { |
| shell_print_ctx("Provisioning link opened on %s", bearer2str(bearer)); |
| } |
| |
| static void link_close(bt_mesh_prov_bearer_t bearer) |
| { |
| shell_print_ctx("Provisioning link closed on %s", bearer2str(bearer)); |
| } |
| |
| static uint8_t static_val[16]; |
| |
| struct bt_mesh_prov bt_mesh_shell_prov = { |
| .uuid = dev_uuid, |
| .link_open = link_open, |
| .link_close = link_close, |
| .complete = prov_complete, |
| .node_added = prov_node_added, |
| .reset = prov_reset, |
| .static_val = NULL, |
| .static_val_len = 0, |
| .output_size = 6, |
| .output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING), |
| .output_number = output_number, |
| .output_string = output_string, |
| .input_size = 6, |
| .input_actions = (BT_MESH_ENTER_NUMBER | BT_MESH_ENTER_STRING), |
| .input = input, |
| .input_complete = prov_input_complete, |
| }; |
| |
| static int cmd_static_oob(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| if (argc < 2) { |
| bt_mesh_shell_prov.static_val = NULL; |
| bt_mesh_shell_prov.static_val_len = 0U; |
| } else { |
| bt_mesh_shell_prov.static_val_len = hex2bin(argv[1], strlen(argv[1]), |
| static_val, 16); |
| if (bt_mesh_shell_prov.static_val_len) { |
| bt_mesh_shell_prov.static_val = static_val; |
| } else { |
| bt_mesh_shell_prov.static_val = NULL; |
| } |
| } |
| |
| if (bt_mesh_shell_prov.static_val) { |
| shell_print(shell, "Static OOB value set (length %u)", |
| bt_mesh_shell_prov.static_val_len); |
| } else { |
| shell_print(shell, "Static OOB value cleared"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_uuid(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t uuid[16]; |
| size_t len; |
| |
| len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid)); |
| if (len < 1) { |
| return -EINVAL; |
| } |
| |
| memcpy(dev_uuid, uuid, len); |
| (void)memset(dev_uuid + len, 0, sizeof(dev_uuid) - len); |
| |
| shell_print(shell, "Device UUID set"); |
| |
| return 0; |
| } |
| |
| static int cmd_init(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| |
| ctx_shell = sh; |
| shell_print(sh, "Mesh shell initialized"); |
| |
| return 0; |
| } |
| |
| static int cmd_reset(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| uint16_t addr; |
| |
| addr = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (addr == net.local) { |
| bt_mesh_reset(); |
| shell_print(shell, "Local node reset complete"); |
| } else if (IS_ENABLED(CONFIG_BT_MESH_CFG_CLI)) { |
| int err; |
| bool reset = false; |
| |
| err = bt_mesh_cfg_node_reset(net.net_idx, net.dst, &reset); |
| if (err) { |
| shell_error(shell, "Unable to send " |
| "Remote Node Reset (err %d)", err); |
| return 0; |
| } |
| |
| shell_print(shell, "Remote node reset complete"); |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_MESH_LOW_POWER) |
| static int cmd_lpn(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| static bool enabled; |
| bool onoff; |
| int err = 0; |
| |
| if (argc < 2) { |
| shell_print(shell, "%s", enabled ? "enabled" : "disabled"); |
| return 0; |
| } |
| |
| onoff = shell_strtobool(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (onoff) { |
| if (enabled) { |
| shell_print(shell, "LPN already enabled"); |
| return 0; |
| } |
| |
| err = bt_mesh_lpn_set(true); |
| if (err) { |
| shell_error(shell, "Enabling LPN failed (err %d)", err); |
| } else { |
| enabled = true; |
| } |
| } else { |
| if (!enabled) { |
| shell_print(shell, "LPN already disabled"); |
| return 0; |
| } |
| |
| err = bt_mesh_lpn_set(false); |
| if (err) { |
| shell_error(shell, "Enabling LPN failed (err %d)", err); |
| } else { |
| enabled = false; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_poll(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err; |
| |
| err = bt_mesh_lpn_poll(); |
| if (err) { |
| shell_error(shell, "Friend Poll failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| static void lpn_established(uint16_t net_idx, uint16_t friend_addr, |
| uint8_t queue_size, uint8_t recv_win) |
| { |
| shell_print_ctx("Friendship (as LPN) established to " |
| "Friend 0x%04x Queue Size %d Receive Window %d", |
| friend_addr, queue_size, recv_win); |
| } |
| |
| static void lpn_terminated(uint16_t net_idx, uint16_t friend_addr) |
| { |
| shell_print_ctx("Friendship (as LPN) lost with Friend " |
| "0x%04x", friend_addr); |
| } |
| |
| BT_MESH_LPN_CB_DEFINE(lpn_cb) = { |
| .established = lpn_established, |
| .terminated = lpn_terminated, |
| }; |
| |
| #endif /* MESH_LOW_POWER */ |
| |
| #if defined(CONFIG_BT_MESH_GATT_PROXY) |
| static int cmd_ident(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err; |
| |
| err = bt_mesh_proxy_identity_enable(); |
| if (err) { |
| shell_error(shell, "Failed advertise using Node Identity (err " |
| "%d)", err); |
| } |
| |
| return 0; |
| } |
| #endif /* MESH_GATT_PROXY */ |
| |
| #if defined(CONFIG_BT_MESH_CFG_CLI) |
| static int cmd_get_comp(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_RX_SDU_MAX); |
| struct bt_mesh_comp_p0_elem elem; |
| struct bt_mesh_comp_p0 comp; |
| uint8_t page = 0x00; |
| int err = 0; |
| |
| if (argc > 1) { |
| page = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| } |
| |
| err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, &page, |
| &buf); |
| if (err) { |
| shell_error(shell, "Getting composition failed (err %d)", err); |
| return 0; |
| } |
| |
| if (page != 0x00) { |
| shell_print(shell, "Got page 0x%02x. No parser available.", |
| page); |
| return 0; |
| } |
| |
| err = bt_mesh_comp_p0_get(&comp, &buf); |
| if (err) { |
| shell_error(shell, "Couldn't parse Composition data (err %d)", |
| err); |
| return 0; |
| } |
| |
| shell_print(shell, "Got Composition Data for 0x%04x:", net.dst); |
| shell_print(shell, "\tCID 0x%04x", comp.cid); |
| shell_print(shell, "\tPID 0x%04x", comp.pid); |
| shell_print(shell, "\tVID 0x%04x", comp.vid); |
| shell_print(shell, "\tCRPL 0x%04x", comp.crpl); |
| shell_print(shell, "\tFeatures 0x%04x", comp.feat); |
| |
| while (bt_mesh_comp_p0_elem_pull(&comp, &elem)) { |
| int i; |
| |
| shell_print(shell, "\tElement @ 0x%04x:", elem.loc); |
| |
| if (elem.nsig) { |
| shell_print(shell, "\t\tSIG Models:"); |
| } else { |
| shell_print(shell, "\t\tNo SIG Models"); |
| } |
| |
| for (i = 0; i < elem.nsig; i++) { |
| uint16_t mod_id = bt_mesh_comp_p0_elem_mod(&elem, i); |
| |
| shell_print(shell, "\t\t\t0x%04x", mod_id); |
| } |
| |
| if (elem.nvnd) { |
| shell_print(shell, "\t\tVendor Models:"); |
| } else { |
| shell_print(shell, "\t\tNo Vendor Models"); |
| } |
| |
| for (i = 0; i < elem.nvnd; i++) { |
| struct bt_mesh_mod_id_vnd mod = |
| bt_mesh_comp_p0_elem_mod_vnd(&elem, i); |
| |
| shell_print(shell, "\t\t\tCompany 0x%04x: 0x%04x", |
| mod.company, mod.id); |
| } |
| } |
| |
| if (buf.len) { |
| shell_print(shell, "\t\t...truncated data!"); |
| } |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_MESH_CFG_CLI */ |
| |
| static int cmd_dst(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| |
| if (argc < 2) { |
| shell_print(shell, "Destination address: 0x%04x%s", net.dst, |
| net.dst == net.local ? " (local)" : ""); |
| return 0; |
| } |
| |
| if (!strcmp(argv[1], "local")) { |
| net.dst = net.local; |
| } else { |
| net.dst = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| } |
| |
| shell_print(shell, "Destination address set to 0x%04x%s", net.dst, |
| net.dst == net.local ? " (local)" : ""); |
| return 0; |
| } |
| |
| static int cmd_netidx(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| |
| if (argc < 2) { |
| shell_print(shell, "NetIdx: 0x%04x", net.net_idx); |
| return 0; |
| } |
| |
| net.net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| shell_print(shell, "NetIdx set to 0x%04x", net.net_idx); |
| return 0; |
| } |
| |
| static int cmd_appidx(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| |
| if (argc < 2) { |
| shell_print(shell, "AppIdx: 0x%04x", net.app_idx); |
| return 0; |
| } |
| |
| net.app_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| shell_print(shell, "AppIdx set to 0x%04x", net.app_idx); |
| return 0; |
| } |
| |
| static int cmd_net_send(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| NET_BUF_SIMPLE_DEFINE(msg, 32); |
| struct bt_mesh_msg_ctx ctx = { |
| .send_ttl = BT_MESH_TTL_DEFAULT, |
| .net_idx = net.net_idx, |
| .addr = net.dst, |
| .app_idx = net.app_idx, |
| |
| }; |
| struct bt_mesh_net_tx tx = { |
| .ctx = &ctx, |
| .src = net.local, |
| }; |
| size_t len; |
| int err; |
| |
| len = hex2bin(argv[1], strlen(argv[1]), |
| msg.data, net_buf_simple_tailroom(&msg) - 4); |
| net_buf_simple_add(&msg, len); |
| |
| err = bt_mesh_trans_send(&tx, &msg, NULL, NULL); |
| if (err) { |
| shell_error(shell, "Failed to send (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_MESH_IV_UPDATE_TEST) |
| static int cmd_iv_update(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| if (bt_mesh_iv_update()) { |
| shell_print(shell, "Transitioned to IV Update In Progress " |
| "state"); |
| } else { |
| shell_print(shell, "Transitioned to IV Update Normal state"); |
| } |
| |
| shell_print(shell, "IV Index is 0x%08x", bt_mesh.iv_index); |
| |
| return 0; |
| } |
| |
| static int cmd_iv_update_test(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| int err = 0; |
| bool enable; |
| |
| enable = shell_strtobool(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (enable) { |
| shell_print(shell, "Enabling IV Update test mode"); |
| } else { |
| shell_print(shell, "Disabling IV Update test mode"); |
| } |
| |
| bt_mesh_iv_update_test(enable); |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_MESH_IV_UPDATE_TEST */ |
| |
| static int cmd_rpl_clear(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| bt_mesh_rpl_clear(); |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_MESH_CFG_CLI) |
| static int cmd_beacon(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t status; |
| int err = 0; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_beacon_get(net.net_idx, net.dst, &status); |
| } else { |
| uint8_t val = shell_strtobool(argv[1], 0, &err); |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_beacon_set(net.net_idx, net.dst, val, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Beacon Get/Set message " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| shell_print(shell, "Beacon state is 0x%02x", status); |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_MESH_CFG_CLI */ |
| |
| static void print_unprovisioned_beacon(uint8_t uuid[16], |
| bt_mesh_prov_oob_info_t oob_info, |
| uint32_t *uri_hash) |
| { |
| char uuid_hex_str[32 + 1]; |
| |
| bin2hex(uuid, 16, uuid_hex_str, sizeof(uuid_hex_str)); |
| |
| shell_print_ctx("PB-ADV UUID %s, OOB Info 0x%04x, URI Hash 0x%x", |
| uuid_hex_str, oob_info, |
| (uri_hash == NULL ? 0 : *uri_hash)); |
| } |
| |
| #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT) |
| static void pb_gatt_unprovisioned(uint8_t uuid[16], |
| bt_mesh_prov_oob_info_t oob_info) |
| { |
| char uuid_hex_str[32 + 1]; |
| |
| bin2hex(uuid, 16, uuid_hex_str, sizeof(uuid_hex_str)); |
| |
| shell_print_ctx("PB-GATT UUID %s, OOB Info 0x%04x", uuid_hex_str, oob_info); |
| } |
| |
| static int cmd_provision_gatt(const struct shell *sh, size_t argc, |
| char *argv[]) |
| { |
| static uint8_t uuid[16]; |
| uint8_t attention_duration; |
| uint16_t net_idx; |
| uint16_t addr; |
| size_t len; |
| int err = 0; |
| |
| len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid)); |
| (void)memset(uuid + len, 0, sizeof(uuid) - len); |
| |
| net_idx = shell_strtoul(argv[2], 0, &err); |
| addr = shell_strtoul(argv[3], 0, &err); |
| attention_duration = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_provision_gatt(uuid, net_idx, addr, attention_duration); |
| if (err) { |
| shell_error(sh, "Provisioning failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| #if defined(CONFIG_BT_MESH_PROXY_CLIENT) |
| static int cmd_proxy_connect(const struct shell *sh, size_t argc, |
| char *argv[]) |
| { |
| uint16_t net_idx; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_proxy_connect(net_idx); |
| if (err) { |
| shell_error(sh, "Proxy connect failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_proxy_disconnect(const struct shell *sh, size_t argc, |
| char *argv[]) |
| { |
| uint16_t net_idx; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_proxy_disconnect(net_idx); |
| if (err) { |
| shell_error(sh, "Proxy disconnect failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| static int cmd_beacon_listen(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| int err = 0; |
| bool val = shell_strtobool(argv[1], 0, &err); |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (val) { |
| bt_mesh_shell_prov.unprovisioned_beacon = print_unprovisioned_beacon; |
| #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT) |
| bt_mesh_shell_prov.unprovisioned_beacon_gatt = pb_gatt_unprovisioned; |
| #endif |
| } else { |
| bt_mesh_shell_prov.unprovisioned_beacon = NULL; |
| bt_mesh_shell_prov.unprovisioned_beacon_gatt = NULL; |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_MESH_CFG_CLI) |
| static int cmd_ttl(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t ttl; |
| int err = 0; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_ttl_get(net.net_idx, net.dst, &ttl); |
| } else { |
| uint8_t val = shell_strtoul(argv[1], 0, &err); |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_ttl_set(net.net_idx, net.dst, val, &ttl); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Default TTL Get/Set " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| shell_print(shell, "Default TTL is 0x%02x", ttl); |
| |
| return 0; |
| } |
| |
| static int cmd_friend(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t frnd; |
| int err = 0; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_friend_get(net.net_idx, net.dst, &frnd); |
| } else { |
| uint8_t val = shell_strtobool(argv[1], 0, &err); |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_friend_set(net.net_idx, net.dst, val, &frnd); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Friend Get/Set (err %d)", |
| err); |
| return 0; |
| } |
| |
| shell_print(shell, "Friend is set to 0x%02x", frnd); |
| |
| return 0; |
| } |
| |
| static int cmd_gatt_proxy(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t proxy; |
| int err = 0; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_gatt_proxy_get(net.net_idx, net.dst, &proxy); |
| } else { |
| uint8_t val = shell_strtobool(argv[1], 0, &err); |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_gatt_proxy_set(net.net_idx, net.dst, val, |
| &proxy); |
| } |
| |
| if (err) { |
| shell_print(shell, "Unable to send GATT Proxy Get/Set " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| shell_print(shell, "GATT Proxy is set to 0x%02x", proxy); |
| |
| return 0; |
| } |
| |
| static int cmd_polltimeout_get(const struct shell *sh, |
| size_t argc, char *argv[]) |
| { |
| uint16_t lpn_address; |
| int32_t poll_timeout; |
| int err = 0; |
| |
| lpn_address = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_lpn_timeout_get(net.net_idx, |
| net.dst, lpn_address, |
| &poll_timeout); |
| if (err) { |
| shell_error(sh, "Unable to send LPN PollTimeout Get" |
| " (err %d)", err); |
| return 0; |
| } |
| |
| shell_print(sh, "PollTimeout value %d", poll_timeout); |
| |
| return 0; |
| } |
| |
| static int cmd_net_transmit(const struct shell *shell, |
| size_t argc, char *argv[]) |
| { |
| uint8_t transmit; |
| int err = 0; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_net_transmit_get(net.net_idx, |
| net.dst, &transmit); |
| } else { |
| if (argc != 3) { |
| shell_error(shell, "Wrong number of input arguments" |
| "(2 arguments are required)"); |
| return -EINVAL; |
| } |
| |
| uint8_t count, interval, new_transmit; |
| |
| count = shell_strtoul(argv[1], 0, &err); |
| interval = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| new_transmit = BT_MESH_TRANSMIT(count, interval); |
| |
| err = bt_mesh_cfg_net_transmit_set(net.net_idx, net.dst, |
| new_transmit, &transmit); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send network transmit" |
| " Get/Set (err %d)", err); |
| return 0; |
| } |
| |
| shell_print(shell, "Transmit 0x%02x (count %u interval %ums)", |
| transmit, BT_MESH_TRANSMIT_COUNT(transmit), |
| BT_MESH_TRANSMIT_INT(transmit)); |
| |
| return 0; |
| } |
| |
| static int cmd_relay(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t relay, transmit; |
| int err = 0; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_relay_get(net.net_idx, net.dst, &relay, |
| &transmit); |
| } else { |
| uint8_t count, interval, new_transmit; |
| uint8_t val = shell_strtobool(argv[1], 0, &err); |
| |
| if (val) { |
| if (argc > 2) { |
| count = shell_strtoul(argv[2], 0, &err); |
| } else { |
| count = 2U; |
| } |
| |
| if (argc > 3) { |
| interval = shell_strtoul(argv[3], 0, &err); |
| } else { |
| interval = 20U; |
| } |
| |
| new_transmit = BT_MESH_TRANSMIT(count, interval); |
| } else { |
| new_transmit = 0U; |
| } |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_relay_set(net.net_idx, net.dst, val, |
| new_transmit, &relay, &transmit); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Relay Get/Set (err %d)", |
| err); |
| return 0; |
| } |
| |
| shell_print(shell, "Relay is 0x%02x, Transmit 0x%02x (count %u interval" |
| " %ums)", relay, transmit, BT_MESH_TRANSMIT_COUNT(transmit), |
| BT_MESH_TRANSMIT_INT(transmit)); |
| |
| return 0; |
| } |
| |
| static int cmd_net_key_add(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| bool has_key_val = (argc > 2); |
| uint8_t key_val[16]; |
| uint16_t key_net_idx; |
| uint8_t status; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (has_key_val) { |
| size_t len; |
| |
| len = hex2bin(argv[3], strlen(argv[3]), |
| key_val, sizeof(key_val)); |
| (void)memset(key_val, 0, sizeof(key_val) - len); |
| } else { |
| memcpy(key_val, default_key, sizeof(key_val)); |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { |
| struct bt_mesh_cdb_subnet *subnet; |
| |
| subnet = bt_mesh_cdb_subnet_get(key_net_idx); |
| if (subnet) { |
| if (has_key_val) { |
| shell_error(shell, |
| "Subnet 0x%03x already has a value", |
| key_net_idx); |
| return 0; |
| } |
| |
| memcpy(key_val, subnet->keys[0].net_key, 16); |
| } else { |
| subnet = bt_mesh_cdb_subnet_alloc(key_net_idx); |
| if (!subnet) { |
| shell_error(shell, |
| "No space for subnet in cdb"); |
| return 0; |
| } |
| |
| memcpy(subnet->keys[0].net_key, key_val, 16); |
| bt_mesh_cdb_subnet_store(subnet); |
| } |
| } |
| |
| err = bt_mesh_cfg_net_key_add(net.net_idx, net.dst, key_net_idx, |
| key_val, &status); |
| if (err) { |
| shell_print(shell, "Unable to send NetKey Add (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "NetKeyAdd failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "NetKey added with NetKey Index 0x%03x", |
| key_net_idx); |
| } |
| |
| return 0; |
| } |
| |
| |
| static int cmd_net_key_update(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| bool has_key_val = (argc > 2); |
| uint8_t key_val[16]; |
| uint16_t key_net_idx; |
| uint8_t status; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (has_key_val) { |
| size_t len; |
| |
| len = hex2bin(argv[2], strlen(argv[2]), |
| key_val, sizeof(key_val)); |
| (void)memset(key_val, 0, sizeof(key_val) - len); |
| } else { |
| memcpy(key_val, default_key, sizeof(key_val)); |
| } |
| |
| err = bt_mesh_cfg_net_key_update(net.net_idx, net.dst, key_net_idx, |
| key_val, &status); |
| if (err) { |
| shell_print(sh, "Unable to send NetKey Update (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(sh, "NetKeyUpdate failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(sh, "NetKey updated with NetKey Index 0x%03x", |
| key_net_idx); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_net_key_get(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint16_t keys[16]; |
| size_t cnt; |
| int err, i; |
| |
| cnt = ARRAY_SIZE(keys); |
| |
| err = bt_mesh_cfg_net_key_get(net.net_idx, net.dst, keys, &cnt); |
| if (err) { |
| shell_print(shell, "Unable to send NetKeyGet (err %d)", err); |
| return 0; |
| } |
| |
| shell_print(shell, "NetKeys known by 0x%04x:", net.dst); |
| for (i = 0; i < cnt; i++) { |
| shell_print(shell, "\t0x%03x", keys[i]); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_net_key_del(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint16_t key_net_idx; |
| uint8_t status; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_net_key_del(net.net_idx, net.dst, key_net_idx, |
| &status); |
| if (err) { |
| shell_print(shell, "Unable to send NetKeyDel (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "NetKeyDel failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "NetKey 0x%03x deleted", key_net_idx); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_app_key_add(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t key_val[16]; |
| uint16_t key_net_idx, key_app_idx; |
| bool has_key_val = (argc > 3); |
| uint8_t status; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| key_app_idx = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (has_key_val) { |
| size_t len; |
| |
| len = hex2bin(argv[3], strlen(argv[3]), |
| key_val, sizeof(key_val)); |
| (void)memset(key_val, 0, sizeof(key_val) - len); |
| } else { |
| memcpy(key_val, default_key, sizeof(key_val)); |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { |
| struct bt_mesh_cdb_app_key *app_key; |
| |
| app_key = bt_mesh_cdb_app_key_get(key_app_idx); |
| if (app_key) { |
| if (has_key_val) { |
| shell_error( |
| shell, |
| "App key 0x%03x already has a value", |
| key_app_idx); |
| return 0; |
| } |
| |
| memcpy(key_val, app_key->keys[0].app_key, 16); |
| } else { |
| app_key = bt_mesh_cdb_app_key_alloc(key_net_idx, |
| key_app_idx); |
| if (!app_key) { |
| shell_error(shell, |
| "No space for app key in cdb"); |
| return 0; |
| } |
| |
| memcpy(app_key->keys[0].app_key, key_val, 16); |
| bt_mesh_cdb_app_key_store(app_key); |
| } |
| } |
| |
| err = bt_mesh_cfg_app_key_add(net.net_idx, net.dst, key_net_idx, |
| key_app_idx, key_val, &status); |
| if (err) { |
| shell_error(shell, "Unable to send App Key Add (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "AppKeyAdd failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "AppKey added, NetKeyIndex 0x%04x " |
| "AppKeyIndex 0x%04x", key_net_idx, key_app_idx); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_app_key_upd(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| uint8_t key_val[16]; |
| uint16_t key_net_idx, key_app_idx; |
| bool has_key_val = (argc > 3); |
| uint8_t status; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| key_app_idx = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (has_key_val) { |
| size_t len; |
| |
| len = hex2bin(argv[3], strlen(argv[3]), |
| key_val, sizeof(key_val)); |
| (void)memset(key_val, 0, sizeof(key_val) - len); |
| } else { |
| memcpy(key_val, default_key, sizeof(key_val)); |
| } |
| |
| err = bt_mesh_cfg_app_key_update(net.net_idx, net.dst, key_net_idx, |
| key_app_idx, key_val, &status); |
| if (err) { |
| shell_error(sh, "Unable to send App Key Update (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(sh, "AppKey update failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(sh, "AppKey updated, NetKeyIndex 0x%04x " |
| "AppKeyIndex 0x%04x", key_net_idx, key_app_idx); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_app_key_get(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint16_t net_idx; |
| uint16_t keys[16]; |
| size_t cnt; |
| uint8_t status; |
| int err = 0; |
| int i; |
| |
| cnt = ARRAY_SIZE(keys); |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| |
| err = bt_mesh_cfg_app_key_get(net.net_idx, net.dst, net_idx, &status, |
| keys, &cnt); |
| if (err) { |
| shell_print(shell, "Unable to send AppKeyGet (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "AppKeyGet failed with status 0x%02x", |
| status); |
| return 0; |
| } |
| |
| shell_print(shell, |
| "AppKeys for NetKey 0x%03x known by 0x%04x:", net_idx, |
| net.dst); |
| for (i = 0; i < cnt; i++) { |
| shell_print(shell, "\t0x%03x", keys[i]); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_node_id(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| uint16_t net_idx; |
| uint8_t status, identify; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_node_identity_get(net.net_idx, net.dst, |
| net_idx, &status, |
| &identify); |
| if (err) { |
| shell_print(sh, "Unable to send Node Identify Get (err %d)", err); |
| return 0; |
| } |
| } else { |
| uint8_t new_identify = shell_strtoul(argv[2], 0, &err); |
| |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_node_identity_set(net.net_idx, net.dst, net_idx, new_identify, |
| &status, &identify); |
| if (err) { |
| shell_print(sh, "Unable to send Node Identify Set (err %d)", err); |
| return 0; |
| } |
| } |
| |
| |
| if (status) { |
| shell_print(sh, "Node Identify Get/Set failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(sh, "Node Identify Get/Set successful with identify 0x%02x", |
| identify); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_app_key_del(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint16_t key_net_idx, key_app_idx; |
| uint8_t status; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| key_app_idx = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_app_key_del(net.net_idx, net.dst, key_net_idx, |
| key_app_idx, &status); |
| if (err) { |
| shell_error(shell, "Unable to send App Key del(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "AppKeyDel failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "AppKey deleted, NetKeyIndex 0x%04x " |
| "AppKeyIndex 0x%04x", key_net_idx, key_app_idx); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_app_bind(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, mod_app_idx, mod_id, cid; |
| uint8_t status; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| mod_app_idx = shell_strtoul(argv[2], 0, &err); |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_app_bind_vnd(net.net_idx, net.dst, |
| elem_addr, mod_app_idx, |
| mod_id, cid, &status); |
| } else { |
| err = bt_mesh_cfg_mod_app_bind(net.net_idx, net.dst, elem_addr, |
| mod_app_idx, mod_id, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model App Bind (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model App Bind failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "AppKey successfully bound"); |
| } |
| |
| return 0; |
| } |
| |
| |
| static int cmd_mod_app_unbind(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, mod_app_idx, mod_id, cid; |
| uint8_t status; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| mod_app_idx = shell_strtoul(argv[2], 0, &err); |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_app_unbind_vnd(net.net_idx, net.dst, |
| elem_addr, mod_app_idx, |
| mod_id, cid, &status); |
| } else { |
| err = bt_mesh_cfg_mod_app_unbind(net.net_idx, net.dst, |
| elem_addr, mod_app_idx, mod_id, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model App Unbind (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model App Unbind failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "AppKey successfully unbound"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_app_get(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, mod_id, cid; |
| uint16_t apps[16]; |
| uint8_t status; |
| size_t cnt; |
| int err = 0; |
| int i; |
| |
| cnt = ARRAY_SIZE(apps); |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| mod_id = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 3) { |
| cid = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_app_get_vnd(net.net_idx, net.dst, |
| elem_addr, mod_id, cid, |
| &status, apps, &cnt); |
| } else { |
| err = bt_mesh_cfg_mod_app_get(net.net_idx, net.dst, elem_addr, |
| mod_id, &status, apps, &cnt); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model App Get (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model App Get failed with status 0x%02x", |
| status); |
| } else { |
| shell_print( |
| shell, |
| "Apps bound to Element 0x%04x, Model 0x%04x %s:", |
| elem_addr, mod_id, argc > 3 ? argv[3] : "(SIG)"); |
| |
| if (!cnt) { |
| shell_print(shell, "\tNone."); |
| } |
| |
| for (i = 0; i < cnt; i++) { |
| shell_print(shell, "\t0x%04x", apps[i]); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_add(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t status; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| sub_addr = shell_strtoul(argv[2], 0, &err); |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_add_vnd(net.net_idx, net.dst, |
| elem_addr, sub_addr, mod_id, |
| cid, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_add(net.net_idx, net.dst, elem_addr, |
| sub_addr, mod_id, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model Subscription Add " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model Subscription Add failed with status " |
| "0x%02x", status); |
| } else { |
| shell_print(shell, "Model subscription was successful"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_del(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t status; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| sub_addr = shell_strtoul(argv[2], 0, &err); |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_del_vnd(net.net_idx, net.dst, |
| elem_addr, sub_addr, mod_id, |
| cid, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_del(net.net_idx, net.dst, elem_addr, |
| sub_addr, mod_id, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model Subscription Delete " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model Subscription Delete failed with " |
| "status 0x%02x", status); |
| } else { |
| shell_print(shell, "Model subscription deltion was successful"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_add_va(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t label[16]; |
| uint8_t status; |
| size_t len; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| |
| len = hex2bin(argv[2], strlen(argv[2]), label, sizeof(label)); |
| (void)memset(label + len, 0, sizeof(label) - len); |
| |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_va_add_vnd(net.net_idx, net.dst, |
| elem_addr, label, mod_id, |
| cid, &sub_addr, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_va_add(net.net_idx, net.dst, |
| elem_addr, label, mod_id, |
| &sub_addr, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Mod Sub VA Add (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Mod Sub VA Add failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(shell, "0x%04x subscribed to Label UUID %s " |
| "(va 0x%04x)", elem_addr, argv[2], sub_addr); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_del_va(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t label[16]; |
| uint8_t status; |
| size_t len; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| |
| len = hex2bin(argv[2], strlen(argv[2]), label, sizeof(label)); |
| (void)memset(label + len, 0, sizeof(label) - len); |
| |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_va_del_vnd(net.net_idx, net.dst, |
| elem_addr, label, mod_id, |
| cid, &sub_addr, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_va_del(net.net_idx, net.dst, |
| elem_addr, label, mod_id, |
| &sub_addr, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model Subscription Delete " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model Subscription Delete failed with " |
| "status 0x%02x", status); |
| } else { |
| shell_print(shell, "0x%04x unsubscribed from Label UUID %s " |
| "(va 0x%04x)", elem_addr, argv[2], sub_addr); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_ow(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t status; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| sub_addr = shell_strtoul(argv[2], 0, &err); |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_overwrite_vnd(net.net_idx, net.dst, |
| elem_addr, sub_addr, mod_id, |
| cid, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_overwrite(net.net_idx, net.dst, elem_addr, |
| sub_addr, mod_id, &status); |
| } |
| |
| if (err) { |
| shell_error(sh, "Unable to send Model Subscription Overwrite " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(sh, "Model Subscription Overwrite failed with " |
| "status 0x%02x", status); |
| } else { |
| shell_print(sh, "Model subscription overwrite was successful"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_ow_va(const struct shell *sh, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t label[16]; |
| uint8_t status; |
| size_t len; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| |
| len = hex2bin(argv[2], strlen(argv[2]), label, sizeof(label)); |
| (void)memset(label + len, 0, sizeof(label) - len); |
| |
| mod_id = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 4) { |
| cid = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_va_overwrite_vnd(net.net_idx, net.dst, |
| elem_addr, label, mod_id, |
| cid, &sub_addr, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_va_overwrite(net.net_idx, net.dst, |
| elem_addr, label, mod_id, |
| &sub_addr, &status); |
| } |
| |
| if (err) { |
| shell_error(sh, "Unable to send Mod Sub VA Overwrite (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(sh, "Mod Sub VA Overwrite failed with status 0x%02x", |
| status); |
| } else { |
| shell_print(sh, "0x%04x overwrite to Label UUID %s " |
| "(va 0x%04x)", elem_addr, argv[2], sub_addr); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_del_all(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| uint16_t elem_addr, mod_id, cid; |
| uint8_t status; |
| int err = 0; |
| |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| mod_id = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 3) { |
| cid = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_del_all_vnd(net.net_idx, net.dst, |
| elem_addr, mod_id, |
| cid, &status); |
| } else { |
| err = bt_mesh_cfg_mod_sub_del_all(net.net_idx, net.dst, elem_addr, |
| mod_id, &status); |
| } |
| |
| if (err) { |
| shell_error(sh, "Unable to send Model Subscription Delete All" |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(sh, "Model Subscription Delete All failed with " |
| "status 0x%02x", status); |
| } else { |
| shell_print(sh, "Model subscription deltion all was successful"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_sub_get(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, mod_id, cid; |
| uint16_t subs[16]; |
| uint8_t status; |
| size_t cnt; |
| int err = 0; |
| int i; |
| |
| cnt = ARRAY_SIZE(subs); |
| elem_addr = shell_strtoul(argv[1], 0, &err); |
| mod_id = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 3) { |
| cid = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_mod_sub_get_vnd(net.net_idx, net.dst, |
| elem_addr, mod_id, cid, |
| &status, subs, &cnt); |
| } else { |
| err = bt_mesh_cfg_mod_sub_get(net.net_idx, net.dst, elem_addr, |
| mod_id, &status, subs, &cnt); |
| } |
| |
| if (err) { |
| shell_error(shell, "Unable to send Model Subscription Get " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model Subscription Get failed with " |
| "status 0x%02x", status); |
| } else { |
| shell_print( |
| shell, |
| "Model Subscriptions for Element 0x%04x, " |
| "Model 0x%04x %s:", |
| elem_addr, mod_id, argc > 3 ? argv[3] : "(SIG)"); |
| |
| if (!cnt) { |
| shell_print(shell, "\tNone."); |
| } |
| |
| for (i = 0; i < cnt; i++) { |
| shell_print(shell, "\t0x%04x", subs[i]); |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_krp(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| uint8_t status, phase; |
| uint16_t key_net_idx; |
| int err = 0; |
| |
| key_net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc < 3) { |
| err = bt_mesh_cfg_krp_get(net.net_idx, net.dst, key_net_idx, |
| &status, &phase); |
| } else { |
| uint16_t trans = shell_strtoul(argv[2], 0, &err); |
| |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_krp_set(net.net_idx, net.dst, key_net_idx, |
| trans, &status, &phase); |
| } |
| |
| if (err) { |
| shell_error(sh, "Unable to send krp Get/Set " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| shell_print(sh, "Krp Get/Set with status 0x%02x and phase 0x%02x", |
| status, phase); |
| |
| return 0; |
| } |
| |
| static int mod_pub_get(const struct shell *shell, uint16_t addr, uint16_t mod_id, |
| uint16_t cid) |
| { |
| struct bt_mesh_cfg_mod_pub pub; |
| uint8_t status; |
| int err; |
| |
| if (cid == CID_NVAL) { |
| err = bt_mesh_cfg_mod_pub_get(net.net_idx, net.dst, addr, |
| mod_id, &pub, &status); |
| } else { |
| err = bt_mesh_cfg_mod_pub_get_vnd(net.net_idx, net.dst, addr, |
| mod_id, cid, &pub, &status); |
| } |
| |
| if (err) { |
| shell_error(shell, "Model Publication Get failed (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Model Publication Get failed " |
| "(status 0x%02x)", status); |
| return 0; |
| } |
| |
| shell_print(shell, "Model Publication for Element 0x%04x, Model 0x%04x:\n" |
| "\tPublish Address: 0x%04x\n" |
| "\tAppKeyIndex: 0x%04x\n" |
| "\tCredential Flag: %u\n" |
| "\tPublishTTL: %u\n" |
| "\tPublishPeriod: 0x%02x\n" |
| "\tPublishRetransmitCount: %u\n" |
| "\tPublishRetransmitInterval: %ums", |
| addr, mod_id, pub.addr, pub.app_idx, pub.cred_flag, pub.ttl, |
| pub.period, BT_MESH_PUB_TRANSMIT_COUNT(pub.transmit), |
| BT_MESH_PUB_TRANSMIT_INT(pub.transmit)); |
| |
| return 0; |
| } |
| |
| static int mod_pub_set(const struct shell *sh, uint16_t addr, bool is_va, |
| uint16_t mod_id, uint16_t cid, char *argv[]) |
| { |
| struct bt_mesh_cfg_mod_pub pub; |
| uint8_t status, count; |
| uint16_t interval; |
| uint8_t uuid[16]; |
| uint8_t len; |
| int err = 0; |
| |
| if (!is_va) { |
| pub.addr = shell_strtoul(argv[0], 0, &err); |
| pub.uuid = NULL; |
| } else { |
| len = hex2bin(argv[0], strlen(argv[0]), uuid, sizeof(uuid)); |
| memset(uuid + len, 0, sizeof(uuid) - len); |
| pub.uuid = (const uint8_t *)&uuid; |
| } |
| |
| pub.app_idx = shell_strtoul(argv[1], 0, &err); |
| pub.cred_flag = shell_strtoul(argv[2], 0, &err); |
| pub.ttl = shell_strtoul(argv[3], 0, &err); |
| pub.period = shell_strtoul(argv[4], 0, &err); |
| |
| count = shell_strtoul(argv[5], 0, &err); |
| if (count > 7) { |
| shell_print(sh, "Invalid retransmit count"); |
| return -EINVAL; |
| } |
| |
| interval = shell_strtoul(argv[6], 0, &err); |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (interval > (31 * 50) || (interval % 50)) { |
| shell_print(sh, "Invalid retransmit interval %u", interval); |
| return -EINVAL; |
| } |
| |
| pub.transmit = BT_MESH_PUB_TRANSMIT(count, interval); |
| |
| if (cid == CID_NVAL) { |
| err = bt_mesh_cfg_mod_pub_set(net.net_idx, net.dst, addr, |
| mod_id, &pub, &status); |
| } else { |
| err = bt_mesh_cfg_mod_pub_set_vnd(net.net_idx, net.dst, addr, |
| mod_id, cid, &pub, &status); |
| } |
| |
| if (err) { |
| shell_error(sh, "Model Publication Set failed (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(sh, "Model Publication Set failed " |
| "(status 0x%02x)", status); |
| } else { |
| shell_print(sh, "Model Publication successfully set"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_pub(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| uint16_t addr, mod_id, cid; |
| |
| addr = shell_strtoul(argv[1], 0, &err); |
| mod_id = shell_strtoul(argv[2], 0, &err); |
| |
| argc -= 3; |
| argv += 3; |
| |
| if (argc == 1 || argc == 8) { |
| cid = shell_strtoul(argv[0], 0, &err); |
| argc--; |
| argv++; |
| } else { |
| cid = CID_NVAL; |
| } |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc > 0) { |
| if (argc < 7) { |
| return -EINVAL; |
| } |
| |
| return mod_pub_set(shell, addr, false, mod_id, cid, argv); |
| } else { |
| return mod_pub_get(shell, addr, mod_id, cid); |
| } |
| } |
| |
| static int cmd_mod_pub_va(const struct shell *sh, size_t argc, char *argv[]) |
| { |
| int err = 0; |
| uint16_t addr, mod_id, cid = CID_NVAL; |
| |
| addr = shell_strtoul(argv[1], 0, &err); |
| mod_id = shell_strtoul(argv[9], 0, &err); |
| |
| if (argc > 10) { |
| cid = shell_strtoul(argv[10], 0, &err); |
| } |
| |
| if (err) { |
| shell_warn(sh, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| argv += 2; |
| |
| return mod_pub_set(sh, addr, true, mod_id, cid, argv); |
| } |
| |
| static void hb_sub_print(const struct shell *shell, |
| struct bt_mesh_cfg_hb_sub *sub) |
| { |
| shell_print(shell, "Heartbeat Subscription:\n" |
| "\tSource: 0x%04x\n" |
| "\tDestination: 0x%04x\n" |
| "\tPeriodLog: 0x%02x\n" |
| "\tCountLog: 0x%02x\n" |
| "\tMinHops: %u\n" |
| "\tMaxHops: %u", |
| sub->src, sub->dst, sub->period, sub->count, |
| sub->min, sub->max); |
| } |
| |
| static int hb_sub_get(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| struct bt_mesh_cfg_hb_sub sub; |
| uint8_t status; |
| int err; |
| |
| err = bt_mesh_cfg_hb_sub_get(net.net_idx, net.dst, &sub, &status); |
| if (err) { |
| shell_error(shell, "Heartbeat Subscription Get failed (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Heartbeat Subscription Get failed " |
| "(status 0x%02x)", status); |
| } else { |
| hb_sub_print(shell, &sub); |
| } |
| |
| return 0; |
| } |
| |
| static int hb_sub_set(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| struct bt_mesh_cfg_hb_sub sub; |
| uint8_t status; |
| int err = 0; |
| |
| sub.src = shell_strtoul(argv[1], 0, &err); |
| sub.dst = shell_strtoul(argv[2], 0, &err); |
| sub.period = shell_strtoul(argv[3], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_hb_sub_set(net.net_idx, net.dst, &sub, &status); |
| if (err) { |
| shell_error(shell, "Heartbeat Subscription Set failed (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Heartbeat Subscription Set failed " |
| "(status 0x%02x)", status); |
| } else { |
| hb_sub_print(shell, &sub); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_hb_sub(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| if (argc > 1) { |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| return hb_sub_set(shell, argc, argv); |
| } else { |
| return hb_sub_get(shell, argc, argv); |
| } |
| } |
| |
| static int hb_pub_get(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| struct bt_mesh_cfg_hb_pub pub; |
| uint8_t status; |
| int err; |
| |
| err = bt_mesh_cfg_hb_pub_get(net.net_idx, net.dst, &pub, &status); |
| if (err) { |
| shell_error(shell, "Heartbeat Publication Get failed (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Heartbeat Publication Get failed " |
| "(status 0x%02x)", status); |
| return 0; |
| } |
| |
| shell_print(shell, "Heartbeat publication:"); |
| shell_print(shell, "\tdst 0x%04x count 0x%02x period 0x%02x", |
| pub.dst, pub.count, pub.period); |
| shell_print(shell, "\tttl 0x%02x feat 0x%04x net_idx 0x%04x", |
| pub.ttl, pub.feat, pub.net_idx); |
| |
| return 0; |
| } |
| |
| static int hb_pub_set(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| struct bt_mesh_cfg_hb_pub pub; |
| uint8_t status; |
| int err = 0; |
| |
| pub.dst = shell_strtoul(argv[1], 0, &err); |
| pub.count = shell_strtoul(argv[2], 0, &err); |
| pub.period = shell_strtoul(argv[3], 0, &err); |
| pub.ttl = shell_strtoul(argv[4], 0, &err); |
| pub.feat = shell_strtoul(argv[5], 0, &err); |
| pub.net_idx = shell_strtoul(argv[6], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_cfg_hb_pub_set(net.net_idx, net.dst, &pub, &status); |
| if (err) { |
| shell_error(shell, "Heartbeat Publication Set failed (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| shell_print(shell, "Heartbeat Publication Set failed " |
| "(status 0x%02x)", status); |
| } else { |
| shell_print(shell, "Heartbeat publication successfully set"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_hb_pub(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| if (argc > 1) { |
| if (argc < 7) { |
| return -EINVAL; |
| } |
| |
| return hb_pub_set(shell, argc, argv); |
| } else { |
| return hb_pub_get(shell, argc, argv); |
| } |
| } |
| #endif /* CONFIG_BT_MESH_CFG_CLI */ |
| |
| #if defined(CONFIG_BT_MESH_PROV_DEVICE) |
| static int cmd_pb(bt_mesh_prov_bearer_t bearer, const struct shell *shell, |
| size_t argc, char *argv[]) |
| { |
| int err = 0; |
| bool onoff; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| onoff = shell_strtobool(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (onoff) { |
| err = bt_mesh_prov_enable(bearer); |
| if (err) { |
| shell_error(shell, "Failed to enable %s (err %d)", |
| bearer2str(bearer), err); |
| } else { |
| shell_print(shell, "%s enabled", bearer2str(bearer)); |
| } |
| } else { |
| err = bt_mesh_prov_disable(bearer); |
| if (err) { |
| shell_error(shell, "Failed to disable %s (err %d)", |
| bearer2str(bearer), err); |
| } else { |
| shell_print(shell, "%s disabled", bearer2str(bearer)); |
| } |
| } |
| |
| return 0; |
| } |
| #endif |
| |
| #if defined(CONFIG_BT_MESH_PB_ADV) |
| static int cmd_pb_adv(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| return cmd_pb(BT_MESH_PROV_ADV, shell, argc, argv); |
| } |
| |
| #if defined(CONFIG_BT_MESH_PROVISIONER) |
| static int cmd_provision_adv(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t uuid[16]; |
| uint8_t attention_duration; |
| uint16_t net_idx; |
| uint16_t addr; |
| size_t len; |
| int err = 0; |
| |
| len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid)); |
| (void)memset(uuid + len, 0, sizeof(uuid) - len); |
| |
| net_idx = shell_strtoul(argv[2], 0, &err); |
| addr = shell_strtoul(argv[3], 0, &err); |
| attention_duration = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_provision_adv(uuid, net_idx, addr, attention_duration); |
| if (err) { |
| shell_error(shell, "Provisioning failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_MESH_PROVISIONER */ |
| |
| #endif /* CONFIG_BT_MESH_PB_ADV */ |
| |
| #if defined(CONFIG_BT_MESH_PB_GATT) |
| static int cmd_pb_gatt(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| return cmd_pb(BT_MESH_PROV_GATT, shell, argc, argv); |
| } |
| #endif /* CONFIG_BT_MESH_PB_GATT */ |
| |
| static int cmd_provision(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| const uint8_t *net_key = default_key; |
| uint16_t net_idx, addr; |
| uint32_t iv_index; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| addr = shell_strtoul(argv[2], 0, &err); |
| |
| if (argc > 3) { |
| iv_index = shell_strtoul(argv[3], 0, &err); |
| } else { |
| iv_index = 0U; |
| } |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { |
| const struct bt_mesh_cdb_subnet *sub; |
| |
| sub = bt_mesh_cdb_subnet_get(net_idx); |
| if (!sub) { |
| shell_error(shell, "No cdb entry for subnet 0x%03x", |
| net_idx); |
| return 0; |
| } |
| |
| net_key = sub->keys[SUBNET_KEY_TX_IDX(sub)].net_key; |
| } |
| |
| err = bt_mesh_provision(net_key, net_idx, 0, iv_index, addr, |
| default_key); |
| if (err) { |
| shell_error(shell, "Provisioning failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_MESH_CFG_CLI) |
| int cmd_timeout(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| int32_t timeout_ms; |
| int err = 0; |
| |
| if (argc == 2) { |
| int32_t timeout_s = shell_strtol(argv[1], 0, &err); |
| |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (timeout_s < 0 || timeout_s > (INT32_MAX / 1000)) { |
| timeout_ms = SYS_FOREVER_MS; |
| } else { |
| timeout_ms = timeout_s * MSEC_PER_SEC; |
| } |
| |
| bt_mesh_cfg_cli_timeout_set(timeout_ms); |
| } |
| |
| timeout_ms = bt_mesh_cfg_cli_timeout_get(); |
| if (timeout_ms == SYS_FOREVER_MS) { |
| shell_print(shell, "Message timeout: forever"); |
| } else { |
| shell_print(shell, "Message timeout: %u seconds", |
| timeout_ms / 1000); |
| } |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_MESH_CFG_CLI */ |
| |
| #if defined(CONFIG_BT_MESH_HEALTH_CLI) |
| static int cmd_fault_get(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t faults[32]; |
| size_t fault_count; |
| uint8_t test_id; |
| uint16_t cid; |
| int err = 0; |
| |
| cid = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| fault_count = sizeof(faults); |
| |
| err = bt_mesh_health_fault_get(net.dst, net.app_idx, cid, &test_id, |
| faults, &fault_count); |
| if (err) { |
| shell_error(shell, "Failed to send Health Fault Get (err %d)", |
| err); |
| } else { |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_fault_clear(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t faults[32]; |
| size_t fault_count; |
| uint8_t test_id; |
| uint16_t cid; |
| int err = 0; |
| |
| cid = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| fault_count = sizeof(faults); |
| |
| err = bt_mesh_health_fault_clear(net.dst, net.app_idx, cid, |
| &test_id, faults, &fault_count); |
| if (err) { |
| shell_error(shell, "Failed to send Health Fault Clear (err %d)", |
| err); |
| } else { |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_fault_clear_unack(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t cid; |
| int err = 0; |
| |
| cid = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_fault_clear_unack(net.dst, net.app_idx, cid); |
| if (err) { |
| shell_error(shell, "Health Fault Clear Unacknowledged failed " |
| "(err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_fault_test(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t faults[32]; |
| size_t fault_count; |
| uint8_t test_id; |
| uint16_t cid; |
| int err = 0; |
| |
| fault_count = sizeof(faults); |
| cid = shell_strtoul(argv[1], 0, &err); |
| test_id = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_fault_test(net.dst, net.app_idx, cid, |
| test_id, faults, &fault_count); |
| if (err) { |
| shell_error(shell, "Failed to send Health Fault Test (err %d)", |
| err); |
| } else { |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_fault_test_unack(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint16_t cid; |
| uint8_t test_id; |
| int err = 0; |
| |
| cid = shell_strtoul(argv[1], 0, &err); |
| test_id = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_fault_test_unack(net.dst, net.app_idx, cid, test_id); |
| if (err) { |
| shell_error(shell, "Health Fault Test Unacknowledged failed " |
| "(err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_period_get(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t divisor; |
| int err; |
| |
| err = bt_mesh_health_period_get(net.dst, net.app_idx, &divisor); |
| if (err) { |
| shell_error(shell, "Failed to send Health Period Get (err %d)", |
| err); |
| } else { |
| shell_print(shell, "Health FastPeriodDivisor: %u", divisor); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_period_set(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t divisor, updated_divisor; |
| int err = 0; |
| |
| divisor = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_period_set(net.dst, net.app_idx, divisor, |
| &updated_divisor); |
| if (err) { |
| shell_error(shell, "Failed to send Health Period Set (err %d)", |
| err); |
| } else { |
| shell_print(shell, "Health FastPeriodDivisor: %u", |
| updated_divisor); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_period_set_unack(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t divisor; |
| int err = 0; |
| |
| divisor = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_period_set_unack(net.dst, net.app_idx, divisor); |
| if (err) { |
| shell_print(shell, "Failed to send Health Period Set (err %d)", |
| err); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_attention_get(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t attention; |
| int err; |
| |
| err = bt_mesh_health_attention_get(net.dst, net.app_idx, |
| &attention); |
| if (err) { |
| shell_error(shell, "Failed to send Health Attention Get " |
| "(err %d)", err); |
| } else { |
| shell_print(shell, "Health Attention Timer: %u", attention); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_attention_set(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t attention, updated_attention; |
| int err = 0; |
| |
| attention = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_attention_set(net.dst, net.app_idx, attention, |
| &updated_attention); |
| if (err) { |
| shell_error(shell, "Failed to send Health Attention Set " |
| "(err %d)", err); |
| } else { |
| shell_print(shell, "Health Attention Timer: %u", |
| updated_attention); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_attention_set_unack(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t attention; |
| int err = 0; |
| |
| attention = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| err = bt_mesh_health_attention_set_unack(net.dst, net.app_idx, attention); |
| if (err) { |
| shell_error(shell, "Failed to send Health Attention Set " |
| "(err %d)", err); |
| } |
| |
| return 0; |
| } |
| #endif /* CONFIG_BT_MESH_HEALTH_CLI */ |
| |
| static struct bt_mesh_elem *primary_element(void) |
| { |
| const struct bt_mesh_comp *comp = bt_mesh_comp_get(); |
| |
| if (comp) { |
| return &comp->elem[0]; |
| } |
| |
| return NULL; |
| } |
| |
| static int cmd_add_fault(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t fault_id; |
| uint8_t i; |
| struct bt_mesh_elem *elem; |
| int err = 0; |
| |
| elem = primary_element(); |
| if (elem == NULL) { |
| shell_print(shell, "Element not found!"); |
| return -EINVAL; |
| } |
| |
| fault_id = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (!fault_id) { |
| shell_print(shell, "The Fault ID must be non-zero!"); |
| return -EINVAL; |
| } |
| |
| for (i = 0U; i < sizeof(cur_faults); i++) { |
| if (!cur_faults[i]) { |
| cur_faults[i] = fault_id; |
| break; |
| } |
| } |
| |
| if (i == sizeof(cur_faults)) { |
| shell_print(shell, "Fault array is full. Use \"del-fault\" to " |
| "clear it"); |
| return 0; |
| } |
| |
| for (i = 0U; i < sizeof(reg_faults); i++) { |
| if (!reg_faults[i]) { |
| reg_faults[i] = fault_id; |
| break; |
| } |
| } |
| |
| if (i == sizeof(reg_faults)) { |
| shell_print(shell, "No space to store more registered faults"); |
| } |
| |
| bt_mesh_fault_update(elem); |
| |
| return 0; |
| } |
| |
| static int cmd_del_fault(const struct shell *shell, size_t argc, char *argv[]) |
| { |
| uint8_t fault_id; |
| uint8_t i; |
| struct bt_mesh_elem *elem; |
| int err = 0; |
| |
| elem = primary_element(); |
| if (elem == NULL) { |
| shell_print(shell, "Element not found!"); |
| return -EINVAL; |
| } |
| |
| if (argc < 2) { |
| (void)memset(cur_faults, 0, sizeof(cur_faults)); |
| shell_print(shell, "All current faults cleared"); |
| bt_mesh_fault_update(elem); |
| return 0; |
| } |
| |
| fault_id = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (!fault_id) { |
| shell_print(shell, "The Fault ID must be non-zero!"); |
| return -EINVAL; |
| } |
| |
| for (i = 0U; i < sizeof(cur_faults); i++) { |
| if (cur_faults[i] == fault_id) { |
| cur_faults[i] = 0U; |
| shell_print(shell, "Fault cleared"); |
| } |
| } |
| |
| bt_mesh_fault_update(elem); |
| |
| return 0; |
| } |
| |
| #if defined(CONFIG_BT_MESH_CDB) |
| static int cmd_cdb_create(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| uint8_t net_key[16]; |
| size_t len; |
| int err; |
| |
| if (argc < 2) { |
| bt_rand(net_key, 16); |
| } else { |
| len = hex2bin(argv[1], strlen(argv[1]), net_key, |
| sizeof(net_key)); |
| memset(net_key + len, 0, sizeof(net_key) - len); |
| } |
| |
| err = bt_mesh_cdb_create(net_key); |
| if (err < 0) { |
| shell_print(shell, "Failed to create CDB (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_clear(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| bt_mesh_cdb_clear(); |
| |
| shell_print(shell, "Cleared CDB"); |
| |
| return 0; |
| } |
| |
| static void cdb_print_nodes(const struct shell *shell) |
| { |
| char key_hex_str[32 + 1], uuid_hex_str[32 + 1]; |
| struct bt_mesh_cdb_node *node; |
| int i, total = 0; |
| bool configured; |
| |
| shell_print(shell, "Address Elements Flags %-32s DevKey", "UUID"); |
| |
| for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) { |
| node = &bt_mesh_cdb.nodes[i]; |
| if (node->addr == BT_MESH_ADDR_UNASSIGNED) { |
| continue; |
| } |
| |
| configured = atomic_test_bit(node->flags, |
| BT_MESH_CDB_NODE_CONFIGURED); |
| |
| total++; |
| bin2hex(node->uuid, 16, uuid_hex_str, sizeof(uuid_hex_str)); |
| bin2hex(node->dev_key, 16, key_hex_str, sizeof(key_hex_str)); |
| shell_print(shell, "0x%04x %-8d %-5s %s %s", node->addr, |
| node->num_elem, configured ? "C" : "-", |
| uuid_hex_str, key_hex_str); |
| } |
| |
| shell_print(shell, "> Total nodes: %d", total); |
| } |
| |
| static void cdb_print_subnets(const struct shell *shell) |
| { |
| struct bt_mesh_cdb_subnet *subnet; |
| char key_hex_str[32 + 1]; |
| int i, total = 0; |
| |
| shell_print(shell, "NetIdx NetKey"); |
| |
| for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) { |
| subnet = &bt_mesh_cdb.subnets[i]; |
| if (subnet->net_idx == BT_MESH_KEY_UNUSED) { |
| continue; |
| } |
| |
| total++; |
| bin2hex(subnet->keys[0].net_key, 16, key_hex_str, |
| sizeof(key_hex_str)); |
| shell_print(shell, "0x%03x %s", subnet->net_idx, |
| key_hex_str); |
| } |
| |
| shell_print(shell, "> Total subnets: %d", total); |
| } |
| |
| static void cdb_print_app_keys(const struct shell *shell) |
| { |
| struct bt_mesh_cdb_app_key *app_key; |
| char key_hex_str[32 + 1]; |
| int i, total = 0; |
| |
| shell_print(shell, "NetIdx AppIdx AppKey"); |
| |
| for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) { |
| app_key = &bt_mesh_cdb.app_keys[i]; |
| if (app_key->net_idx == BT_MESH_KEY_UNUSED) { |
| continue; |
| } |
| |
| total++; |
| bin2hex(app_key->keys[0].app_key, 16, key_hex_str, |
| sizeof(key_hex_str)); |
| shell_print(shell, "0x%03x 0x%03x %s", |
| app_key->net_idx, app_key->app_idx, key_hex_str); |
| } |
| |
| shell_print(shell, "> Total app-keys: %d", total); |
| } |
| |
| static int cmd_cdb_show(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| if (!atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) { |
| shell_print(shell, "No valid networks"); |
| return 0; |
| } |
| |
| shell_print(shell, "Mesh Network Information"); |
| shell_print(shell, "========================"); |
| |
| cdb_print_nodes(shell); |
| shell_print(shell, "---"); |
| cdb_print_subnets(shell); |
| shell_print(shell, "---"); |
| cdb_print_app_keys(shell); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_node_add(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_node *node; |
| uint8_t uuid[16], dev_key[16]; |
| uint16_t addr, net_idx; |
| uint8_t num_elem; |
| size_t len; |
| int err = 0; |
| |
| len = hex2bin(argv[1], strlen(argv[1]), uuid, sizeof(uuid)); |
| memset(uuid + len, 0, sizeof(uuid) - len); |
| |
| addr = shell_strtoul(argv[2], 0, &err); |
| num_elem = shell_strtoul(argv[3], 0, &err); |
| net_idx = shell_strtoul(argv[4], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc < 6) { |
| bt_rand(dev_key, 16); |
| } else { |
| len = hex2bin(argv[5], strlen(argv[5]), dev_key, |
| sizeof(dev_key)); |
| memset(dev_key + len, 0, sizeof(dev_key) - len); |
| } |
| |
| node = bt_mesh_cdb_node_alloc(uuid, addr, num_elem, net_idx); |
| if (node == NULL) { |
| shell_print(shell, "Failed to allocate node"); |
| return 0; |
| } |
| |
| memcpy(node->dev_key, dev_key, 16); |
| |
| if (IS_ENABLED(CONFIG_BT_SETTINGS)) { |
| bt_mesh_cdb_node_store(node); |
| } |
| |
| shell_print(shell, "Added node 0x%04x", addr); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_node_del(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_node *node; |
| uint16_t addr; |
| int err = 0; |
| |
| addr = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| node = bt_mesh_cdb_node_get(addr); |
| if (node == NULL) { |
| shell_print(shell, "No node with address 0x%04x", addr); |
| return 0; |
| } |
| |
| bt_mesh_cdb_node_del(node, true); |
| |
| shell_print(shell, "Deleted node 0x%04x", addr); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_subnet_add(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_subnet *sub; |
| uint8_t net_key[16]; |
| uint16_t net_idx; |
| size_t len; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc < 3) { |
| bt_rand(net_key, 16); |
| } else { |
| len = hex2bin(argv[2], strlen(argv[2]), net_key, |
| sizeof(net_key)); |
| memset(net_key + len, 0, sizeof(net_key) - len); |
| } |
| |
| sub = bt_mesh_cdb_subnet_alloc(net_idx); |
| if (sub == NULL) { |
| shell_print(shell, "Could not add subnet"); |
| return 0; |
| } |
| |
| memcpy(sub->keys[0].net_key, net_key, 16); |
| |
| if (IS_ENABLED(CONFIG_BT_SETTINGS)) { |
| bt_mesh_cdb_subnet_store(sub); |
| } |
| |
| shell_print(shell, "Added Subnet 0x%03x", net_idx); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_subnet_del(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_subnet *sub; |
| uint16_t net_idx; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| sub = bt_mesh_cdb_subnet_get(net_idx); |
| if (sub == NULL) { |
| shell_print(shell, "No subnet with NetIdx 0x%03x", net_idx); |
| return 0; |
| } |
| |
| bt_mesh_cdb_subnet_del(sub, true); |
| |
| shell_print(shell, "Deleted subnet 0x%03x", net_idx); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_app_key_add(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_app_key *key; |
| uint16_t net_idx, app_idx; |
| uint8_t app_key[16]; |
| size_t len; |
| int err = 0; |
| |
| net_idx = shell_strtoul(argv[1], 0, &err); |
| app_idx = shell_strtoul(argv[2], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| if (argc < 4) { |
| bt_rand(app_key, 16); |
| } else { |
| len = hex2bin(argv[3], strlen(argv[3]), app_key, |
| sizeof(app_key)); |
| memset(app_key + len, 0, sizeof(app_key) - len); |
| } |
| |
| key = bt_mesh_cdb_app_key_alloc(net_idx, app_idx); |
| if (key == NULL) { |
| shell_print(shell, "Could not add AppKey"); |
| return 0; |
| } |
| |
| memcpy(key->keys[0].app_key, app_key, 16); |
| |
| if (IS_ENABLED(CONFIG_BT_SETTINGS)) { |
| bt_mesh_cdb_app_key_store(key); |
| } |
| |
| shell_print(shell, "Added AppKey 0x%03x", app_idx); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_app_key_del(const struct shell *shell, size_t argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_app_key *key; |
| uint16_t app_idx; |
| int err = 0; |
| |
| app_idx = shell_strtoul(argv[1], 0, &err); |
| if (err) { |
| shell_warn(shell, "Unable to parse input string argument"); |
| return err; |
| } |
| |
| key = bt_mesh_cdb_app_key_get(app_idx); |
| if (key == NULL) { |
| shell_print(shell, "No AppKey 0x%03x", app_idx); |
| return 0; |
| } |
| |
| bt_mesh_cdb_app_key_del(key, true); |
| |
| shell_print(shell, "Deleted AppKey 0x%03x", app_idx); |
| |
| return 0; |
| } |
| #endif |
| |
| /* List of Mesh subcommands. |
| * |
| * Each command is documented in doc/reference/bluetooth/mesh/shell.rst. |
| * |
| * Please keep the documentation up to date by adding any new commands to the |
| * list. |
| */ |
| SHELL_STATIC_SUBCMD_SET_CREATE(mesh_cmds, |
| /* General operations */ |
| SHELL_CMD_ARG(init, NULL, NULL, cmd_init, 1, 0), |
| SHELL_CMD_ARG(reset, NULL, "<addr>", cmd_reset, 2, 0), |
| #if defined(CONFIG_BT_MESH_LOW_POWER) |
| SHELL_CMD_ARG(lpn, NULL, "<value: off, on>", cmd_lpn, 2, 0), |
| SHELL_CMD_ARG(poll, NULL, NULL, cmd_poll, 1, 0), |
| #endif |
| #if defined(CONFIG_BT_MESH_GATT_PROXY) |
| SHELL_CMD_ARG(ident, NULL, NULL, cmd_ident, 1, 0), |
| #endif |
| SHELL_CMD_ARG(dst, NULL, "[destination address]", cmd_dst, 1, 1), |
| SHELL_CMD_ARG(netidx, NULL, "[NetIdx]", cmd_netidx, 1, 1), |
| SHELL_CMD_ARG(appidx, NULL, "[AppIdx]", cmd_appidx, 1, 1), |
| |
| /* Commands which access internal APIs, for testing only */ |
| SHELL_CMD_ARG(net-send, NULL, "<hex string>", cmd_net_send, 2, 0), |
| #if defined(CONFIG_BT_MESH_IV_UPDATE_TEST) |
| SHELL_CMD_ARG(iv-update, NULL, NULL, cmd_iv_update, 1, 0), |
| SHELL_CMD_ARG(iv-update-test, NULL, "<value: off, on>", |
| cmd_iv_update_test, 2, 0), |
| #endif |
| SHELL_CMD_ARG(rpl-clear, NULL, NULL, cmd_rpl_clear, 1, 0), |
| |
| /* Provisioning operations */ |
| #if defined(CONFIG_BT_MESH_PB_GATT) |
| SHELL_CMD_ARG(pb-gatt, NULL, "<val: off, on>", cmd_pb_gatt, 2, 0), |
| #endif |
| #if defined(CONFIG_BT_MESH_PB_ADV) |
| SHELL_CMD_ARG(pb-adv, NULL, "<val: off, on>", cmd_pb_adv, 2, 0), |
| #if defined(CONFIG_BT_MESH_PROVISIONER) |
| SHELL_CMD_ARG(provision-adv, NULL, "<UUID> <NetKeyIndex> <addr> " |
| "<AttentionDuration>", cmd_provision_adv, 5, 0), |
| #endif |
| #endif |
| |
| #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT) |
| SHELL_CMD_ARG(provision-gatt, NULL, "<UUID> <NetKeyIndex> <addr> " |
| "<AttentionDuration>", cmd_provision_gatt, 5, 0), |
| #endif |
| |
| #if defined(CONFIG_BT_MESH_PROXY_CLIENT) |
| SHELL_CMD_ARG(proxy-connect, NULL, "<NetKeyIndex>", |
| cmd_proxy_connect, 2, 0), |
| SHELL_CMD_ARG(proxy-disconnect, NULL, "<NetKeyIndex>", |
| cmd_proxy_disconnect, 2, 0), |
| #endif |
| |
| SHELL_CMD_ARG(uuid, NULL, "<UUID: 1-16 hex values>", cmd_uuid, 2, 0), |
| SHELL_CMD_ARG(input-num, NULL, "<number>", cmd_input_num, 2, 0), |
| SHELL_CMD_ARG(input-str, NULL, "<string>", cmd_input_str, 2, 0), |
| SHELL_CMD_ARG(static-oob, NULL, "[val: 1-16 hex values]", |
| cmd_static_oob, 2, 1), |
| SHELL_CMD_ARG(provision, NULL, "<NetKeyIndex> <addr> [IVIndex]", |
| cmd_provision, 3, 1), |
| SHELL_CMD_ARG(beacon-listen, NULL, "<val: off, on>", cmd_beacon_listen, |
| 2, 0), |
| |
| #if defined(CONFIG_BT_MESH_CFG_CLI) |
| /* Configuration Client Model operations */ |
| SHELL_CMD_ARG(timeout, NULL, "[timeout in seconds]", cmd_timeout, 1, 1), |
| SHELL_CMD_ARG(get-comp, NULL, "[page]", cmd_get_comp, 1, 1), |
| SHELL_CMD_ARG(beacon, NULL, "[val: off, on]", cmd_beacon, 1, 1), |
| SHELL_CMD_ARG(ttl, NULL, "[ttl: 0x00, 0x02-0x7f]", cmd_ttl, 1, 1), |
| SHELL_CMD_ARG(friend, NULL, "[val: off, on]", cmd_friend, 1, 1), |
| SHELL_CMD_ARG(gatt-proxy, NULL, "[val: off, on]", cmd_gatt_proxy, 1, 1), |
| SHELL_CMD_ARG(relay, NULL, |
| "[<val: off, on> [<count: 0-7> [interval: 10-320]]]", |
| cmd_relay, 1, 3), |
| SHELL_CMD_ARG(net-key-add, NULL, "<NetKeyIndex> [val]", cmd_net_key_add, |
| 2, 1), |
| SHELL_CMD_ARG(net-key-upd, NULL, "<NetKeyIndex> [val]", cmd_net_key_update, |
| 2, 1), |
| SHELL_CMD_ARG(net-key-get, NULL, NULL, cmd_net_key_get, 1, 0), |
| SHELL_CMD_ARG(net-key-del, NULL, "<NetKeyIndex>", cmd_net_key_del, 2, |
| 0), |
| SHELL_CMD_ARG(app-key-add, NULL, "<NetKeyIndex> <AppKeyIndex> [val]", |
| cmd_app_key_add, 3, 1), |
| SHELL_CMD_ARG(app-key-upd, NULL, "<NetKeyIndex> <AppKeyIndex> [val]", |
| cmd_app_key_upd, 3, 1), |
| SHELL_CMD_ARG(app-key-del, NULL, "<NetKeyIndex> <AppKeyIndex>", |
| cmd_app_key_del, 3, 0), |
| SHELL_CMD_ARG(app-key-get, NULL, "<NetKeyIndex>", cmd_app_key_get, 2, |
| 0), |
| SHELL_CMD_ARG(node-id, NULL, "<NetKeyIndex> [Identify]", cmd_node_id, 2, 1), |
| SHELL_CMD_ARG(polltimeout-get, NULL, "<LPN Address>", cmd_polltimeout_get, 2, 0), |
| SHELL_CMD_ARG(net-transmit-param, NULL, "[<count: 0-7>" |
| " <interval: 10-320>]", cmd_net_transmit, 1, 2), |
| SHELL_CMD_ARG(mod-app-bind, NULL, |
| "<addr> <AppIndex> <Model ID> [Company ID]", |
| cmd_mod_app_bind, 4, 1), |
| SHELL_CMD_ARG(mod-app-get, NULL, |
| "<elem addr> <Model ID> [Company ID]", |
| cmd_mod_app_get, 3, 1), |
| SHELL_CMD_ARG(mod-app-unbind, NULL, |
| "<addr> <AppIndex> <Model ID> [Company ID]", |
| cmd_mod_app_unbind, 4, 1), |
| SHELL_CMD_ARG(mod-pub, NULL, "<addr> <mod id> [cid] [<PubAddr> " |
| "<AppKeyIndex> <cred: off, on> <ttl> <period> <count> <interval>]", |
| cmd_mod_pub, 3, 1 + 7), |
| SHELL_CMD_ARG(mod-pub-va, NULL, "<addr> <UUID: 16 hex values> " |
| "<AppKeyIndex> <cred: off, on> <ttl> <period> <count> <interval> " |
| "<mod id> [cid]", |
| cmd_mod_pub_va, 10, 1), |
| SHELL_CMD_ARG(mod-sub-add, NULL, |
| "<elem addr> <sub addr> <Model ID> [Company ID]", |
| cmd_mod_sub_add, 4, 1), |
| SHELL_CMD_ARG(mod-sub-del, NULL, |
| "<elem addr> <sub addr> <Model ID> [Company ID]", |
| cmd_mod_sub_del, 4, 1), |
| SHELL_CMD_ARG(mod-sub-add-va, NULL, |
| "<elem addr> <Label UUID> <Model ID> [Company ID]", |
| cmd_mod_sub_add_va, 4, 1), |
| SHELL_CMD_ARG(mod-sub-del-va, NULL, |
| "<elem addr> <Label UUID> <Model ID> [Company ID]", |
| cmd_mod_sub_del_va, 4, 1), |
| SHELL_CMD_ARG(mod-sub-ow, NULL, |
| "<elem addr> <sub addr> <Model ID> [Company ID]", |
| cmd_mod_sub_ow, 4, 1), |
| SHELL_CMD_ARG(mod-sub-ow-va, NULL, |
| "<elem addr> <Label UUID> <Model ID> [Company ID]", |
| cmd_mod_sub_ow_va, 4, 1), |
| SHELL_CMD_ARG(mod-sub-del-all, NULL, |
| "<elem addr> <Model ID> [Company ID]", |
| cmd_mod_sub_del_all, 3, 1), |
| SHELL_CMD_ARG(mod-sub-get, NULL, |
| "<elem addr> <Model ID> [Company ID]", |
| cmd_mod_sub_get, 3, 1), |
| SHELL_CMD_ARG(krp, NULL, "<NetKeyIndex> [Phase]", |
| cmd_krp, 2, 1), |
| SHELL_CMD_ARG(hb-sub, NULL, "[<src> <dst> <period>]", cmd_hb_sub, 1, 3), |
| SHELL_CMD_ARG(hb-pub, NULL, |
| "[<dst> <count> <period> <ttl> <features> <NetKeyIndex>]", |
| cmd_hb_pub, 1, 6), |
| #endif |
| |
| #if defined(CONFIG_BT_MESH_HEALTH_CLI) |
| /* Health Client Model Operations */ |
| SHELL_CMD_ARG(fault-get, NULL, "<Company ID>", cmd_fault_get, 2, 0), |
| SHELL_CMD_ARG(fault-clear, NULL, "<Company ID>", cmd_fault_clear, 2, 0), |
| SHELL_CMD_ARG(fault-clear-unack, NULL, "<Company ID>", |
| cmd_fault_clear_unack, 2, 0), |
| SHELL_CMD_ARG(fault-test, NULL, "<Company ID> <Test ID>", |
| cmd_fault_test, 3, 0), |
| SHELL_CMD_ARG(fault-test-unack, NULL, "<Company ID> <Test ID>", |
| cmd_fault_test_unack, 3, 0), |
| SHELL_CMD_ARG(period-get, NULL, NULL, cmd_period_get, 1, 0), |
| SHELL_CMD_ARG(period-set, NULL, "<divisor>", cmd_period_set, 2, 0), |
| SHELL_CMD_ARG(period-set-unack, NULL, "<divisor>", cmd_period_set_unack, |
| 2, 0), |
| SHELL_CMD_ARG(attention-get, NULL, NULL, cmd_attention_get, 1, 0), |
| SHELL_CMD_ARG(attention-set, NULL, "<timer>", cmd_attention_set, 2, 0), |
| SHELL_CMD_ARG(attention-set-unack, NULL, "<timer>", |
| cmd_attention_set_unack, 2, 0), |
| #endif |
| |
| /* Health Server Model Operations */ |
| SHELL_CMD_ARG(add-fault, NULL, "<Fault ID>", cmd_add_fault, 2, 0), |
| SHELL_CMD_ARG(del-fault, NULL, "[Fault ID]", cmd_del_fault, 1, 1), |
| |
| #if defined(CONFIG_BT_MESH_CDB) |
| /* Mesh Configuration Database Operations */ |
| SHELL_CMD_ARG(cdb-create, NULL, "[NetKey]", cmd_cdb_create, 1, 1), |
| SHELL_CMD_ARG(cdb-clear, NULL, NULL, cmd_cdb_clear, 1, 0), |
| SHELL_CMD_ARG(cdb-show, NULL, NULL, cmd_cdb_show, 1, 0), |
| SHELL_CMD_ARG(cdb-node-add, NULL, "<UUID> <addr> <num-elem> " |
| "<NetKeyIdx> [DevKey]", cmd_cdb_node_add, 5, 1), |
| SHELL_CMD_ARG(cdb-node-del, NULL, "<addr>", cmd_cdb_node_del, 2, 0), |
| SHELL_CMD_ARG(cdb-subnet-add, NULL, "<NeyKeyIdx> [<NetKey>]", |
| cmd_cdb_subnet_add, 2, 1), |
| SHELL_CMD_ARG(cdb-subnet-del, NULL, "<NetKeyIdx>", cmd_cdb_subnet_del, |
| 2, 0), |
| SHELL_CMD_ARG(cdb-app-key-add, NULL, "<NetKeyIdx> <AppKeyIdx> " |
| "[<AppKey>]", cmd_cdb_app_key_add, 3, 1), |
| SHELL_CMD_ARG(cdb-app-key-del, NULL, "<AppKeyIdx>", cmd_cdb_app_key_del, |
| 2, 0), |
| #endif |
| |
| SHELL_SUBCMD_SET_END |
| ); |
| |
| static int cmd_mesh(const struct shell *shell, size_t argc, char **argv) |
| { |
| if (argc == 1) { |
| shell_help(shell); |
| /* shell returns 1 when help is printed */ |
| return 1; |
| } |
| |
| shell_error(shell, "%s unknown parameter: %s", argv[0], argv[1]); |
| |
| return -EINVAL; |
| } |
| |
| SHELL_CMD_ARG_REGISTER(mesh, &mesh_cmds, "Bluetooth mesh shell commands", |
| cmd_mesh, 1, 1); |