ESP32 NVS Keys Part 1
This began as a four- or five-question exploration of the Non-volatile storage library for the ESP32. However, the queries, simple at first, grew in depth as I probed their bounds.
What constitutes a valid key?
Keys are ASCII strings; the maximum key length is currently 15 characters.
On its face, this means anything a developer might type from 1 to 15 characters could be a valid key e.g. api_key, or domain_name, or fifteen_chars_0 would be valid strings. The limitation on length appears to imply that the API appends a final NUL char as the sixteenth char thus satisfying the requirements of a terminating 0x00 at the end of a C-style string. Let’s look at the nvs_set_str() function.
esp_err_t nvs_set_str(nvs_handle_t handle, const char* key, const char* value);
key‘s type is a const char* meaning the data has to be stored somewhere either on the stack or the heap, and this function is expecting a pointer which cannot change the data.
const char[] my_key_0 = "This is valid!"; const char[] my_key_1 = "a";
my_key_0 and my_key_1 would be perfectly valid const char pointers to supply to the function call. How about naïve? It turns out that’s a valid key. How about naïve_key_is_ok?
Error (ESP_ERR_NVS_KEY_TOO_LONG) storing value in key (my_key_2)!
That’s odd, I counted fifteen characters: n – a – ï – v – e – _ – k – e – y – _ – i – s – _ – o – k. That’s interesting: the IDE tells me it’s 17 chars long, and the compiler warns me:
(char [17])"naïve_key_is_ok"
warning: multi-character character constant [-Wmultichar]
const char np_key_3[] = { 'n', 'a', 'ï', 'v', 'e', '_', 'k', 'e', 'y', '_', 'i', 's', '_', 'o', '\0' };
That’s interesting. Let’s try forcing it with hex values. (note the final 0x00 or NUL character)
const char my_key_3[] = { 0x6e, 0x61, 0xef, 0x76, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x73, 0x5f, 0x6f, 0x6b, 0x00 };
That works without issue. Let’s shorten the string by one character.
const char my_key_3[] = "naïve_key_is_o";
That works as well. Does that mean the keys are equivalent??? This is just one of the many questions I encountered. For brevity’s sake, I’ll attempt to answer that in a future post. It does point to one answer, however, these ASCII strings can be comprised of valid numbers which fit. Consider:
const char my_key_4[] = { 0x00, 0x00 }; const char my_key_5[] = "\0";
These are both perfectly valid. Even the following is a “valid string”:
const char my_key_6[] = { 0x00 };
It appears that the function will accept any string so long as its bit representation does not exceed 16 bytes total. A developer can rely on the compiler to convert the “printable” and “extended” ASCII characters with the awareness that the compiler may want to widen the extended characters into multiple bytes and that they may not be directly compatible with their hexadecimal equivalents, but I will expand on this in a follow-up post. The other option is to take direct responsibility for crafting character strings from numerical values which expands the possible range of valid characters into the “control” characters section of ASCII. Please note that the NUL (0x00) character can be used, but extreme caution is advised as it behaves unlike the other characters.
1 comment