/* * Copyright (c) 2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include struct settings_list_callback_params { const struct shell *shell_ptr; const char *subtree; }; static int settings_list_callback(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg, void *param) { ARG_UNUSED(len); ARG_UNUSED(read_cb); ARG_UNUSED(cb_arg); struct settings_list_callback_params *params = param; if (params->subtree != NULL) { shell_print(params->shell_ptr, "%s/%s", params->subtree, key); } else { shell_print(params->shell_ptr, "%s", key); } return 0; } static int cmd_list(const struct shell *shell_ptr, size_t argc, char *argv[]) { int err; struct settings_list_callback_params params = { .shell_ptr = shell_ptr, .subtree = (argc == 2 ? argv[1] : NULL) }; err = settings_load_subtree_direct(params.subtree, settings_list_callback, ¶ms); if (err) { shell_error(shell_ptr, "Failed to load settings: %d", err); } return err; } enum settings_value_types { SETTINGS_VALUE_HEX, SETTINGS_VALUE_STRING, }; struct settings_read_callback_params { const struct shell *shell_ptr; const enum settings_value_types value_type; bool value_found; }; static int settings_read_callback(const char *key, size_t len, settings_read_cb read_cb, void *cb_arg, void *param) { uint8_t buffer[SETTINGS_MAX_VAL_LEN]; ssize_t num_read_bytes = MIN(len, SETTINGS_MAX_VAL_LEN); struct settings_read_callback_params *params = param; /* Process only the exact match and ignore descendants of the searched name */ if (settings_name_next(key, NULL) != 0) { return 0; } params->value_found = true; num_read_bytes = read_cb(cb_arg, buffer, num_read_bytes); if (num_read_bytes < 0) { shell_error(params->shell_ptr, "Failed to read value: %d", (int) num_read_bytes); return 0; } if (num_read_bytes == 0) { shell_warn(params->shell_ptr, "Value is empty"); return 0; } switch (params->value_type) { case SETTINGS_VALUE_HEX: shell_hexdump(params->shell_ptr, buffer, num_read_bytes); break; case SETTINGS_VALUE_STRING: if (buffer[num_read_bytes - 1] != '\0') { shell_error(params->shell_ptr, "Value is not a string"); return 0; } shell_print(params->shell_ptr, "%s", buffer); break; } if (len > SETTINGS_MAX_VAL_LEN) { shell_print(params->shell_ptr, "(The output has been truncated)"); } return 0; } static int settings_parse_type(const char *type, enum settings_value_types *value_type) { if (strcmp(type, "string") == 0) { *value_type = SETTINGS_VALUE_STRING; } else if (strcmp(type, "hex") == 0) { *value_type = SETTINGS_VALUE_HEX; } else { return -EINVAL; } return 0; } static int cmd_read(const struct shell *shell_ptr, size_t argc, char *argv[]) { int err; enum settings_value_types value_type = SETTINGS_VALUE_HEX; if (argc > 2) { err = settings_parse_type(argv[1], &value_type); if (err) { shell_error(shell_ptr, "Invalid type: %s", argv[1]); return err; } } struct settings_read_callback_params params = { .shell_ptr = shell_ptr, .value_type = value_type, .value_found = false }; err = settings_load_subtree_direct(argv[argc - 1], settings_read_callback, ¶ms); if (err) { shell_error(shell_ptr, "Failed to load setting: %d", err); } else if (!params.value_found) { err = -ENOENT; shell_error(shell_ptr, "Setting not found"); } return err; } static int cmd_write(const struct shell *shell_ptr, size_t argc, char *argv[]) { int err; uint8_t buffer[CONFIG_SHELL_CMD_BUFF_SIZE / 2]; size_t buffer_len = 0; enum settings_value_types value_type = SETTINGS_VALUE_HEX; if (argc > 3) { err = settings_parse_type(argv[1], &value_type); if (err) { shell_error(shell_ptr, "Invalid type: %s", argv[1]); return err; } } switch (value_type) { case SETTINGS_VALUE_HEX: buffer_len = hex2bin(argv[argc - 1], strlen(argv[argc - 1]), buffer, sizeof(buffer)); break; case SETTINGS_VALUE_STRING: buffer_len = strlen(argv[argc - 1]) + 1; if (buffer_len > sizeof(buffer)) { shell_error(shell_ptr, "%s is bigger than shell's buffer", argv[argc - 1]); return -EINVAL; } memcpy(buffer, argv[argc - 1], buffer_len); break; } if (buffer_len == 0) { shell_error(shell_ptr, "Failed to parse value"); return -EINVAL; } err = settings_save_one(argv[argc - 2], buffer, buffer_len); if (err) { shell_error(shell_ptr, "Failed to write setting: %d", err); } return err; } static int cmd_delete(const struct shell *shell_ptr, size_t argc, char *argv[]) { int err; err = settings_delete(argv[1]); if (err) { shell_error(shell_ptr, "Failed to delete setting: %d", err); } return err; } SHELL_STATIC_SUBCMD_SET_CREATE(settings_cmds, SHELL_CMD_ARG(list, NULL, "List all settings in a subtree (omit to list all)\n" "Usage: settings list [subtree]", cmd_list, 1, 1), SHELL_CMD_ARG(read, NULL, "Read a specific setting\n" "Usage: settings read [type] \n" "type: string or hex (default: hex)", cmd_read, 2, 1), SHELL_CMD_ARG(write, NULL, "Write to a specific setting\n" "Usage: settings write [type] \n" "type: string or hex (default: hex)", cmd_write, 3, 1), SHELL_CMD_ARG(delete, NULL, "Delete a specific setting\n" "Usage: settings delete ", cmd_delete, 2, 0), SHELL_SUBCMD_SET_END); static int cmd_settings(const struct shell *shell_ptr, size_t argc, char **argv) { shell_error(shell_ptr, "%s unknown parameter: %s", argv[0], argv[1]); return -EINVAL; } SHELL_CMD_ARG_REGISTER(settings, &settings_cmds, "Settings shell commands", cmd_settings, 2, 0);