]> granicus.if.org Git - esp-idf/commitdiff
Added support for NVS in console example
authorMartin Válik <martin.valik@espressif.com>
Fri, 11 Jan 2019 01:51:50 +0000 (09:51 +0800)
committerIvan Grokhotkov <ivan@espressif.com>
Fri, 11 Jan 2019 01:51:50 +0000 (09:51 +0800)
components/nvs_flash/include/nvs.h
examples/system/console/components/cmd_nvs/CMakeLists.txt [new file with mode: 0644]
examples/system/console/components/cmd_nvs/cmd_nvs.c [new file with mode: 0644]
examples/system/console/components/cmd_nvs/cmd_nvs.h [new file with mode: 0644]
examples/system/console/components/cmd_nvs/component.mk [new file with mode: 0644]
examples/system/console/main/cmd_decl.h
examples/system/console/main/console_example_main.c

index 0cc3ba09a6ef69c1450e0fa1db4fa1d03baa0436..1d88217ee0b662fed22081a8cedabb9f58386cb2 100644 (file)
@@ -65,6 +65,20 @@ typedef enum {
        NVS_READWRITE  /*!< Read and write */
 } nvs_open_mode;
 
+typedef enum {
+    NVS_TYPE_U8    = 0x01,
+    NVS_TYPE_I8    = 0x11,
+    NVS_TYPE_U16   = 0x02,
+    NVS_TYPE_I16   = 0x12,
+    NVS_TYPE_U32   = 0x04,
+    NVS_TYPE_I32   = 0x14,
+    NVS_TYPE_U64   = 0x08,
+    NVS_TYPE_I64   = 0x18,
+    NVS_TYPE_STR   = 0x21,
+    NVS_TYPE_BLOB  = 0x42,
+    NVS_TYPE_ANY   = 0xff // Must be last
+} nvs_type_t;
+
 /**
  * @brief      Open non-volatile storage with a given namespace from the default NVS partition
  *
diff --git a/examples/system/console/components/cmd_nvs/CMakeLists.txt b/examples/system/console/components/cmd_nvs/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7c2d3c7
--- /dev/null
@@ -0,0 +1,7 @@
+set(COMPONENT_ADD_INCLUDEDIRS .)
+
+set(COMPONENT_SRCS "cmd_nvs.c")
+
+set(COMPONENT_REQUIRES console nvs_flash)
+
+register_component()
diff --git a/examples/system/console/components/cmd_nvs/cmd_nvs.c b/examples/system/console/components/cmd_nvs/cmd_nvs.c
new file mode 100644 (file)
index 0000000..a7e4319
--- /dev/null
@@ -0,0 +1,518 @@
+/* Console example — NVS commands
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "esp_log.h"
+#include "esp_console.h"
+#include "argtable3/argtable3.h"
+#include "freertos/FreeRTOS.h"
+#include "freertos/event_groups.h"
+#include "esp_err.h"
+#include "cmd_nvs.h"
+#include "nvs.h"
+
+typedef struct {
+    nvs_type_t type;
+    const char *str;
+} type_str_pair_t;
+
+static const type_str_pair_t type_str_pair[] = {
+    { NVS_TYPE_I8, "i8" },
+    { NVS_TYPE_U8, "u8" },
+    { NVS_TYPE_U16, "u16" },
+    { NVS_TYPE_I16, "i16" },
+    { NVS_TYPE_U32, "u32" },
+    { NVS_TYPE_I32, "i32" },
+    { NVS_TYPE_U64, "u64" },
+    { NVS_TYPE_I64, "i64" },
+    { NVS_TYPE_STR, "str" },
+    { NVS_TYPE_BLOB, "blob" },
+    { NVS_TYPE_ANY, "any" },
+};
+
+static const size_t TYPE_STR_PAIR_SIZE = sizeof(type_str_pair) / sizeof(type_str_pair[0]);
+static const char *ARG_TYPE_STR = "type can be: i8, u8, i16, u16 i32, u32 i64, u64, str, blob";
+static char current_namespace[16] = "storage";
+static const char *TAG = "cmd_nvs";
+
+static struct {
+    struct arg_str *key;
+    struct arg_str *type;
+    struct arg_str *value;
+    struct arg_end *end;
+} set_args;
+
+static struct {
+    struct arg_str *key;
+    struct arg_str *type;
+    struct arg_end *end;
+} get_args;
+
+static struct {
+    struct arg_str *key;
+    struct arg_end *end;
+} erase_args;
+
+static struct {
+    struct arg_str *namespace;
+    struct arg_end *end;
+} erase_all_args;
+
+static struct {
+    struct arg_str *namespace;
+    struct arg_end *end;
+} namespace_args;
+
+
+static nvs_type_t str_to_type(const char *type)
+{
+    for (int i = 0; i < TYPE_STR_PAIR_SIZE; i++) {
+        const type_str_pair_t *p = &type_str_pair[i];
+        if (strncmp(type, p->str, strlen(p->str)) == 0) {
+            return  p->type;
+        }
+    }
+
+    return NVS_TYPE_ANY;
+}
+
+static esp_err_t store_blob(nvs_handle nvs, const char *key, const char *str_values)
+{
+    uint8_t value;
+    size_t str_len = strlen(str_values);
+    size_t blob_len = str_len / 2;
+
+    if (str_len % 2) {
+        ESP_LOGE(TAG, "Blob data must contain even number of characters");
+        return ESP_ERR_NVS_TYPE_MISMATCH;
+    }
+
+    char *blob = (char *)malloc(blob_len);
+    if (blob == NULL) {
+        return ESP_ERR_NO_MEM;
+    }
+
+    for (int i = 0, j = 0; i < str_len; i++) {
+        char ch = str_values[i];
+        if (ch >= '0' && ch <= '9') {
+            value = ch - '0';
+        } else if (ch >= 'A' && ch <= 'F') {
+            value = ch - 'A' + 10;
+        } else if (ch >= 'a' && ch <= 'f') {
+            value = ch - 'a' + 10;
+        } else {
+            ESP_LOGE(TAG, "Blob data contain invalid character");
+            free(blob);
+            return ESP_ERR_NVS_TYPE_MISMATCH;
+        }
+
+        if (i & 1) {
+            blob[j++] += value;
+        } else {
+            blob[j] = value << 4;
+        }
+    }
+
+    esp_err_t err = nvs_set_blob(nvs, key, blob, blob_len);
+    free(blob);
+
+    if (err == ESP_OK) {
+        err = nvs_commit(nvs);
+    }
+
+    return err;
+}
+
+static void print_blob(const char *blob, size_t len)
+{
+    for (int i = 0; i < len; i++) {
+        printf("%02x", blob[i]);
+    }
+    printf("\n");
+}
+
+static esp_err_t set_value_in_nvs(const char *key, const char *str_type, const char *str_value)
+{
+    esp_err_t err;
+    nvs_handle nvs;
+    bool range_error = false;
+
+    nvs_type_t type = str_to_type(str_type);
+
+    if (type == NVS_TYPE_ANY) {
+        return ESP_ERR_NVS_TYPE_MISMATCH;
+    }
+
+    err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
+    if (err != ESP_OK) {
+        return err;
+    }
+
+    if (type == NVS_TYPE_I8) {
+        int32_t value = strtol(str_value, NULL, 0);
+        if (value < INT8_MIN || value > INT8_MAX || errno == ERANGE) {
+            range_error = true;
+        } else {
+            err = nvs_set_i8(nvs, key, (int8_t)value);
+        }
+    } else if (type == NVS_TYPE_U8) {
+        uint32_t value = strtoul(str_value, NULL, 0);
+        if (value > UINT8_MAX || errno == ERANGE) {
+            range_error = true;
+        } else {
+            err = nvs_set_u8(nvs, key, (uint8_t)value);
+        }
+    } else if (type == NVS_TYPE_I16) {
+        int32_t value = strtol(str_value, NULL, 0);
+        if (value < INT16_MIN || value > INT16_MAX || errno == ERANGE) {
+            range_error = true;
+        } else {
+            err = nvs_set_i16(nvs, key, (int16_t)value);
+        }
+    } else if (type == NVS_TYPE_U16) {
+        uint32_t value = strtoul(str_value, NULL, 0);
+        if (value > UINT16_MAX || errno == ERANGE) {
+            range_error = true;
+        } else {
+            err = nvs_set_u16(nvs, key, (uint16_t)value);
+        }
+    } else if (type == NVS_TYPE_I32) {
+        int32_t value = strtol(str_value, NULL, 0);
+        if (errno != ERANGE) {
+            err = nvs_set_i32(nvs, key, value);
+        }
+    } else if (type == NVS_TYPE_U32) {
+        uint32_t value = strtoul(str_value, NULL, 0);
+        if (errno != ERANGE) {
+            err = nvs_set_u32(nvs, key, value);
+        }
+    } else if (type == NVS_TYPE_I64) {
+        int64_t value = strtoll(str_value, NULL, 0);
+        if (errno != ERANGE) {
+            err = nvs_set_i64(nvs, key, value);
+        }
+    } else if (type == NVS_TYPE_U64) {
+        uint64_t value = strtoull(str_value, NULL, 0);
+        if (errno != ERANGE) {
+            err = nvs_set_u64(nvs, key, value);
+        }
+    } else if (type == NVS_TYPE_STR) {
+        err = nvs_set_str(nvs, key, str_value);
+    } else if (type == NVS_TYPE_BLOB) {
+        err = store_blob(nvs, key, str_value);
+    }
+
+    if (range_error || errno == ERANGE) {
+        nvs_close(nvs);
+        return ESP_ERR_NVS_VALUE_TOO_LONG;
+    }
+
+    if (err == ESP_OK) {
+        err = nvs_commit(nvs);
+        if (err == ESP_OK) {
+            ESP_LOGI(TAG, "Value stored under key '%s'", key);
+        }
+    }
+
+    nvs_close(nvs);
+    return err;
+}
+
+static esp_err_t get_value_from_nvs(const char *key, const char *str_type)
+{
+    nvs_handle nvs;
+    esp_err_t err;
+
+    nvs_type_t type = str_to_type(str_type);
+
+    if (type == NVS_TYPE_ANY) {
+        return ESP_ERR_NVS_TYPE_MISMATCH;
+    }
+
+    err = nvs_open(current_namespace, NVS_READONLY, &nvs);
+    if (err != ESP_OK) {
+        return err;
+    }
+
+    if (type == NVS_TYPE_I8) {
+        int8_t value;
+        err = nvs_get_i8(nvs, key, &value);
+        if (err == ESP_OK) {
+            printf("Value associated with key '%s' is %d \n", key, value);
+        }
+    } else if (type == NVS_TYPE_U8) {
+        uint8_t value;
+        err = nvs_get_u8(nvs, key, &value);
+        if (err == ESP_OK) {
+            printf("Value associated with key '%s' is %u \n", key, value);
+        }
+    } else if (type == NVS_TYPE_I16) {
+        int16_t value;
+        err = nvs_get_i16(nvs, key, &value);
+        if (err == ESP_OK) {
+            printf("Value associated with key '%s' is %d \n", key, value);
+        }
+    } else if (type == NVS_TYPE_U16) {
+        uint16_t value;
+        if ((err = nvs_get_u16(nvs, key, &value)) == ESP_OK) {
+            printf("Value associated with key '%s' is %u", key, value);
+        }
+    } else if (type == NVS_TYPE_I32) {
+        int32_t value;
+        if ((err = nvs_get_i32(nvs, key, &value)) == ESP_OK) {
+            printf("Value associated with key '%s' is %d \n", key, value);
+        }
+    } else if (type == NVS_TYPE_U32) {
+        uint32_t value;
+        if ((err = nvs_get_u32(nvs, key, &value)) == ESP_OK) {
+            printf("Value associated with key '%s' is %u \n", key, value);
+        }
+    } else if (type == NVS_TYPE_I64) {
+        int64_t value;
+        if ((err = nvs_get_i64(nvs, key, &value)) == ESP_OK) {
+            printf("Value associated with key '%s' is %lld \n", key, value);
+        }
+    } else if (type == NVS_TYPE_U64) {
+        uint64_t value;
+        if ( (err = nvs_get_u64(nvs, key, &value)) == ESP_OK) {
+            printf("Value associated with key '%s' is %llu \n", key, value);
+        }
+    } else if (type == NVS_TYPE_STR) {
+        size_t len;
+        if ( (err = nvs_get_str(nvs, key, NULL, &len)) == ESP_OK) {
+            char *str = (char *)malloc(len);
+            if ( (err = nvs_get_str(nvs, key, str, &len)) == ESP_OK) {
+                printf("String associated with key '%s' is %s \n", key, str);
+            }
+            free(str);
+        }
+    } else if (type == NVS_TYPE_BLOB) {
+        size_t len;
+        if ( (err = nvs_get_blob(nvs, key, NULL, &len)) == ESP_OK) {
+            char *blob = (char *)malloc(len);
+            if ( (err = nvs_get_blob(nvs, key, blob, &len)) == ESP_OK) {
+                printf("Blob associated with key '%s' is %d bytes long: \n", key, len);
+                print_blob(blob, len);
+            }
+            free(blob);
+        }
+    }
+
+    nvs_close(nvs);
+    return err;
+}
+
+static esp_err_t erase(const char *key)
+{
+    nvs_handle nvs;
+
+    esp_err_t err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
+    if (err == ESP_OK) {
+        err = nvs_erase_key(nvs, key);
+        if (err == ESP_OK) {
+            err = nvs_commit(nvs);
+            if (err == ESP_OK) {
+                ESP_LOGI(TAG, "Value with key '%s' erased", key);
+            }
+        }
+        nvs_close(nvs);
+    }
+
+    return err;
+}
+
+static esp_err_t erase_all(const char *name)
+{
+    nvs_handle nvs;
+
+    esp_err_t err = nvs_open(current_namespace, NVS_READWRITE, &nvs);
+    if (err == ESP_OK) {
+        err = nvs_erase_all(nvs);
+        if (err == ESP_OK) {
+            err = nvs_commit(nvs);
+        }
+    }
+
+    ESP_LOGI(TAG, "Namespace '%s' was %s erased", name, (err == ESP_OK) ? "" : "not");
+    nvs_close(nvs);
+    return ESP_OK;
+}
+
+static int set_value(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **) &set_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, set_args.end, argv[0]);
+        return 1;
+    }
+
+    const char *key = set_args.key->sval[0];
+    const char *type = set_args.type->sval[0];
+    const char *values = set_args.value->sval[0];
+
+    esp_err_t err = set_value_in_nvs(key, type, values);
+
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s", esp_err_to_name(err));
+        return 1;
+    }
+
+    return 0;
+
+}
+
+static int get_value(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **) &get_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, get_args.end, argv[0]);
+        return 1;
+    }
+
+    const char *key = get_args.key->sval[0];
+    const char *type = get_args.type->sval[0];
+
+    esp_err_t err = get_value_from_nvs(key, type);
+
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s", esp_err_to_name(err));
+        return 1;
+    }
+
+    return 0;
+}
+
+static int erase_value(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **) &erase_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, erase_args.end, argv[0]);
+        return 1;
+    }
+
+    const char *key = erase_args.key->sval[0];
+
+    esp_err_t err = erase(key);
+
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s", esp_err_to_name(err));
+        return 1;
+    }
+
+    return 0;
+}
+
+static int erase_namespace(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **) &erase_all_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, erase_all_args.end, argv[0]);
+        return 1;
+    }
+
+    const char *name = erase_all_args.namespace->sval[0];
+
+    esp_err_t err = erase_all(name);
+    if (err != ESP_OK) {
+        ESP_LOGE(TAG, "%s", esp_err_to_name(err));
+        return 1;
+    }
+
+    return 0;
+}
+
+static int set_namespace(int argc, char **argv)
+{
+    int nerrors = arg_parse(argc, argv, (void **) &namespace_args);
+    if (nerrors != 0) {
+        arg_print_errors(stderr, namespace_args.end, argv[0]);
+        return 1;
+    }
+
+    const char *namespace = namespace_args.namespace->sval[0];
+    strlcpy(current_namespace, namespace, sizeof(current_namespace));
+    ESP_LOGI(TAG, "Namespace set to '%s'", current_namespace);
+    return 0;
+}
+
+void register_nvs()
+{
+    set_args.key = arg_str1(NULL, NULL, "<key>", "key of the value to be set");
+    set_args.type = arg_str1(NULL, NULL, "<type>", ARG_TYPE_STR);
+    set_args.value = arg_str1("v", "value", "<value>", "value to be stored");
+    set_args.end = arg_end(2);
+
+    get_args.key = arg_str1(NULL, NULL, "<key>", "key of the value to be read");
+    get_args.type = arg_str1(NULL, NULL, "<type>", ARG_TYPE_STR);
+    get_args.end = arg_end(2);
+
+    erase_args.key = arg_str1(NULL, NULL, "<key>", "key of the value to be erased");
+    erase_args.end = arg_end(2);
+
+    erase_all_args.namespace = arg_str1(NULL, NULL, "<namespace>", "namespace to be erased");
+    erase_all_args.end = arg_end(2);
+
+    namespace_args.namespace = arg_str1(NULL, NULL, "<namespace>", "namespace of the partition to be selected");
+    namespace_args.end = arg_end(2);
+
+    const esp_console_cmd_t set_cmd = {
+        .command = "nvs_set",
+        .help = "Set variable in selected namespace. Blob type must be comma separated list of hex values. \n"
+        "Examples:\n"
+        " nvs_set VarName i32 -v 123 \n"
+        " nvs_set VarName srt -v YourString \n"
+        " nvs_set VarName blob -v 0123456789abcdef \n",
+        .hint = NULL,
+        .func = &set_value,
+        .argtable = &set_args
+    };
+
+    const esp_console_cmd_t get_cmd = {
+        .command = "nvs_get",
+        .help = "Get variable from selected namespace. \n"
+        "Example: nvs_get VarName i32",
+        .hint = NULL,
+        .func = &get_value,
+        .argtable = &get_args
+    };
+
+    const esp_console_cmd_t erase_cmd = {
+        .command = "nvs_erase",
+        .help = "Erase variable from current namespace",
+        .hint = NULL,
+        .func = &erase_value,
+        .argtable = &erase_args
+    };
+
+    const esp_console_cmd_t erase_namespace_cmd = {
+        .command = "nvs_erase_namespace",
+        .help = "Erases specified namespace",
+        .hint = NULL,
+        .func = &erase_namespace,
+        .argtable = &erase_all_args
+    };
+
+    const esp_console_cmd_t namespace_cmd = {
+        .command = "nvs_namespace",
+        .help = "Set current namespace",
+        .hint = NULL,
+        .func = &set_namespace,
+        .argtable = &namespace_args
+    };
+
+    ESP_ERROR_CHECK(esp_console_cmd_register(&set_cmd));
+    ESP_ERROR_CHECK(esp_console_cmd_register(&get_cmd));
+    ESP_ERROR_CHECK(esp_console_cmd_register(&erase_cmd));
+    ESP_ERROR_CHECK(esp_console_cmd_register(&namespace_cmd));
+    ESP_ERROR_CHECK(esp_console_cmd_register(&erase_namespace_cmd));
+}
diff --git a/examples/system/console/components/cmd_nvs/cmd_nvs.h b/examples/system/console/components/cmd_nvs/cmd_nvs.h
new file mode 100644 (file)
index 0000000..6d0de50
--- /dev/null
@@ -0,0 +1,21 @@
+/* Console example — declarations of command registration functions.
+
+   This example code is in the Public Domain (or CC0 licensed, at your option.)
+
+   Unless required by applicable law or agreed to in writing, this
+   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, either express or implied.
+*/
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Register NVS functions
+void register_nvs();
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/examples/system/console/components/cmd_nvs/component.mk b/examples/system/console/components/cmd_nvs/component.mk
new file mode 100644 (file)
index 0000000..e0e9f4c
--- /dev/null
@@ -0,0 +1,10 @@
+#
+# Component Makefile
+#
+# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
+# this will take the sources in the src/ directory, compile them and link them into
+# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
+# please read the SDK documents if you need to do this.
+#
+
+COMPONENT_ADD_INCLUDEDIRS := .
index efdda4e25e08dc5983446c28edc3d36427d8bf60..983b6e974c9370af6c9b7d201076a1db7fb6f608 100644 (file)
@@ -14,6 +14,7 @@ extern "C" {
 
 #include "cmd_system.h"
 #include "cmd_wifi.h"
+#include "cmd_nvs.h"
 
 #ifdef __cplusplus
 }
index f56563f6c08ab774643fe6e57b10481fa8a0481c..23d1cf2c9165155f740edcc2a3eed8541613f9bb 100644 (file)
@@ -130,6 +130,7 @@ void app_main()
     esp_console_register_help_command();
     register_system();
     register_wifi();
+    register_nvs();
 
     /* Prompt to be printed before each line.
      * This can be customized, made dynamic, etc.