| /** @file |
| * @brief Bluetooth Mesh shell |
| * |
| */ |
| |
| /* |
| * Copyright (c) 2017 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "syscfg/syscfg.h" |
| |
| #if MYNEWT_VAL(BLE_MESH_SHELL) |
| |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <errno.h> |
| #include "shell/shell.h" |
| #include "console/console.h" |
| #include "mesh/mesh.h" |
| #include "mesh/main.h" |
| #include "mesh/glue.h" |
| #include "mesh/testing.h" |
| |
| /* Private includes for raw Network & Transport layer access */ |
| #include "net.h" |
| #include "rpl.h" |
| #include "access.h" |
| #include "mesh_priv.h" |
| #include "lpn.h" |
| #include "transport.h" |
| #include "foundation.h" |
| #include "testing.h" |
| #include "settings.h" |
| |
| #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) |
| #include "mesh/model_srv.h" |
| #include "mesh/model_cli.h" |
| #include "light_model.h" |
| #endif |
| |
| /* This should be higher priority (lower value) than main task priority */ |
| #define BLE_MESH_SHELL_TASK_PRIO 126 |
| #define BLE_MESH_SHELL_STACK_SIZE 768 |
| |
| OS_TASK_STACK_DEFINE(g_blemesh_shell_stack, BLE_MESH_SHELL_STACK_SIZE); |
| |
| struct os_task mesh_shell_task; |
| static struct os_eventq mesh_shell_queue; |
| |
| #define CID_NVAL 0xffff |
| #define CID_VENDOR 0x05C3 |
| |
| /* Vendor Model data */ |
| #define VND_MODEL_ID_1 0x1234 |
| |
| /* 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, |
| }; |
| |
| #define CUR_FAULTS_MAX 4 |
| |
| static uint8_t cur_faults[CUR_FAULTS_MAX]; |
| static uint8_t reg_faults[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 = 0, *count = 0; 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) |
| { |
| printk("Sending current faults\n"); |
| |
| *test_id = 0x00; |
| *company_id = CID_VENDOR; |
| |
| 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 != CID_VENDOR) { |
| printk("Faults requested for unknown Company ID 0x%04x\n", cid); |
| return -EINVAL; |
| } |
| |
| printk("Sending registered faults\n"); |
| |
| *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 != CID_VENDOR) { |
| return -EINVAL; |
| } |
| |
| 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 != CID_VENDOR) { |
| 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, |
| }; |
| |
| static struct bt_mesh_health_srv health_srv = { |
| .cb = &health_srv_cb, |
| }; |
| |
| static struct bt_mesh_model_pub health_pub; |
| |
| static void |
| health_pub_init(void) |
| { |
| health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(CUR_FAULTS_MAX); |
| } |
| #if MYNEWT_VAL(BLE_MESH_CFG_CLI) |
| |
| static struct bt_mesh_cfg_cli cfg_cli = { |
| }; |
| |
| #endif /* MYNEWT_VAL(BLE_MESH_CFG_CLI) */ |
| |
| #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) |
| void show_faults(uint8_t test_id, uint16_t cid, uint8_t *faults, size_t fault_count) |
| { |
| size_t i; |
| |
| if (!fault_count) { |
| printk("Health Test ID 0x%02x Company ID 0x%04x: no faults\n", |
| test_id, cid); |
| return; |
| } |
| |
| printk("Health Test ID 0x%02x Company ID 0x%04x Fault Count %zu:\n", |
| test_id, cid, fault_count); |
| |
| for (i = 0; i < fault_count; i++) { |
| printk("\t0x%02x\n", 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) |
| { |
| printk("Health Current Status from 0x%04x\n", addr); |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| static struct bt_mesh_health_cli health_cli = { |
| .current_status = health_current_status, |
| }; |
| |
| #endif /* MYNEWT_VAL(BLE_MESH_HEALTH_CLI) */ |
| |
| #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) |
| static struct bt_mesh_gen_model_cli gen_onoff_cli; |
| static struct bt_mesh_model_pub gen_onoff_cli_pub; |
| static struct bt_mesh_model_pub gen_onoff_srv_pub; |
| static struct bt_mesh_gen_model_cli gen_level_cli; |
| static struct bt_mesh_model_pub gen_level_cli_pub; |
| static struct bt_mesh_model_pub gen_level_srv_pub; |
| static struct bt_mesh_model_pub light_lightness_pub; |
| static struct bt_mesh_gen_onoff_srv gen_onoff_srv = { |
| .get = light_model_gen_onoff_get, |
| .set = light_model_gen_onoff_set, |
| }; |
| static struct bt_mesh_gen_level_srv gen_level_srv = { |
| .get = light_model_gen_level_get, |
| .set = light_model_gen_level_set, |
| }; |
| static struct bt_mesh_light_lightness_srv light_lightness_srv = { |
| .get = light_model_light_lightness_get, |
| .set = light_model_light_lightness_set, |
| }; |
| |
| void bt_mesh_set_gen_onoff_srv_cb(int (*get)(struct bt_mesh_model *model, uint8_t *state), |
| int (*set)(struct bt_mesh_model *model, uint8_t state)) |
| { |
| gen_onoff_srv.get = get; |
| gen_onoff_srv.set = set; |
| } |
| |
| void bt_mesh_set_gen_level_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level), |
| int (*set)(struct bt_mesh_model *model, int16_t level)) |
| { |
| gen_level_srv.get = get; |
| gen_level_srv.set = set; |
| } |
| |
| void bt_mesh_set_light_lightness_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level), |
| int (*set)(struct bt_mesh_model *model, int16_t level)) |
| { |
| light_lightness_srv.get = get; |
| light_lightness_srv.set = set; |
| } |
| #endif |
| |
| static struct bt_mesh_model root_models[] = { |
| BT_MESH_MODEL_CFG_SRV, |
| BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), |
| #if MYNEWT_VAL(BLE_MESH_CFG_CLI) |
| BT_MESH_MODEL_CFG_CLI(&cfg_cli), |
| #endif |
| #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) |
| BT_MESH_MODEL_HEALTH_CLI(&health_cli), |
| #endif |
| #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) |
| BT_MESH_MODEL_GEN_ONOFF_SRV(&gen_onoff_srv, &gen_onoff_srv_pub), |
| BT_MESH_MODEL_GEN_ONOFF_CLI(&gen_onoff_cli, &gen_onoff_cli_pub), |
| BT_MESH_MODEL_GEN_LEVEL_SRV(&gen_level_srv, &gen_level_srv_pub), |
| BT_MESH_MODEL_GEN_LEVEL_CLI(&gen_level_cli, &gen_level_cli_pub), |
| BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(&light_lightness_srv, &light_lightness_pub), |
| #endif |
| }; |
| |
| static struct bt_mesh_model vnd_models[] = { |
| BT_MESH_MODEL_VND(CID_VENDOR, VND_MODEL_ID_1, |
| BT_MESH_MODEL_NO_OPS, NULL, NULL), |
| }; |
| |
| static struct bt_mesh_elem elements[] = { |
| BT_MESH_ELEM(0, root_models, vnd_models), |
| }; |
| |
| static const struct bt_mesh_comp comp = { |
| .cid = CID_VENDOR, |
| .elem = elements, |
| .elem_count = ARRAY_SIZE(elements), |
| }; |
| |
| static uint8_t hex2val(char c) |
| { |
| if (c >= '0' && c <= '9') { |
| return c - '0'; |
| } else if (c >= 'a' && c <= 'f') { |
| return c - 'a' + 10; |
| } else if (c >= 'A' && c <= 'F') { |
| return c - 'A' + 10; |
| } else { |
| return 0; |
| } |
| } |
| |
| int char2hex(char c, uint8_t *x) |
| { |
| if (c >= '0' && c <= '9') { |
| *x = c - '0'; |
| } else if (c >= 'a' && c <= 'f') { |
| *x = c - 'a' + 10; |
| } else if (c >= 'A' && c <= 'F') { |
| *x = c - 'A' + 10; |
| } else { |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| int hex2char(uint8_t x, char *c) |
| { |
| if (x <= 9) { |
| *c = x + '0'; |
| } else if (x <= 15) { |
| *c = x - 10 + 'a'; |
| } else { |
| return -EINVAL; |
| } |
| |
| return 0; |
| } |
| |
| size_t bin2hex(const uint8_t *buf, size_t buflen, char *hex, size_t hexlen) |
| { |
| if ((hexlen + 1) < buflen * 2) { |
| return 0; |
| } |
| |
| for (size_t i = 0; i < buflen; i++) { |
| if (hex2char(buf[i] >> 4, &hex[2 * i]) < 0) { |
| return 0; |
| } |
| if (hex2char(buf[i] & 0xf, &hex[2 * i + 1]) < 0) { |
| return 0; |
| } |
| } |
| |
| hex[2 * buflen] = '\0'; |
| return 2 * buflen; |
| } |
| |
| static size_t hex2bin(const char *hex, uint8_t *bin, size_t bin_len) |
| { |
| size_t len = 0; |
| |
| while (*hex && len < bin_len) { |
| bin[len] = hex2val(*hex++) << 4; |
| |
| if (!*hex) { |
| len++; |
| break; |
| } |
| |
| bin[len++] |= hex2val(*hex++); |
| } |
| |
| return len; |
| } |
| |
| static void prov_complete(uint16_t net_idx, uint16_t addr) |
| { |
| printk("Local node provisioned, net_idx 0x%04x address 0x%04x\n", |
| 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) |
| { |
| printk("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) |
| { |
| printk("Input complete"); |
| } |
| |
| static void prov_reset(void) |
| { |
| printk("The local node has been reset and needs reprovisioning\n"); |
| } |
| |
| static int output_number(bt_mesh_output_action_t action, uint32_t number) |
| { |
| printk("OOB Number: %lu\n", number); |
| return 0; |
| } |
| |
| static int output_string(const char *str) |
| { |
| printk("OOB String: %s\n", str); |
| return 0; |
| } |
| |
| static bt_mesh_input_action_t input_act; |
| static uint8_t input_size; |
| |
| static int cmd_input_num(int argc, char *argv[]) |
| { |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| if (input_act != BT_MESH_ENTER_NUMBER) { |
| printk("A number hasn't been requested!\n"); |
| return 0; |
| } |
| |
| if (strlen(argv[1]) < input_size) { |
| printk("Too short input (%u digits required)\n", |
| input_size); |
| return 0; |
| } |
| |
| err = bt_mesh_input_number(strtoul(argv[1], NULL, 10)); |
| if (err) { |
| printk("Numeric input failed (err %d)\n", err); |
| return 0; |
| } |
| |
| input_act = BT_MESH_NO_INPUT; |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_input_num_help = { |
| NULL, "<number>", NULL |
| }; |
| |
| static int cmd_input_str(int argc, char *argv[]) |
| { |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| if (input_act != BT_MESH_ENTER_STRING) { |
| printk("A string hasn't been requested!\n"); |
| return 0; |
| } |
| |
| if (strlen(argv[1]) < input_size) { |
| printk("Too short input (%u characters required)\n", |
| input_size); |
| return 0; |
| } |
| |
| err = bt_mesh_input_string(argv[1]); |
| if (err) { |
| printk("String input failed (err %d)\n", err); |
| return 0; |
| } |
| |
| input_act = BT_MESH_NO_INPUT; |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_input_str_help = { |
| NULL, "<string>", NULL |
| }; |
| |
| static int input(bt_mesh_input_action_t act, uint8_t size) |
| { |
| switch (act) { |
| case BT_MESH_ENTER_NUMBER: |
| printk("Enter a number (max %u digits) with: input-num <num>\n", |
| size); |
| break; |
| case BT_MESH_ENTER_STRING: |
| printk("Enter a string (max %u chars) with: input-str <str>\n", |
| size); |
| break; |
| default: |
| printk("Unknown input action %u (size %u) requested!\n", |
| 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) |
| { |
| printk("Provisioning link opened on %s\n", bearer2str(bearer)); |
| } |
| |
| static void link_close(bt_mesh_prov_bearer_t bearer) |
| { |
| printk("Provisioning link closed on %s\n", bearer2str(bearer)); |
| } |
| |
| static uint8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID); |
| |
| static uint8_t static_val[16]; |
| |
| static struct bt_mesh_prov 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 = MYNEWT_VAL(BLE_MESH_OOB_OUTPUT_SIZE), |
| .output_actions = MYNEWT_VAL(BLE_MESH_OOB_OUTPUT_ACTIONS), |
| .output_number = output_number, |
| .output_string = output_string, |
| .input_size = MYNEWT_VAL(BLE_MESH_OOB_INPUT_SIZE), |
| .input_actions = MYNEWT_VAL(BLE_MESH_OOB_INPUT_ACTIONS), |
| .input = input, |
| .input_complete = prov_input_complete, |
| }; |
| |
| static int cmd_static_oob(int argc, char *argv[]) |
| { |
| if (argc < 2) { |
| prov.static_val = NULL; |
| prov.static_val_len = 0; |
| } else { |
| prov.static_val_len = hex2bin(argv[1], static_val, 16); |
| if (prov.static_val_len) { |
| prov.static_val = static_val; |
| } else { |
| prov.static_val = NULL; |
| } |
| } |
| |
| if (prov.static_val) { |
| printk("Static OOB value set (length %u)\n", |
| prov.static_val_len); |
| } else { |
| printk("Static OOB value cleared\n"); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_static_oob_help = { |
| NULL, "[val: 1-16 hex values]", NULL |
| }; |
| |
| static int cmd_uuid(int argc, char *argv[]) |
| { |
| uint8_t uuid[16]; |
| size_t len; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| len = hex2bin(argv[1], uuid, sizeof(uuid)); |
| if (len < 1) { |
| return -EINVAL; |
| } |
| |
| memcpy(dev_uuid, uuid, len); |
| memset(dev_uuid + len, 0, sizeof(dev_uuid) - len); |
| |
| printk("Device UUID set\n"); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_uuid_help = { |
| NULL, "<UUID: 1-16 hex values>", NULL |
| }; |
| |
| static int cmd_reset(int argc, char *argv[]) |
| { |
| uint16_t addr; |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| addr = strtoul(argv[1], NULL, 0); |
| |
| if (addr == net.local) { |
| bt_mesh_reset(); |
| printk("Local node reset complete"); |
| } else { |
| int err; |
| bool reset = false; |
| |
| err = bt_mesh_cfg_node_reset(net.net_idx, net.dst, &reset); |
| if (err) { |
| printk("Unable to send " |
| "Remote Node Reset (err %d)", err); |
| return 0; |
| } |
| |
| printk("Remote node reset complete"); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_reset_help = { |
| NULL, "<addr>", NULL |
| }; |
| |
| static uint8_t str2u8(const char *str) |
| { |
| if (isdigit(str[0])) { |
| return strtoul(str, NULL, 0); |
| } |
| |
| return (!strcmp(str, "on") || !strcmp(str, "enable")); |
| } |
| |
| static bool str2bool(const char *str) |
| { |
| return str2u8(str); |
| } |
| |
| #if MYNEWT_VAL(BLE_MESH_LOW_POWER) |
| static int cmd_lpn(int argc, char *argv[]) |
| { |
| static bool enabled; |
| int err; |
| |
| if (argc < 2) { |
| printk("%s\n", enabled ? "enabled" : "disabled"); |
| return 0; |
| } |
| |
| if (str2bool(argv[1])) { |
| if (enabled) { |
| printk("LPN already enabled\n"); |
| return 0; |
| } |
| |
| err = bt_mesh_lpn_set(true); |
| if (err) { |
| printk("Enabling LPN failed (err %d)\n", err); |
| } else { |
| enabled = true; |
| } |
| } else { |
| if (!enabled) { |
| printk("LPN already disabled\n"); |
| return 0; |
| } |
| |
| err = bt_mesh_lpn_set(false); |
| if (err) { |
| printk("Enabling LPN failed (err %d)\n", err); |
| } else { |
| enabled = false; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_poll(int argc, char *argv[]) |
| { |
| int err; |
| |
| err = bt_mesh_lpn_poll(); |
| if (err) { |
| printk("Friend Poll failed (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| |
| static void lpn_cb(uint16_t friend_addr, bool established) |
| { |
| if (established) { |
| printk("Friendship (as LPN) established to Friend 0x%04x\n", |
| friend_addr); |
| } else { |
| printk("Friendship (as LPN) lost with Friend 0x%04x\n", |
| friend_addr); |
| } |
| } |
| |
| struct shell_cmd_help cmd_lpn_help = { |
| NULL, "<value: off, on>", NULL |
| }; |
| |
| #endif /* MESH_LOW_POWER */ |
| |
| static int check_pub_addr_unassigned(void) |
| { |
| #ifdef ARCH_sim |
| return 0; |
| #else |
| uint8_t zero_addr[BLE_DEV_ADDR_LEN] = { 0 }; |
| |
| return memcmp(MYNEWT_VAL(BLE_PUBLIC_DEV_ADDR), |
| zero_addr, BLE_DEV_ADDR_LEN) == 0; |
| #endif |
| } |
| |
| int cmd_mesh_init(int argc, char *argv[]) |
| { |
| int err; |
| ble_addr_t addr; |
| |
| if (check_pub_addr_unassigned()) { |
| /* Use NRPA */ |
| err = ble_hs_id_gen_rnd(1, &addr); |
| assert(err == 0); |
| err = ble_hs_id_set_rnd(addr.val); |
| assert(err == 0); |
| |
| err = bt_mesh_init(addr.type, &prov, &comp); |
| } |
| else { |
| err = bt_mesh_init(0, &prov, &comp); |
| } |
| |
| if (err) { |
| printk("Mesh initialization failed (err %d)\n", err); |
| } |
| |
| printk("Mesh initialized\n"); |
| |
| if (IS_ENABLED(CONFIG_SETTINGS)) { |
| settings_load(); |
| } |
| |
| if (bt_mesh_is_provisioned()) { |
| printk("Mesh network restored from flash\n"); |
| } else { |
| printk("Use \"pb-adv on\" or \"pb-gatt on\" to enable" |
| " advertising\n"); |
| } |
| |
| #if MYNEWT_VAL(BLE_MESH_LOW_POWER) |
| bt_mesh_lpn_set_cb(lpn_cb); |
| #endif |
| |
| return 0; |
| } |
| |
| #if MYNEWT_VAL(BLE_MESH_GATT_PROXY) |
| static int cmd_ident(int argc, char *argv[]) |
| { |
| int err; |
| |
| err = bt_mesh_proxy_identity_enable(); |
| if (err) { |
| printk("Failed advertise using Node Identity (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| #endif /* MESH_GATT_PROXY */ |
| |
| static int cmd_dst(int argc, char *argv[]) |
| { |
| if (argc < 2) { |
| printk("Destination address: 0x%04x%s\n", net.dst, |
| net.dst == net.local ? " (local)" : ""); |
| return 0; |
| } |
| |
| if (!strcmp(argv[1], "local")) { |
| net.dst = net.local; |
| } else { |
| net.dst = strtoul(argv[1], NULL, 0); |
| } |
| |
| printk("Destination address set to 0x%04x%s\n", net.dst, |
| net.dst == net.local ? " (local)" : ""); |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_dst_help = { |
| NULL, "[destination address]", NULL |
| }; |
| |
| static int cmd_netidx(int argc, char *argv[]) |
| { |
| if (argc < 2) { |
| printk("NetIdx: 0x%04x\n", net.net_idx); |
| return 0; |
| } |
| |
| net.net_idx = strtoul(argv[1], NULL, 0); |
| printk("NetIdx set to 0x%04x\n", net.net_idx); |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_netidx_help = { |
| NULL, "[NetIdx]", NULL |
| }; |
| |
| static int cmd_appidx(int argc, char *argv[]) |
| { |
| if (argc < 2) { |
| printk("AppIdx: 0x%04x\n", net.app_idx); |
| return 0; |
| } |
| |
| net.app_idx = strtoul(argv[1], NULL, 0); |
| printk("AppIdx set to 0x%04x\n", net.app_idx); |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_appidx_help = { |
| NULL, "[AppIdx]", NULL |
| }; |
| |
| static int cmd_net_send(int argc, char *argv[]) |
| { |
| struct os_mbuf *msg = NET_BUF_SIMPLE(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 = 0; |
| |
| if (argc < 2) { |
| err = -EINVAL; |
| goto done; |
| } |
| |
| net_buf_simple_init(msg, 0); |
| len = hex2bin(argv[1], msg->om_data, net_buf_simple_tailroom(msg) - 4); |
| net_buf_simple_add(msg, len); |
| |
| err = bt_mesh_trans_send(&tx, msg, NULL, NULL); |
| if (err) { |
| printk("Failed to send (err %d)\n", err); |
| } |
| |
| done: |
| os_mbuf_free_chain(msg); |
| return err; |
| } |
| |
| struct shell_cmd_help cmd_net_send_help = { |
| NULL, "<hex string>", NULL |
| }; |
| |
| static int cmd_rpl_clear(int argc, char *argv[]) |
| { |
| bt_mesh_rpl_clear(); |
| return 0; |
| } |
| |
| #if MYNEWT_VAL(BLE_MESH_LOW_POWER) |
| static int cmd_lpn_subscribe(int argc, char *argv[]) |
| { |
| uint16_t address; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| address = strtoul(argv[1], NULL, 0); |
| |
| printk("address 0x%04x", address); |
| |
| bt_mesh_lpn_group_add(address); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_lpn_subscribe_help = { |
| NULL, "<addr>", NULL |
| }; |
| |
| static int cmd_lpn_unsubscribe(int argc, char *argv[]) |
| { |
| uint16_t address; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| address = strtoul(argv[1], NULL, 0); |
| |
| printk("address 0x%04x", address); |
| |
| bt_mesh_lpn_group_del(&address, 1); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_lpn_unsubscribe_help = { |
| NULL, "<addr>", NULL |
| }; |
| #endif |
| |
| #if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST) |
| static int cmd_iv_update(int argc, char *argv[]) |
| { |
| if (bt_mesh_iv_update()) { |
| printk("Transitioned to IV Update In Progress state\n"); |
| } else { |
| printk("Transitioned to IV Update Normal state\n"); |
| } |
| |
| printk("IV Index is 0x%08lx\n", bt_mesh.iv_index); |
| |
| return 0; |
| } |
| |
| static int cmd_iv_update_test(int argc, char *argv[]) |
| { |
| bool enable; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| enable = str2bool(argv[1]); |
| if (enable) { |
| printk("Enabling IV Update test mode\n"); |
| } else { |
| printk("Disabling IV Update test mode\n"); |
| } |
| |
| bt_mesh_iv_update_test(enable); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_iv_update_test_help = { |
| NULL, "<value: off, on>", NULL |
| }; |
| #endif |
| |
| #if MYNEWT_VAL(BLE_MESH_CFG_CLI) |
| |
| int cmd_timeout(int argc, char *argv[]) |
| { |
| int32_t timeout; |
| |
| if (argc < 2) { |
| timeout = bt_mesh_cfg_cli_timeout_get(); |
| if (timeout == K_FOREVER) { |
| printk("Message timeout: forever\n"); |
| } else { |
| printk("Message timeout: %lu seconds\n", |
| timeout / 1000); |
| } |
| |
| return 0; |
| } |
| |
| timeout = strtol(argv[1], NULL, 0); |
| if (timeout < 0 || timeout > (INT32_MAX / 1000)) { |
| timeout = K_FOREVER; |
| } else { |
| timeout = timeout * 1000; |
| } |
| |
| bt_mesh_cfg_cli_timeout_set(timeout); |
| if (timeout == K_FOREVER) { |
| printk("Message timeout: forever\n"); |
| } else { |
| printk("Message timeout: %lu seconds\n", |
| timeout / 1000); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_timeout_help = { |
| NULL, "[timeout in seconds]", NULL |
| }; |
| |
| |
| static int cmd_get_comp(int argc, char *argv[]) |
| { |
| struct os_mbuf *comp = NET_BUF_SIMPLE(32); |
| uint8_t status, page = 0x00; |
| int err = 0; |
| |
| if (argc > 1) { |
| page = strtol(argv[1], NULL, 0); |
| } |
| |
| net_buf_simple_init(comp, 0); |
| err = bt_mesh_cfg_comp_data_get(net.net_idx, net.dst, page, |
| &status, comp); |
| if (err) { |
| printk("Getting composition failed (err %d)\n", err); |
| goto done; |
| } |
| |
| if (status != 0x00) { |
| printk("Got non-success status 0x%02x\n", status); |
| goto done; |
| } |
| |
| printk("Got Composition Data for 0x%04x:\n", net.dst); |
| printk("\tCID 0x%04x\n", net_buf_simple_pull_le16(comp)); |
| printk("\tPID 0x%04x\n", net_buf_simple_pull_le16(comp)); |
| printk("\tVID 0x%04x\n", net_buf_simple_pull_le16(comp)); |
| printk("\tCRPL 0x%04x\n", net_buf_simple_pull_le16(comp)); |
| printk("\tFeatures 0x%04x\n", net_buf_simple_pull_le16(comp)); |
| |
| while (comp->om_len > 4) { |
| uint8_t sig, vnd; |
| uint16_t loc; |
| int i; |
| |
| loc = net_buf_simple_pull_le16(comp); |
| sig = net_buf_simple_pull_u8(comp); |
| vnd = net_buf_simple_pull_u8(comp); |
| |
| printk("\n\tElement @ 0x%04x:\n", loc); |
| |
| if (comp->om_len < ((sig * 2) + (vnd * 4))) { |
| printk("\t\t...truncated data!\n"); |
| break; |
| } |
| |
| if (sig) { |
| printk("\t\tSIG Models:\n"); |
| } else { |
| printk("\t\tNo SIG Models\n"); |
| } |
| |
| for (i = 0; i < sig; i++) { |
| uint16_t mod_id = net_buf_simple_pull_le16(comp); |
| |
| printk("\t\t\t0x%04x\n", mod_id); |
| } |
| |
| if (vnd) { |
| printk("\t\tVendor Models:\n"); |
| } else { |
| printk("\t\tNo Vendor Models\n"); |
| } |
| |
| for (i = 0; i < vnd; i++) { |
| uint16_t cid = net_buf_simple_pull_le16(comp); |
| uint16_t mod_id = net_buf_simple_pull_le16(comp); |
| |
| printk("\t\t\tCompany 0x%04x: 0x%04x\n", cid, mod_id); |
| } |
| } |
| |
| done: |
| os_mbuf_free_chain(comp); |
| return err; |
| } |
| |
| struct shell_cmd_help cmd_get_comp_help = { |
| NULL, "[page]", NULL |
| }; |
| |
| static int cmd_beacon(int argc, char *argv[]) |
| { |
| uint8_t status; |
| int err; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_beacon_get(net.net_idx, net.dst, &status); |
| } else { |
| uint8_t val = str2u8(argv[1]); |
| |
| err = bt_mesh_cfg_beacon_set(net.net_idx, net.dst, val, |
| &status); |
| } |
| |
| if (err) { |
| printk("Unable to send Beacon Get/Set message (err %d)\n", err); |
| return 0; |
| } |
| |
| printk("Beacon state is 0x%02x\n", status); |
| |
| return 0; |
| } |
| |
| 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)); |
| |
| printk("UUID %s, OOB Info 0x%04x, URI Hash 0x%lx", |
| uuid_hex_str, oob_info, |
| (uri_hash == NULL ? 0 : *uri_hash)); |
| } |
| |
| static int cmd_beacon_listen(int argc, char *argv[]) |
| { |
| uint8_t val = str2u8(argv[1]); |
| |
| if (val) { |
| prov.unprovisioned_beacon = print_unprovisioned_beacon; |
| } else { |
| prov.unprovisioned_beacon = NULL; |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_beacon_help = { |
| NULL, "[val: off, on]", NULL |
| }; |
| |
| struct shell_cmd_help cmd_beacon_listen_help = { |
| NULL, "[val: off, on]", NULL |
| }; |
| |
| static int cmd_ttl(int argc, char *argv[]) |
| { |
| uint8_t ttl; |
| int err; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_ttl_get(net.net_idx, net.dst, &ttl); |
| } else { |
| uint8_t val = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_cfg_ttl_set(net.net_idx, net.dst, val, &ttl); |
| } |
| |
| if (err) { |
| printk("Unable to send Default TTL Get/Set (err %d)\n", err); |
| return 0; |
| } |
| |
| printk("Default TTL is 0x%02x\n", ttl); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_ttl_help = { |
| NULL, "[ttl: 0x00, 0x02-0x7f]", NULL |
| }; |
| |
| static int cmd_friend(int argc, char *argv[]) |
| { |
| uint8_t frnd; |
| int err; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_friend_get(net.net_idx, net.dst, &frnd); |
| } else { |
| uint8_t val = str2u8(argv[1]); |
| |
| err = bt_mesh_cfg_friend_set(net.net_idx, net.dst, val, &frnd); |
| } |
| |
| if (err) { |
| printk("Unable to send Friend Get/Set (err %d)\n", err); |
| return 0; |
| } |
| |
| printk("Friend is set to 0x%02x\n", frnd); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_friend_help = { |
| NULL, "[val: off, on]", NULL |
| }; |
| |
| static int cmd_gatt_proxy(int argc, char *argv[]) |
| { |
| uint8_t proxy; |
| int err; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_gatt_proxy_get(net.net_idx, net.dst, &proxy); |
| } else { |
| uint8_t val = str2u8(argv[1]); |
| |
| err = bt_mesh_cfg_gatt_proxy_set(net.net_idx, net.dst, val, |
| &proxy); |
| } |
| |
| if (err) { |
| printk("Unable to send GATT Proxy Get/Set (err %d)\n", err); |
| return 0; |
| } |
| |
| printk("GATT Proxy is set to 0x%02x\n", proxy); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_gatt_proxy_help = { |
| NULL, "[val: off, on]", NULL |
| }; |
| |
| static int cmd_net_transmit(int argc, char *argv[]) |
| { |
| uint8_t transmit; |
| int err; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_net_transmit_get(net.net_idx, |
| net.dst, &transmit); |
| } else { |
| if (argc != 3) { |
| printk("Wrong number of input arguments" |
| "(2 arguments are required)"); |
| return -EINVAL; |
| } |
| |
| uint8_t count, interval, new_transmit; |
| |
| count = strtoul(argv[1], NULL, 0); |
| interval = strtoul(argv[2], NULL, 0); |
| |
| new_transmit = BT_MESH_TRANSMIT(count, interval); |
| |
| err = bt_mesh_cfg_net_transmit_set(net.net_idx, net.dst, |
| new_transmit, &transmit); |
| } |
| |
| if (err) { |
| printk("Unable to send network transmit" |
| " Get/Set (err %d)", err); |
| return 0; |
| } |
| |
| printk("Transmit 0x%02x (count %u interval %ums)", |
| transmit, BT_MESH_TRANSMIT_COUNT(transmit), |
| BT_MESH_TRANSMIT_INT(transmit)); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_net_transmit_help = { |
| NULL, "[<count: 0-7> <interval: 10-320>]", NULL |
| }; |
| |
| static int cmd_relay(int argc, char *argv[]) |
| { |
| uint8_t relay, transmit; |
| int err; |
| |
| if (argc < 2) { |
| err = bt_mesh_cfg_relay_get(net.net_idx, net.dst, &relay, |
| &transmit); |
| } else { |
| uint8_t val = str2u8(argv[1]); |
| uint8_t count, interval, new_transmit; |
| |
| if (val) { |
| if (argc > 2) { |
| count = strtoul(argv[2], NULL, 0); |
| } else { |
| count = 2; |
| } |
| |
| if (argc > 3) { |
| interval = strtoul(argv[3], NULL, 0); |
| } else { |
| interval = 20; |
| } |
| |
| new_transmit = BT_MESH_TRANSMIT(count, interval); |
| } else { |
| new_transmit = 0; |
| } |
| |
| err = bt_mesh_cfg_relay_set(net.net_idx, net.dst, val, |
| new_transmit, &relay, &transmit); |
| } |
| |
| if (err) { |
| printk("Unable to send Relay Get/Set (err %d)\n", err); |
| return 0; |
| } |
| |
| printk("Relay is 0x%02x, Transmit 0x%02x (count %u interval %ums)\n", |
| relay, transmit, BT_MESH_TRANSMIT_COUNT(transmit), |
| BT_MESH_TRANSMIT_INT(transmit)); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_relay_help = { |
| NULL, "[val: off, on] [count: 0-7] [interval: 0-32]", NULL |
| }; |
| |
| static int cmd_net_key_add(int argc, char *argv[]) |
| { |
| bool has_key_val = (argc > 2); |
| uint8_t key_val[16]; |
| uint16_t key_net_idx; |
| uint8_t status; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| key_net_idx = strtoul(argv[1], NULL, 0); |
| |
| if (has_key_val) { |
| size_t len; |
| |
| len = hex2bin(argv[3], key_val, sizeof(key_val)); |
| 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) { |
| printk("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) { |
| printk("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) { |
| printk("Unable to send NetKey Add (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("NetKeyAdd failed with status 0x%02x\n", status); |
| } else { |
| printk("NetKey added with NetKey Index 0x%03x\n", key_net_idx); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_net_key_add_help = { |
| NULL, "<NetKeyIndex> [val]", NULL |
| }; |
| |
| static int cmd_net_key_get(int 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) { |
| printk("Unable to send NetKeyGet (err %d)", err); |
| return 0; |
| } |
| |
| printk("NetKeys known by 0x%04x:", net.dst); |
| for (i = 0; i < cnt; i++) { |
| printk("\t0x%03x", keys[i]); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_net_key_get_help = { |
| NULL, NULL, NULL |
| }; |
| |
| static int cmd_net_key_del(int argc, char *argv[]) |
| { |
| uint16_t key_net_idx; |
| uint8_t status; |
| int err; |
| |
| key_net_idx = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_cfg_net_key_del(net.net_idx, net.dst, key_net_idx, |
| &status); |
| if (err) { |
| printk("Unable to send NetKeyDel (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("NetKeyDel failed with status 0x%02x", |
| status); |
| } else { |
| printk("NetKey 0x%03x deleted", key_net_idx); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_net_key_del_help = { |
| NULL, "<NetKeyIndex>", NULL |
| }; |
| |
| static int cmd_app_key_add(int 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; |
| |
| if (argc < 3) { |
| return -EINVAL; |
| } |
| |
| key_net_idx = strtoul(argv[1], NULL, 0); |
| key_app_idx = strtoul(argv[2], NULL, 0); |
| |
| if (has_key_val) { |
| size_t len; |
| |
| len = hex2bin(argv[3], key_val, sizeof(key_val)); |
| 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) { |
| printk("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) { |
| printk("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) { |
| printk("Unable to send App Key Add (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("AppKeyAdd failed with status 0x%02x\n", status); |
| } else { |
| printk("AppKey added, NetKeyIndex 0x%04x AppKeyIndex 0x%04x\n", |
| key_net_idx, key_app_idx); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_app_key_add_help = { |
| NULL, "<NetKeyIndex> <AppKeyIndex> [val]", NULL |
| }; |
| |
| static int cmd_app_key_get(int argc, char *argv[]) |
| { |
| uint16_t net_idx; |
| uint16_t keys[16]; |
| size_t cnt; |
| uint8_t status; |
| int err, i; |
| |
| net_idx = strtoul(argv[1], NULL, 0); |
| cnt = ARRAY_SIZE(keys); |
| |
| err = bt_mesh_cfg_app_key_get(net.net_idx, net.dst, net_idx, &status, |
| keys, &cnt); |
| if (err) { |
| printk("Unable to send AppKeyGet (err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("AppKeyGet failed with status 0x%02x", |
| status); |
| return 0; |
| } |
| |
| printk( |
| "AppKeys for NetKey 0x%03x known by 0x%04x:", net_idx, |
| net.dst); |
| for (i = 0; i < cnt; i++) { |
| printk("\t0x%03x", keys[i]); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_app_key_get_help = { |
| NULL, "<NetKeyIndex>", NULL |
| }; |
| |
| static int cmd_app_key_del(int argc, char *argv[]) |
| { |
| uint16_t key_net_idx, key_app_idx; |
| uint8_t status; |
| int err; |
| |
| if (argc < 3) { |
| return -EINVAL; |
| } |
| |
| key_net_idx = strtoul(argv[1], NULL, 0); |
| key_app_idx = strtoul(argv[2], NULL, 0); |
| |
| err = bt_mesh_cfg_app_key_del(net.net_idx, net.dst, key_net_idx, |
| key_app_idx, &status); |
| if (err) { |
| printk("Unable to send App Key del(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("AppKeyDel failed with status 0x%02x", |
| status); |
| } else { |
| printk("AppKey deleted, NetKeyIndex 0x%04x " |
| "AppKeyIndex 0x%04x", key_net_idx, key_app_idx); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_app_key_del_help = { |
| NULL, "<NetKeyIndex> <AppKeyIndex>", NULL |
| }; |
| |
| static int cmd_mod_app_bind(int argc, char *argv[]) |
| { |
| uint16_t elem_addr, mod_app_idx, mod_id, cid; |
| uint8_t status; |
| int err; |
| |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| mod_app_idx = strtoul(argv[2], NULL, 0); |
| mod_id = strtoul(argv[3], NULL, 0); |
| |
| if (argc > 4) { |
| cid = strtoul(argv[4], NULL, 0); |
| 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) { |
| printk("Unable to send Model App Bind (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model App Bind failed with status 0x%02x\n", status); |
| } else { |
| printk("AppKey successfully bound\n"); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_app_bind_help = { |
| NULL, "<addr> <AppIndex> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_app_unbind(int argc, char *argv[]) |
| { |
| uint16_t elem_addr, mod_app_idx, mod_id, cid; |
| uint8_t status; |
| int err; |
| |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| mod_app_idx = strtoul(argv[2], NULL, 0); |
| mod_id = strtoul(argv[3], NULL, 0); |
| |
| if (argc > 4) { |
| cid = strtoul(argv[4], NULL, 0); |
| 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) { |
| printk("Unable to send Model App Unbind (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model App Unbind failed with status 0x%02x", |
| status); |
| } else { |
| printk("AppKey successfully unbound"); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_app_unbind_help = { |
| NULL, "<addr> <AppIndex> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_app_get(int argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, mod_id, cid; |
| uint16_t apps[16]; |
| uint8_t status; |
| size_t cnt; |
| int err, i; |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| mod_id = strtoul(argv[2], NULL, 0); |
| cnt = ARRAY_SIZE(apps); |
| |
| if (argc > 3) { |
| cid = strtoul(argv[3], NULL, 0); |
| 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) { |
| printk("Unable to send Model App Get (err %d)", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model App Get failed with status 0x%02x", |
| status); |
| } else { |
| printk( |
| "Apps bound to Element 0x%04x, Model 0x%04x %s:", |
| elem_addr, mod_id, argc > 3 ? argv[3] : "(SIG)"); |
| |
| if (!cnt) { |
| printk("\tNone."); |
| } |
| |
| for (i = 0; i < cnt; i++) { |
| printk("\t0x%04x", apps[i]); |
| } |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_app_get_help = { |
| NULL, "<elem addr> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_sub_add(int argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t status; |
| int err; |
| |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| sub_addr = strtoul(argv[2], NULL, 0); |
| mod_id = strtoul(argv[3], NULL, 0); |
| |
| if (argc > 4) { |
| cid = strtoul(argv[4], NULL, 0); |
| 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) { |
| printk("Unable to send Model Subscription Add (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model Subscription Add failed with status 0x%02x\n", |
| status); |
| } else { |
| printk("Model subscription was successful\n"); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_sub_add_help = { |
| NULL, "<elem addr> <sub addr> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_sub_del(int argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t status; |
| int err; |
| |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| sub_addr = strtoul(argv[2], NULL, 0); |
| mod_id = strtoul(argv[3], NULL, 0); |
| |
| if (argc > 4) { |
| cid = strtoul(argv[4], NULL, 0); |
| 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) { |
| printk("Unable to send Model Subscription Delete (err %d)\n", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model Subscription Delete failed with status 0x%02x\n", |
| status); |
| } else { |
| printk("Model subscription deltion was successful\n"); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_sub_del_help = { |
| NULL, "<elem addr> <sub addr> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_sub_add_va(int argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t label[16]; |
| uint8_t status; |
| size_t len; |
| int err; |
| |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| |
| len = hex2bin(argv[2], label, sizeof(label)); |
| memset(label + len, 0, sizeof(label) - len); |
| |
| mod_id = strtoul(argv[3], NULL, 0); |
| |
| if (argc > 4) { |
| cid = strtoul(argv[4], NULL, 0); |
| 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) { |
| printk("Unable to send Mod Sub VA Add (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Mod Sub VA Add failed with status 0x%02x\n", |
| status); |
| } else { |
| printk("0x%04x subscribed to Label UUID %s (va 0x%04x)\n", |
| elem_addr, argv[2], sub_addr); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_sub_add_va_help = { |
| NULL, "<elem addr> <Label UUID> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_sub_del_va(int argc, char *argv[]) |
| { |
| uint16_t elem_addr, sub_addr, mod_id, cid; |
| uint8_t label[16]; |
| uint8_t status; |
| size_t len; |
| int err; |
| |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| |
| len = hex2bin(argv[2], label, sizeof(label)); |
| memset(label + len, 0, sizeof(label) - len); |
| |
| mod_id = strtoul(argv[3], NULL, 0); |
| |
| if (argc > 4) { |
| cid = strtoul(argv[4], NULL, 0); |
| 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) { |
| printk("Unable to send Model Subscription Delete (err %d)\n", |
| err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model Subscription Delete failed with status 0x%02x\n", |
| status); |
| } else { |
| printk("0x%04x unsubscribed from Label UUID %s (va 0x%04x)\n", |
| elem_addr, argv[2], sub_addr); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_sub_del_va_help = { |
| NULL, "<elem addr> <Label UUID> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int cmd_mod_sub_get(int argc, |
| char *argv[]) |
| { |
| uint16_t elem_addr, mod_id, cid; |
| uint16_t subs[16]; |
| uint8_t status; |
| size_t cnt; |
| int err, i; |
| |
| elem_addr = strtoul(argv[1], NULL, 0); |
| mod_id = strtoul(argv[2], NULL, 0); |
| cnt = ARRAY_SIZE(subs); |
| |
| if (argc > 3) { |
| cid = strtoul(argv[3], NULL, 0); |
| 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) { |
| printk("Unable to send Model Subscription Get " |
| "(err %d)", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model Subscription Get failed with " |
| "status 0x%02x", status); |
| } else { |
| printk( |
| "Model Subscriptions for Element 0x%04x, " |
| "Model 0x%04x %s:", |
| elem_addr, mod_id, argc > 3 ? argv[3] : "(SIG)"); |
| |
| if (!cnt) { |
| printk("\tNone."); |
| } |
| |
| for (i = 0; i < cnt; i++) { |
| printk("\t0x%04x", subs[i]); |
| } |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_mod_sub_get_help = { |
| NULL, "<elem addr> <Model ID> [Company ID]", NULL |
| }; |
| |
| static int mod_pub_get(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) { |
| printk("Model Publication Get failed (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model Publication Get failed (status 0x%02x)\n", |
| status); |
| return 0; |
| } |
| |
| printk("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\n", |
| 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(uint16_t addr, uint16_t mod_id, uint16_t cid, char *argv[]) |
| { |
| struct bt_mesh_cfg_mod_pub pub; |
| uint8_t status, count; |
| uint16_t interval; |
| int err; |
| |
| pub.addr = strtoul(argv[0], NULL, 0); |
| pub.app_idx = strtoul(argv[1], NULL, 0); |
| pub.cred_flag = str2bool(argv[2]); |
| pub.ttl = strtoul(argv[3], NULL, 0); |
| pub.period = strtoul(argv[4], NULL, 0); |
| |
| count = strtoul(argv[5], NULL, 0); |
| if (count > 7) { |
| printk("Invalid retransmit count\n"); |
| return -EINVAL; |
| } |
| |
| interval = strtoul(argv[6], NULL, 0); |
| if (interval > (31 * 50) || (interval % 50)) { |
| printk("Invalid retransmit interval %u\n", 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) { |
| printk("Model Publication Set failed (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Model Publication Set failed (status 0x%02x)\n", |
| status); |
| } else { |
| printk("Model Publication successfully set\n"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_mod_pub(int argc, char *argv[]) |
| { |
| uint16_t addr, mod_id, cid; |
| |
| if (argc < 3) { |
| return -EINVAL; |
| } |
| |
| addr = strtoul(argv[1], NULL, 0); |
| mod_id = strtoul(argv[2], NULL, 0); |
| |
| argc -= 3; |
| argv += 3; |
| |
| if (argc == 1 || argc == 8) { |
| cid = strtoul(argv[0], NULL, 0); |
| argc--; |
| argv++; |
| } else { |
| cid = CID_NVAL; |
| } |
| |
| if (argc > 0) { |
| if (argc < 7) { |
| return -EINVAL; |
| } |
| |
| return mod_pub_set(addr, mod_id, cid, argv); |
| } else { |
| return mod_pub_get(addr, mod_id, cid); |
| } |
| } |
| |
| struct shell_cmd_help cmd_mod_pub_help = { |
| NULL, "<addr> <mod id> [cid] [<PubAddr> " |
| "<AppKeyIndex> <cred> <ttl> <period> <count> <interval>]" , NULL |
| }; |
| |
| static void hb_sub_print(struct bt_mesh_cfg_hb_sub *sub) |
| { |
| printk("Heartbeat Subscription:\n" |
| "\tSource: 0x%04x\n" |
| "\tDestination: 0x%04x\n" |
| "\tPeriodLog: 0x%02x\n" |
| "\tCountLog: 0x%02x\n" |
| "\tMinHops: %u\n" |
| "\tMaxHops: %u\n", |
| sub->src, sub->dst, sub->period, sub->count, |
| sub->min, sub->max); |
| } |
| |
| static int hb_sub_get(int 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) { |
| printk("Heartbeat Subscription Get failed (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Heartbeat Subscription Get failed (status 0x%02x)\n", |
| status); |
| } else { |
| hb_sub_print(&sub); |
| } |
| |
| return 0; |
| } |
| |
| static int hb_sub_set(int argc, char *argv[]) |
| { |
| struct bt_mesh_cfg_hb_sub sub; |
| uint8_t status; |
| int err; |
| |
| sub.src = strtoul(argv[1], NULL, 0); |
| sub.dst = strtoul(argv[2], NULL, 0); |
| sub.period = strtoul(argv[3], NULL, 0); |
| |
| err = bt_mesh_cfg_hb_sub_set(net.net_idx, net.dst, &sub, &status); |
| if (err) { |
| printk("Heartbeat Subscription Set failed (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Heartbeat Subscription Set failed (status 0x%02x)\n", |
| status); |
| } else { |
| hb_sub_print(&sub); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_hb_sub(int argc, char *argv[]) |
| { |
| if (argc > 1) { |
| if (argc < 4) { |
| return -EINVAL; |
| } |
| |
| return hb_sub_set(argc, argv); |
| } else { |
| return hb_sub_get(argc, argv); |
| } |
| } |
| |
| struct shell_cmd_help cmd_hb_sub_help = { |
| NULL, "<src> <dst> <period>", NULL |
| }; |
| |
| static int hb_pub_get(int 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) { |
| printk("Heartbeat Publication Get failed (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Heartbeat Publication Get failed (status 0x%02x)\n", |
| status); |
| return 0; |
| } |
| |
| printk("Heartbeat publication:\n"); |
| printk("\tdst 0x%04x count 0x%02x period 0x%02x\n", |
| pub.dst, pub.count, pub.period); |
| printk("\tttl 0x%02x feat 0x%04x net_idx 0x%04x\n", |
| pub.ttl, pub.feat, pub.net_idx); |
| |
| return 0; |
| } |
| |
| static int hb_pub_set(int argc, char *argv[]) |
| { |
| struct bt_mesh_cfg_hb_pub pub; |
| uint8_t status; |
| int err; |
| |
| pub.dst = strtoul(argv[1], NULL, 0); |
| pub.count = strtoul(argv[2], NULL, 0); |
| pub.period = strtoul(argv[3], NULL, 0); |
| pub.ttl = strtoul(argv[4], NULL, 0); |
| pub.feat = strtoul(argv[5], NULL, 0); |
| pub.net_idx = strtoul(argv[5], NULL, 0); |
| |
| err = bt_mesh_cfg_hb_pub_set(net.net_idx, net.dst, &pub, &status); |
| if (err) { |
| printk("Heartbeat Publication Set failed (err %d)\n", err); |
| return 0; |
| } |
| |
| if (status) { |
| printk("Heartbeat Publication Set failed (status 0x%02x)\n", |
| status); |
| } else { |
| printk("Heartbeat publication successfully set\n"); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_hb_pub(int argc, char *argv[]) |
| { |
| if (argc > 1) { |
| if (argc < 7) { |
| return -EINVAL; |
| } |
| |
| return hb_pub_set(argc, argv); |
| } else { |
| return hb_pub_get(argc, argv); |
| } |
| } |
| |
| struct shell_cmd_help cmd_hb_pub_help = { |
| NULL, "<dst> <count> <period> <ttl> <features> <NetKeyIndex>" , NULL |
| }; |
| |
| #endif /* MYNEWT_VAL(BLE_MESH_CFG_CLI) */ |
| |
| #if MYNEWT_VAL(BLE_MESH_PROV_DEVICE) |
| static int cmd_pb(bt_mesh_prov_bearer_t bearer, int argc, char *argv[]) |
| { |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| if (str2bool(argv[1])) { |
| err = bt_mesh_prov_enable(bearer); |
| if (err) { |
| printk("Failed to enable %s (err %d)\n", |
| bearer2str(bearer), err); |
| } else { |
| printk("%s enabled\n", bearer2str(bearer)); |
| } |
| } else { |
| err = bt_mesh_prov_disable(bearer); |
| if (err) { |
| printk("Failed to disable %s (err %d)\n", |
| bearer2str(bearer), err); |
| } else { |
| printk("%s disabled\n", bearer2str(bearer)); |
| } |
| } |
| |
| return 0; |
| |
| } |
| |
| struct shell_cmd_help cmd_pb_help = { |
| NULL, "<val: off, on>", NULL |
| }; |
| |
| #endif |
| |
| #if MYNEWT_VAL(BLE_MESH_PB_ADV) |
| static int cmd_pb_adv(int argc, char *argv[]) |
| { |
| return cmd_pb(BT_MESH_PROV_ADV, argc, argv); |
| } |
| |
| #if MYNEWT_VAL(BLE_MESH_PROVISIONER) |
| static int cmd_provision_adv(int argc, char *argv[]) |
| { |
| uint8_t uuid[16]; |
| uint8_t attention_duration; |
| uint16_t net_idx; |
| uint16_t addr; |
| size_t len; |
| int err; |
| |
| len = hex2bin(argv[1], uuid, sizeof(uuid)); |
| (void)memset(uuid + len, 0, sizeof(uuid) - len); |
| |
| net_idx = strtoul(argv[2], NULL, 0); |
| addr = strtoul(argv[3], NULL, 0); |
| attention_duration = strtoul(argv[4], NULL, 0); |
| |
| err = bt_mesh_provision_adv(uuid, net_idx, addr, attention_duration); |
| if (err) { |
| printk("Provisioning failed (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_provision_adv_help = { |
| NULL, "<UUID> <NetKeyIndex> <addr> <AttentionDuration>" , NULL |
| }; |
| #endif /* CONFIG_BT_MESH_PROVISIONER */ |
| |
| #endif /* CONFIG_BT_MESH_PB_ADV */ |
| |
| #if MYNEWT_VAL(BLE_MESH_PB_GATT) |
| static int cmd_pb_gatt(int argc, char *argv[]) |
| { |
| return cmd_pb(BT_MESH_PROV_GATT, argc, argv); |
| } |
| #endif /* CONFIG_BT_MESH_PB_GATT */ |
| |
| static int cmd_provision(int argc, char *argv[]) |
| { |
| const uint8_t *net_key = default_key; |
| uint16_t net_idx, addr; |
| uint32_t iv_index; |
| int err; |
| |
| if (argc < 3) { |
| return -EINVAL; |
| } |
| |
| net_idx = strtoul(argv[1], NULL, 0); |
| addr = strtoul(argv[2], NULL, 0); |
| |
| if (argc > 3) { |
| iv_index = strtoul(argv[3], NULL, 0); |
| } else { |
| iv_index = 0; |
| } |
| |
| if (IS_ENABLED(CONFIG_BT_MESH_CDB)) { |
| const struct bt_mesh_cdb_subnet *sub; |
| |
| sub = bt_mesh_cdb_subnet_get(net_idx); |
| if (!sub) { |
| printk("No cdb entry for subnet 0x%03x", net_idx); |
| return 0; |
| } |
| |
| net_key = sub->keys[sub->kr_flag].net_key; |
| } |
| |
| err = bt_mesh_provision(net_key, net_idx, 0, iv_index, addr, |
| default_key); |
| if (err) { |
| printk("Provisioning failed (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_provision_help = { |
| NULL, "<NetKeyIndex> <addr> [IVIndex]" , NULL |
| }; |
| |
| #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) |
| |
| static int cmd_fault_get(int argc, char *argv[]) |
| { |
| uint8_t faults[32]; |
| size_t fault_count; |
| uint8_t test_id; |
| uint16_t cid; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| cid = strtoul(argv[1], NULL, 0); |
| fault_count = sizeof(faults); |
| |
| err = bt_mesh_health_fault_get(net.dst, net.app_idx, cid, &test_id, |
| faults, &fault_count); |
| if (err) { |
| printk("Failed to send Health Fault Get (err %d)\n", err); |
| } else { |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_fault_get_help = { |
| NULL, "<Company ID>", NULL |
| }; |
| |
| static int cmd_fault_clear(int argc, char *argv[]) |
| { |
| uint8_t faults[32]; |
| size_t fault_count; |
| uint8_t test_id; |
| uint16_t cid; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| cid = strtoul(argv[1], NULL, 0); |
| fault_count = sizeof(faults); |
| |
| err = bt_mesh_health_fault_clear(net.dst, net.app_idx, cid, |
| &test_id, faults, &fault_count); |
| if (err) { |
| printk("Failed to send Health Fault Clear (err %d)\n", err); |
| } else { |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_fault_clear_help = { |
| NULL, "<Company ID>", NULL |
| }; |
| |
| static int cmd_fault_clear_unack(int argc, char *argv[]) |
| { |
| uint16_t cid; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| cid = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_health_fault_clear(net.dst, net.app_idx, cid, |
| NULL, NULL, NULL); |
| if (err) { |
| printk("Health Fault Clear Unacknowledged failed (err %d)\n", |
| err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_fault_clear_unack_help = { |
| NULL, "<Company ID>", NULL |
| }; |
| |
| static int cmd_fault_test(int argc, char *argv[]) |
| { |
| uint8_t faults[32]; |
| size_t fault_count; |
| uint8_t test_id; |
| uint16_t cid; |
| int err; |
| |
| if (argc < 3) { |
| return -EINVAL; |
| } |
| |
| cid = strtoul(argv[1], NULL, 0); |
| test_id = strtoul(argv[2], NULL, 0); |
| fault_count = sizeof(faults); |
| |
| err = bt_mesh_health_fault_test(net.dst, net.app_idx, cid, |
| test_id, faults, &fault_count); |
| if (err) { |
| printk("Failed to send Health Fault Test (err %d)\n", err); |
| } else { |
| show_faults(test_id, cid, faults, fault_count); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_fault_test_help = { |
| NULL, "<Company ID> <Test ID>", NULL |
| }; |
| |
| static int cmd_fault_test_unack(int argc, char *argv[]) |
| { |
| uint16_t cid; |
| uint8_t test_id; |
| int err; |
| |
| if (argc < 3) { |
| return -EINVAL; |
| } |
| |
| cid = strtoul(argv[1], NULL, 0); |
| test_id = strtoul(argv[2], NULL, 0); |
| |
| err = bt_mesh_health_fault_test(net.dst, net.app_idx, cid, |
| test_id, NULL, NULL); |
| if (err) { |
| printk("Health Fault Test Unacknowledged failed (err %d)\n", |
| err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_fault_test_unack_help = { |
| NULL, "<Company ID> <Test ID>", NULL |
| }; |
| |
| static int cmd_period_get(int argc, char *argv[]) |
| { |
| uint8_t divisor; |
| int err; |
| |
| err = bt_mesh_health_period_get(net.dst, net.app_idx, &divisor); |
| if (err) { |
| printk("Failed to send Health Period Get (err %d)\n", err); |
| } else { |
| printk("Health FastPeriodDivisor: %u\n", divisor); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_period_set(int argc, char *argv[]) |
| { |
| uint8_t divisor, updated_divisor; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| divisor = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_health_period_set(net.dst, net.app_idx, divisor, |
| &updated_divisor); |
| if (err) { |
| printk("Failed to send Health Period Set (err %d)\n", err); |
| } else { |
| printk("Health FastPeriodDivisor: %u\n", updated_divisor); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_period_set_help = { |
| NULL, "<divisor>", NULL |
| }; |
| |
| static int cmd_period_set_unack(int argc, char *argv[]) |
| { |
| uint8_t divisor; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| divisor = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_health_period_set(net.dst, net.app_idx, divisor, NULL); |
| if (err) { |
| printk("Failed to send Health Period Set (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_period_set_unack_help = { |
| NULL, "<divisor>", NULL |
| }; |
| |
| static int cmd_attention_get(int argc, char *argv[]) |
| { |
| uint8_t attention; |
| int err; |
| |
| err = bt_mesh_health_attention_get(net.dst, net.app_idx, |
| &attention); |
| if (err) { |
| printk("Failed to send Health Attention Get (err %d)\n", err); |
| } else { |
| printk("Health Attention Timer: %u\n", attention); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_attention_set(int argc, char *argv[]) |
| { |
| uint8_t attention, updated_attention; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| attention = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_health_attention_set(net.dst, net.app_idx, attention, |
| &updated_attention); |
| if (err) { |
| printk("Failed to send Health Attention Set (err %d)\n", err); |
| } else { |
| printk("Health Attention Timer: %u\n", updated_attention); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_attention_set_help = { |
| NULL, "<timer>", NULL |
| }; |
| |
| static int cmd_attention_set_unack(int argc, char *argv[]) |
| { |
| uint8_t attention; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| attention = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_health_attention_set(net.dst, net.app_idx, attention, |
| NULL); |
| if (err) { |
| printk("Failed to send Health Attention Set (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_attention_set_unack_help = { |
| NULL, "<timer>", NULL |
| }; |
| |
| #endif /* MYNEWT_VAL(BLE_MESH_HEALTH_CLI) */ |
| |
| static int cmd_add_fault(int argc, char *argv[]) |
| { |
| uint8_t fault_id; |
| uint8_t i; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| fault_id = strtoul(argv[1], NULL, 0); |
| if (!fault_id) { |
| printk("The Fault ID must be non-zero!\n"); |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < sizeof(cur_faults); i++) { |
| if (!cur_faults[i]) { |
| cur_faults[i] = fault_id; |
| break; |
| } |
| } |
| |
| if (i == sizeof(cur_faults)) { |
| printk("Fault array is full. Use \"del-fault\" to clear it\n"); |
| return 0; |
| } |
| |
| for (i = 0; i < sizeof(reg_faults); i++) { |
| if (!reg_faults[i]) { |
| reg_faults[i] = fault_id; |
| break; |
| } |
| } |
| |
| if (i == sizeof(reg_faults)) { |
| printk("No space to store more registered faults\n"); |
| } |
| |
| bt_mesh_fault_update(&elements[0]); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_add_fault_help = { |
| NULL, "<Fault ID>", NULL |
| }; |
| |
| static int cmd_del_fault(int argc, char *argv[]) |
| { |
| uint8_t fault_id; |
| uint8_t i; |
| |
| if (argc < 2) { |
| memset(cur_faults, 0, sizeof(cur_faults)); |
| printk("All current faults cleared\n"); |
| bt_mesh_fault_update(&elements[0]); |
| return 0; |
| } |
| |
| fault_id = strtoul(argv[1], NULL, 0); |
| if (!fault_id) { |
| printk("The Fault ID must be non-zero!\n"); |
| return -EINVAL; |
| } |
| |
| for (i = 0; i < sizeof(cur_faults); i++) { |
| if (cur_faults[i] == fault_id) { |
| cur_faults[i] = 0; |
| printk("Fault cleared\n"); |
| } |
| } |
| |
| bt_mesh_fault_update(&elements[0]); |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_del_fault_help = { |
| NULL, "[Fault ID]", NULL |
| }; |
| |
| #if defined(CONFIG_BT_MESH_CDB) |
| struct shell_cmd_help cmd_cdb_create_help = { |
| NULL, "[NetKey]", NULL |
| }; |
| struct shell_cmd_help cmd_cdb_clear_help = { |
| NULL, NULL, NULL |
| }; |
| struct shell_cmd_help cmd_cdb_show_help = { |
| NULL, NULL, NULL |
| }; |
| struct shell_cmd_help cmd_cdb_node_add_help = { |
| NULL, "<UUID> <addr> <num-elem> " |
| "<NetKeyIdx> [DevKey]", NULL |
| }; |
| struct shell_cmd_help cmd_cdb_node_del_help = { |
| NULL, "<addr>", NULL |
| }; |
| struct shell_cmd_help cmd_cdb_subnet_add_help = { |
| NULL, "<NeyKeyIdx> [<NetKey>]", NULL |
| }; |
| struct shell_cmd_help cmd_cdb_subnet_del_help = { |
| NULL, "<NetKeyIdx>", NULL |
| }; |
| struct shell_cmd_help cmd_cdb_app_key_add_help = { |
| NULL, "<NetKeyIdx> <AppKeyIdx> [<AppKey>]", NULL |
| }; |
| struct shell_cmd_help cmd_cdb_app_key_del_help = { |
| NULL, "<AppKeyIdx>", NULL |
| }; |
| |
| static int cmd_cdb_create(int 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], net_key, sizeof(net_key)); |
| memset(net_key + len, 0, sizeof(net_key) - len); |
| } |
| |
| err = bt_mesh_cdb_create(net_key); |
| if (err < 0) { |
| printk("Failed to create CDB (err %d)", err); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_clear(int argc, char *argv[]) |
| { |
| bt_mesh_cdb_clear(); |
| |
| printk("Cleared CDB"); |
| |
| return 0; |
| } |
| |
| static void cdb_print_nodes(void) |
| { |
| char key_hex_str[32 + 1], uuid_hex_str[32 + 1]; |
| struct bt_mesh_cdb_node *node; |
| int i, total = 0; |
| bool configured; |
| |
| printk("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)); |
| printk("0x%04x %-8d %-5s %s %s", node->addr, |
| node->num_elem, configured ? "C" : "-", |
| uuid_hex_str, key_hex_str); |
| } |
| |
| printk("> Total nodes: %d", total); |
| } |
| |
| static void cdb_print_subnets(void) |
| { |
| struct bt_mesh_cdb_subnet *subnet; |
| char key_hex_str[32 + 1]; |
| int i, total = 0; |
| |
| printk("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)); |
| printk("0x%03x %s", subnet->net_idx, |
| key_hex_str); |
| } |
| |
| printk("> Total subnets: %d", total); |
| } |
| |
| static void cdb_print_app_keys(void) |
| { |
| struct bt_mesh_cdb_app_key *app_key; |
| char key_hex_str[32 + 1]; |
| int i, total = 0; |
| |
| printk("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)); |
| printk("0x%03x 0x%03x %s", |
| app_key->net_idx, app_key->app_idx, key_hex_str); |
| } |
| |
| printk("> Total app-keys: %d", total); |
| } |
| |
| static int cmd_cdb_show(int argc, char *argv[]) |
| { |
| if (!atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID)) { |
| printk("No valid networks"); |
| return 0; |
| } |
| |
| printk("Mesh Network Information"); |
| printk("========================"); |
| |
| cdb_print_nodes(); |
| printk("---"); |
| cdb_print_subnets(); |
| printk("---"); |
| cdb_print_app_keys(); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_node_add(int 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; |
| |
| len = hex2bin(argv[1], uuid, sizeof(uuid)); |
| memset(uuid + len, 0, sizeof(uuid) - len); |
| |
| addr = strtoul(argv[2], NULL, 0); |
| num_elem = strtoul(argv[3], NULL, 0); |
| net_idx = strtoul(argv[4], NULL, 0); |
| |
| if (argc < 6) { |
| bt_rand(dev_key, 16); |
| } else { |
| len = hex2bin(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) { |
| printk("Failed to allocate node"); |
| return 0; |
| } |
| |
| memcpy(node->dev_key, dev_key, 16); |
| |
| if (IS_ENABLED(CONFIG_SETTINGS)) { |
| bt_mesh_store_cdb_node(node); |
| } |
| |
| printk("Added node 0x%04x", addr); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_node_del(int argc, char *argv[]) |
| { |
| struct bt_mesh_cdb_node *node; |
| uint16_t addr; |
| |
| addr = strtoul(argv[1], NULL, 0); |
| |
| node = bt_mesh_cdb_node_get(addr); |
| if (node == NULL) { |
| printk("No node with address 0x%04x", addr); |
| return 0; |
| } |
| |
| bt_mesh_cdb_node_del(node, true); |
| |
| printk("Deleted node 0x%04x", addr); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_subnet_add(int argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_subnet *sub; |
| uint8_t net_key[16]; |
| uint16_t net_idx; |
| size_t len; |
| |
| net_idx = strtoul(argv[1], NULL, 0); |
| |
| if (argc < 3) { |
| bt_rand(net_key, 16); |
| } else { |
| len = hex2bin(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) { |
| printk("Could not add subnet"); |
| return 0; |
| } |
| |
| memcpy(sub->keys[0].net_key, net_key, 16); |
| |
| if (IS_ENABLED(CONFIG_SETTINGS)) { |
| bt_mesh_store_cdb_subnet(sub); |
| } |
| |
| printk("Added Subnet 0x%03x", net_idx); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_subnet_del(int argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_subnet *sub; |
| uint16_t net_idx; |
| |
| net_idx = strtoul(argv[1], NULL, 0); |
| |
| sub = bt_mesh_cdb_subnet_get(net_idx); |
| if (sub == NULL) { |
| printk("No subnet with NetIdx 0x%03x", net_idx); |
| return 0; |
| } |
| |
| bt_mesh_cdb_subnet_del(sub, true); |
| |
| printk("Deleted subnet 0x%03x", net_idx); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_app_key_add(int argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_app_key *key; |
| uint16_t net_idx, app_idx; |
| uint8_t app_key[16]; |
| size_t len; |
| |
| net_idx = strtoul(argv[1], NULL, 0); |
| app_idx = strtoul(argv[2], NULL, 0); |
| |
| if (argc < 4) { |
| bt_rand(app_key, 16); |
| } else { |
| len = hex2bin(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) { |
| printk("Could not add AppKey"); |
| return 0; |
| } |
| |
| memcpy(key->keys[0].app_key, app_key, 16); |
| |
| if (IS_ENABLED(CONFIG_SETTINGS)) { |
| bt_mesh_store_cdb_app_key(key); |
| } |
| |
| printk("Added AppKey 0x%03x", app_idx); |
| |
| return 0; |
| } |
| |
| static int cmd_cdb_app_key_del(int argc, |
| char *argv[]) |
| { |
| struct bt_mesh_cdb_app_key *key; |
| uint16_t app_idx; |
| |
| app_idx = strtoul(argv[1], NULL, 0); |
| |
| key = bt_mesh_cdb_app_key_get(app_idx); |
| if (key == NULL) { |
| printk("No AppKey 0x%03x", app_idx); |
| return 0; |
| } |
| |
| bt_mesh_cdb_app_key_del(key, true); |
| |
| printk("Deleted AppKey 0x%03x", app_idx); |
| |
| return 0; |
| } |
| #endif |
| |
| #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) |
| static int cmd_gen_onoff_get(int argc, char *argv[]) |
| { |
| uint8_t state; |
| int err; |
| |
| err = bt_mesh_gen_onoff_get(net.net_idx, net.dst, net.app_idx, |
| &state); |
| if (err) { |
| printk("Failed to send Generic OnOff Get (err %d)\n", err); |
| } else { |
| printk("Gen OnOff State %d\n", state); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_gen_onoff_set(int argc, char *argv[]) |
| { |
| uint8_t state; |
| uint8_t val; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| val = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_gen_onoff_set(net.net_idx, net.dst, net.app_idx, |
| val, &state); |
| if (err) { |
| printk("Failed to send Generic OnOff Get (err %d)\n", err); |
| } else { |
| printk("Gen OnOff State %d\n", state); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_gen_onoff_set_help = { |
| NULL, "<0|1>", NULL |
| }; |
| |
| static int cmd_gen_onoff_set_unack(int argc, char *argv[]) |
| { |
| uint8_t val; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| val = strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_gen_onoff_set(net.net_idx, net.dst, net.app_idx, |
| val, NULL); |
| if (err) { |
| printk("Failed to send Generic OnOff Get (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_gen_onoff_set_unack_help = { |
| NULL, "<0|1>", NULL |
| }; |
| |
| static int cmd_gen_level_get(int argc, char *argv[]) |
| { |
| int16_t state; |
| int err; |
| |
| err = bt_mesh_gen_level_get(net.net_idx, net.dst, net.app_idx, |
| &state); |
| if (err) { |
| printk("Failed to send Generic Level Get (err %d)\n", err); |
| } else { |
| printk("Gen Level State %d\n", state); |
| } |
| |
| return 0; |
| } |
| |
| static int cmd_gen_level_set(int argc, char *argv[]) |
| { |
| int16_t state; |
| int16_t val; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| val = (int16_t)strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_gen_level_set(net.net_idx, net.dst, net.app_idx, |
| val, &state); |
| if (err) { |
| printk("Failed to send Generic Level Get (err %d)\n", err); |
| } else { |
| printk("Gen Level State %d\n", state); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_gen_level_set_help = { |
| NULL, "<level>", NULL |
| }; |
| |
| static int cmd_gen_level_set_unack(int argc, char *argv[]) |
| { |
| int16_t val; |
| int err; |
| |
| if (argc < 2) { |
| return -EINVAL; |
| } |
| |
| val = (int16_t)strtoul(argv[1], NULL, 0); |
| |
| err = bt_mesh_gen_level_set(net.net_idx, net.dst, net.app_idx, |
| val, NULL); |
| if (err) { |
| printk("Failed to send Generic Level Get (err %d)\n", err); |
| } |
| |
| return 0; |
| } |
| |
| struct shell_cmd_help cmd_gen_level_set_unack_help = { |
| NULL, "<level>", NULL |
| }; |
| |
| #endif /* MYNEWT_VAL(BLE_MESH_SHELL_MODELS) */ |
| |
| static int cmd_print_credentials(int argc, char *argv[]) |
| { |
| bt_test_print_credentials(); |
| return 0; |
| } |
| |
| static void print_comp_elem(struct bt_mesh_elem *elem, |
| bool primary) |
| { |
| struct bt_mesh_model *mod; |
| int i; |
| |
| printk("Loc: %u\n", elem->loc); |
| printk("Model count: %u\n", elem->model_count); |
| printk("Vnd model count: %u\n", elem->vnd_model_count); |
| |
| for (i = 0; i < elem->model_count; i++) { |
| mod = &elem->models[i]; |
| printk(" Model: %u\n", i); |
| printk(" ID: 0x%04x\n", mod->id); |
| printk(" Opcode: 0x%08lx\n", mod->op->opcode); |
| } |
| |
| for (i = 0; i < elem->vnd_model_count; i++) { |
| mod = &elem->vnd_models[i]; |
| printk(" Vendor model: %u\n", i); |
| printk(" Company: 0x%04x\n", mod->vnd.company); |
| printk(" ID: 0x%04x\n", mod->vnd.id); |
| printk(" Opcode: 0x%08lx\n", mod->op->opcode); |
| } |
| } |
| |
| static int cmd_print_composition_data(int argc, char *argv[]) |
| { |
| const struct bt_mesh_comp *comp; |
| int i; |
| |
| comp = bt_mesh_comp_get(); |
| |
| printk("CID: %u\n", comp->cid); |
| printk("PID: %u\n", comp->pid); |
| printk("VID: %u\n", comp->vid); |
| |
| for (i = 0; i < comp->elem_count; i++) { |
| print_comp_elem(&comp->elem[i], i == 0); |
| } |
| |
| return 0; |
| } |
| |
| |
| static const struct shell_cmd mesh_commands[] = { |
| { |
| .sc_cmd = "init", |
| .sc_cmd_func = cmd_mesh_init, |
| .help = NULL, |
| }, |
| #if MYNEWT_VAL(BLE_MESH_PB_ADV) |
| { |
| .sc_cmd = "pb-adv", |
| .sc_cmd_func = cmd_pb_adv, |
| .help = &cmd_pb_help, |
| }, |
| #if MYNEWT_VAL(BLE_MESH_PROVISIONER) |
| { |
| .sc_cmd = "provision-adv", |
| .sc_cmd_func = cmd_provision_adv, |
| .help = &cmd_provision_adv_help, |
| }, |
| #endif |
| #endif |
| #if MYNEWT_VAL(BLE_MESH_PB_GATT) |
| { |
| .sc_cmd = "pb-gatt", |
| .sc_cmd_func = cmd_pb_gatt, |
| .help = &cmd_pb_help, |
| }, |
| #endif |
| { |
| .sc_cmd = "reset", |
| .sc_cmd_func = cmd_reset, |
| .help = &cmd_reset_help, |
| }, |
| { |
| .sc_cmd = "uuid", |
| .sc_cmd_func = cmd_uuid, |
| .help = &cmd_uuid_help, |
| }, |
| { |
| .sc_cmd = "input-num", |
| .sc_cmd_func = cmd_input_num, |
| .help = &cmd_input_num_help, |
| }, |
| { |
| .sc_cmd = "input-str", |
| .sc_cmd_func = cmd_input_str, |
| .help = &cmd_input_str_help, |
| }, |
| { |
| .sc_cmd = "static-oob", |
| .sc_cmd_func = cmd_static_oob, |
| .help = &cmd_static_oob_help, |
| }, |
| { |
| .sc_cmd = "provision", |
| .sc_cmd_func = cmd_provision, |
| .help = &cmd_provision_help, |
| }, |
| #if MYNEWT_VAL(BLE_MESH_LOW_POWER) |
| { |
| .sc_cmd = "lpn", |
| .sc_cmd_func = cmd_lpn, |
| .help = &cmd_lpn_help, |
| }, |
| { |
| .sc_cmd = "poll", |
| .sc_cmd_func = cmd_poll, |
| .help = NULL, |
| }, |
| #endif |
| #if MYNEWT_VAL(BLE_MESH_GATT_PROXY) |
| { |
| .sc_cmd = "ident", |
| .sc_cmd_func = cmd_ident, |
| .help = NULL, |
| }, |
| #endif |
| { |
| .sc_cmd = "dst", |
| .sc_cmd_func = cmd_dst, |
| .help = &cmd_dst_help, |
| }, |
| { |
| .sc_cmd = "netidx", |
| .sc_cmd_func = cmd_netidx, |
| .help = &cmd_netidx_help, |
| }, |
| { |
| .sc_cmd = "appidx", |
| .sc_cmd_func = cmd_appidx, |
| .help = &cmd_appidx_help, |
| }, |
| |
| /* Commands which access internal APIs, for testing only */ |
| { |
| .sc_cmd = "net-send", |
| .sc_cmd_func = cmd_net_send, |
| .help = &cmd_net_send_help, |
| }, |
| #if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST) |
| { |
| .sc_cmd = "iv-update", |
| .sc_cmd_func = cmd_iv_update, |
| .help = NULL, |
| }, |
| { |
| .sc_cmd = "iv-update-test", |
| .sc_cmd_func = cmd_iv_update_test, |
| .help = &cmd_iv_update_test_help, |
| }, |
| #endif |
| { |
| .sc_cmd = "rpl-clear", |
| .sc_cmd_func = cmd_rpl_clear, |
| .help = NULL, |
| }, |
| #if MYNEWT_VAL(BLE_MESH_LOW_POWER) |
| { |
| .sc_cmd = "lpn-subscribe", |
| .sc_cmd_func = cmd_lpn_subscribe, |
| .help = &cmd_lpn_subscribe_help, |
| }, |
| { |
| .sc_cmd = "lpn-unsubscribe", |
| .sc_cmd_func = cmd_lpn_unsubscribe, |
| .help = &cmd_lpn_unsubscribe_help, |
| }, |
| #endif |
| { |
| .sc_cmd = "print-credentials", |
| .sc_cmd_func = cmd_print_credentials, |
| .help = NULL, |
| }, |
| { |
| .sc_cmd = "print-composition-data", |
| .sc_cmd_func = cmd_print_composition_data, |
| .help = NULL, |
| }, |
| |
| |
| #if MYNEWT_VAL(BLE_MESH_CFG_CLI) |
| /* Configuration Client Model operations */ |
| { |
| .sc_cmd = "timeout", |
| .sc_cmd_func = cmd_timeout, |
| .help = &cmd_timeout_help, |
| }, |
| { |
| .sc_cmd = "get-comp", |
| .sc_cmd_func = cmd_get_comp, |
| .help = &cmd_get_comp_help, |
| }, |
| { |
| .sc_cmd = "beacon", |
| .sc_cmd_func = cmd_beacon, |
| .help = &cmd_beacon_help, |
| }, |
| { |
| .sc_cmd = "beacon-listen", |
| .sc_cmd_func = cmd_beacon_listen, |
| .help = &cmd_beacon_listen_help, |
| }, |
| { |
| .sc_cmd = "ttl", |
| .sc_cmd_func = cmd_ttl, |
| .help = &cmd_ttl_help, |
| }, |
| { |
| .sc_cmd = "friend", |
| .sc_cmd_func = cmd_friend, |
| .help = &cmd_friend_help, |
| }, |
| { |
| .sc_cmd = "gatt-proxy", |
| .sc_cmd_func = cmd_gatt_proxy, |
| .help = &cmd_gatt_proxy_help, |
| }, |
| { |
| .sc_cmd = "relay", |
| .sc_cmd_func = cmd_relay, |
| .help = &cmd_relay_help, |
| }, |
| { |
| .sc_cmd = "net-key-add", |
| .sc_cmd_func = cmd_net_key_add, |
| .help = &cmd_net_key_add_help, |
| }, |
| { |
| .sc_cmd = "net-key-get", |
| .sc_cmd_func = cmd_net_key_get, |
| .help = &cmd_net_key_get_help, |
| }, |
| { |
| .sc_cmd = "net-key-del", |
| .sc_cmd_func = cmd_net_key_del, |
| .help = &cmd_net_key_del_help, |
| }, |
| { |
| .sc_cmd = "app-key-add", |
| .sc_cmd_func = cmd_app_key_add, |
| .help = &cmd_app_key_add_help, |
| }, |
| { |
| .sc_cmd = "app-key-del", |
| .sc_cmd_func = cmd_app_key_del, |
| .help = &cmd_app_key_del_help, |
| }, |
| { |
| .sc_cmd = "app-key-get", |
| .sc_cmd_func = cmd_app_key_get, |
| .help = &cmd_app_key_get_help, |
| }, |
| { |
| .sc_cmd = "net-transmit-param", |
| .sc_cmd_func = cmd_net_transmit, |
| .help = &cmd_net_transmit_help, |
| }, |
| { |
| .sc_cmd = "mod-app-bind", |
| .sc_cmd_func = cmd_mod_app_bind, |
| .help = &cmd_mod_app_bind_help, |
| }, |
| { |
| .sc_cmd = "mod-app-get", |
| .sc_cmd_func = cmd_mod_app_get, |
| .help = &cmd_mod_app_get_help, |
| }, |
| { |
| .sc_cmd = "mod-app-unbind", |
| .sc_cmd_func = cmd_mod_app_unbind, |
| .help = &cmd_mod_app_unbind_help, |
| }, |
| { |
| .sc_cmd = "mod-pub", |
| .sc_cmd_func = cmd_mod_pub, |
| .help = &cmd_mod_pub_help, |
| }, |
| { |
| .sc_cmd = "mod-sub-add", |
| .sc_cmd_func = cmd_mod_sub_add, |
| .help = &cmd_mod_sub_add_help, |
| }, |
| { |
| .sc_cmd = "mod-sub-del", |
| .sc_cmd_func = cmd_mod_sub_del, |
| .help = &cmd_mod_sub_del_help, |
| }, |
| { |
| .sc_cmd = "mod-sub-add-va", |
| .sc_cmd_func = cmd_mod_sub_add_va, |
| .help = &cmd_mod_sub_add_va_help, |
| }, |
| { |
| .sc_cmd = "mod-sub-get", |
| .sc_cmd_func = cmd_mod_sub_get, |
| .help = &cmd_mod_sub_get_help, |
| }, |
| { |
| .sc_cmd = "mod-sub-del-va", |
| .sc_cmd_func = cmd_mod_sub_del_va, |
| .help = &cmd_mod_sub_del_va_help, |
| }, |
| { |
| .sc_cmd = "hb-sub", |
| .sc_cmd_func = cmd_hb_sub, |
| .help = &cmd_hb_sub_help, |
| }, |
| { |
| .sc_cmd = "hb-pub", |
| .sc_cmd_func = cmd_hb_pub, |
| .help = &cmd_hb_pub_help, |
| }, |
| #endif |
| |
| #if MYNEWT_VAL(BLE_MESH_HEALTH_CLI) |
| /* Health Client Model Operations */ |
| { |
| .sc_cmd = "fault-get", |
| .sc_cmd_func = cmd_fault_get, |
| .help = &cmd_fault_get_help, |
| }, |
| { |
| .sc_cmd = "fault-clear", |
| .sc_cmd_func = cmd_fault_clear, |
| .help = &cmd_fault_clear_help, |
| }, |
| { |
| .sc_cmd = "fault-clear-unack", |
| .sc_cmd_func = cmd_fault_clear_unack, |
| .help = &cmd_fault_clear_unack_help, |
| }, |
| { |
| .sc_cmd = "fault-test", |
| .sc_cmd_func = cmd_fault_test, |
| .help = &cmd_fault_test_help, |
| }, |
| { |
| .sc_cmd = "fault-test-unack", |
| .sc_cmd_func = cmd_fault_test_unack, |
| .help = &cmd_fault_test_unack_help, |
| }, |
| { |
| .sc_cmd = "period-get", |
| .sc_cmd_func = cmd_period_get, |
| .help = NULL, |
| }, |
| { |
| .sc_cmd = "period-set", |
| .sc_cmd_func = cmd_period_set, |
| .help = &cmd_period_set_help, |
| }, |
| { |
| .sc_cmd = "period-set-unack", |
| .sc_cmd_func = cmd_period_set_unack, |
| .help = &cmd_period_set_unack_help, |
| }, |
| { |
| .sc_cmd = "attention-get", |
| .sc_cmd_func = cmd_attention_get, |
| .help = NULL, |
| }, |
| { |
| .sc_cmd = "attention-set", |
| .sc_cmd_func = cmd_attention_set, |
| .help = &cmd_attention_set_help, |
| }, |
| { |
| .sc_cmd = "attention-set-unack", |
| .sc_cmd_func = cmd_attention_set_unack, |
| .help = &cmd_attention_set_unack_help, |
| }, |
| #endif |
| |
| /* Health Server Model Operations */ |
| { |
| .sc_cmd = "add-fault", |
| .sc_cmd_func = cmd_add_fault, |
| .help = &cmd_add_fault_help, |
| }, |
| { |
| .sc_cmd = "del-fault", |
| .sc_cmd_func = cmd_del_fault, |
| .help = &cmd_del_fault_help, |
| }, |
| |
| #if MYNEWT_VAL(BLE_MESH_CDB) |
| { |
| .sc_cmd = "cdb-create", |
| .sc_cmd_func = cmd_cdb_create, |
| .help = &cmd_cdb_create_help, |
| },{ |
| .sc_cmd = "cdb-clear", |
| .sc_cmd_func = cmd_cdb_clear, |
| .help = &cmd_cdb_clear_help, |
| },{ |
| .sc_cmd = "cdb-show", |
| .sc_cmd_func = cmd_cdb_show, |
| .help = &cmd_cdb_show_help, |
| },{ |
| .sc_cmd = "cdb-node-add", |
| .sc_cmd_func = cmd_cdb_node_add, |
| .help = &cmd_cdb_node_add_help, |
| },{ |
| .sc_cmd = "cdb-node-del", |
| .sc_cmd_func = cmd_cdb_node_del, |
| .help = &cmd_cdb_node_del_help, |
| },{ |
| .sc_cmd = "cdb-subnet-add", |
| .sc_cmd_func = cmd_cdb_subnet_add, |
| .help = &cmd_cdb_subnet_add_help, |
| },{ |
| .sc_cmd = "cdb-subnet-del", |
| .sc_cmd_func = cmd_cdb_subnet_del, |
| .help = &cmd_cdb_subnet_del_help, |
| },{ |
| .sc_cmd = "cdb-app-key-add", |
| .sc_cmd_func = cmd_cdb_app_key_add, |
| .help = &cmd_cdb_app_key_add_help, |
| },{ |
| .sc_cmd = "cdb-app-key-add", |
| .sc_cmd_func = cmd_cdb_app_key_del, |
| .help = &cmd_cdb_app_key_del_help, |
| }, |
| #endif |
| |
| #if MYNEWT_VAL(BLE_MESH_SHELL_MODELS) |
| /* Generic Client Model Operations */ |
| { |
| .sc_cmd = "gen-onoff-get", |
| .sc_cmd_func = cmd_gen_onoff_get, |
| .help = NULL, |
| }, |
| { |
| .sc_cmd = "gen-onoff-set", |
| .sc_cmd_func = cmd_gen_onoff_set, |
| .help = &cmd_gen_onoff_set_help, |
| }, |
| { |
| .sc_cmd = "gen-onoff-set-unack", |
| .sc_cmd_func = cmd_gen_onoff_set_unack, |
| .help = &cmd_gen_onoff_set_unack_help, |
| }, |
| { |
| .sc_cmd = "gen-level-get", |
| .sc_cmd_func = cmd_gen_level_get, |
| .help = NULL, |
| }, |
| { |
| .sc_cmd = "gen-level-set", |
| .sc_cmd_func = cmd_gen_level_set, |
| .help = &cmd_gen_level_set_help, |
| }, |
| { |
| .sc_cmd = "gen-level-set-unack", |
| .sc_cmd_func = cmd_gen_level_set_unack, |
| .help = &cmd_gen_level_set_unack_help, |
| }, |
| #endif |
| |
| { 0 }, |
| }; |
| |
| static void mesh_shell_thread(void *args) |
| { |
| while (1) { |
| os_eventq_run(&mesh_shell_queue); |
| } |
| } |
| |
| static void bt_mesh_shell_task_init(void) |
| { |
| os_eventq_init(&mesh_shell_queue); |
| |
| os_task_init(&mesh_shell_task, "mesh_sh", mesh_shell_thread, NULL, |
| BLE_MESH_SHELL_TASK_PRIO, OS_WAIT_FOREVER, g_blemesh_shell_stack, |
| BLE_MESH_SHELL_STACK_SIZE); |
| } |
| #endif |
| |
| void ble_mesh_shell_init(void) |
| { |
| #if (MYNEWT_VAL(BLE_MESH_SHELL)) |
| |
| /* Initialize health pub message */ |
| health_pub_init(); |
| |
| /* Shell and other mesh clients should use separate task to |
| avoid deadlocks with mesh message processing queue */ |
| bt_mesh_shell_task_init(); |
| shell_evq_set(&mesh_shell_queue); |
| shell_register("mesh", mesh_commands); |
| |
| #endif |
| } |