3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2019-2020 Google LLC.
5 * Copyright (c) 2018 Nest Labs, Inc.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
23 * Utilities for interacting with the the ESP32 "NVS" key-value store.
25 /* this file behaves like a config.h, comes first */
26 #include <platform/internal/CHIPDeviceLayerInternal.h>
28 #include <platform/ESP32/ESP32Config.h>
30 #include <core/CHIPEncoding.h>
31 #include <platform/ESP32/ESP32Utils.h>
32 #include <support/CHIPMem.h>
33 #include <support/CHIPMemString.h>
34 #include <support/CodeUtils.h>
35 #include <support/logging/CHIPLogging.h>
38 #include "nvs_flash.h"
41 namespace DeviceLayer {
44 // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices.
46 // NVS namespaces used to store device configuration information.
47 const char ESP32Config::kConfigNamespace_ChipFactory[] = "chip-factory";
48 const char ESP32Config::kConfigNamespace_ChipConfig[] = "chip-config";
49 const char ESP32Config::kConfigNamespace_ChipCounters[] = "chip-counters";
51 // Keys stored in the chip-factory namespace
52 const ESP32Config::Key ESP32Config::kConfigKey_SerialNum = { kConfigNamespace_ChipFactory, "serial-num" };
53 const ESP32Config::Key ESP32Config::kConfigKey_MfrDeviceId = { kConfigNamespace_ChipFactory, "device-id" };
54 const ESP32Config::Key ESP32Config::kConfigKey_MfrDeviceCert = { kConfigNamespace_ChipFactory, "device-cert" };
55 const ESP32Config::Key ESP32Config::kConfigKey_MfrDeviceICACerts = { kConfigNamespace_ChipFactory, "device-ca-certs" };
56 const ESP32Config::Key ESP32Config::kConfigKey_MfrDevicePrivateKey = { kConfigNamespace_ChipFactory, "device-key" };
57 const ESP32Config::Key ESP32Config::kConfigKey_ProductRevision = { kConfigNamespace_ChipFactory, "product-rev" };
58 const ESP32Config::Key ESP32Config::kConfigKey_ManufacturingDate = { kConfigNamespace_ChipFactory, "mfg-date" };
59 const ESP32Config::Key ESP32Config::kConfigKey_SetupPinCode = { kConfigNamespace_ChipFactory, "pin-code" };
60 const ESP32Config::Key ESP32Config::kConfigKey_SetupDiscriminator = { kConfigNamespace_ChipFactory, "discriminator" };
62 // Keys stored in the chip-config namespace
63 const ESP32Config::Key ESP32Config::kConfigKey_FabricId = { kConfigNamespace_ChipConfig, "fabric-id" };
64 const ESP32Config::Key ESP32Config::kConfigKey_ServiceConfig = { kConfigNamespace_ChipConfig, "service-config" };
65 const ESP32Config::Key ESP32Config::kConfigKey_PairedAccountId = { kConfigNamespace_ChipConfig, "account-id" };
66 const ESP32Config::Key ESP32Config::kConfigKey_ServiceId = { kConfigNamespace_ChipConfig, "service-id" };
67 const ESP32Config::Key ESP32Config::kConfigKey_GroupKeyIndex = { kConfigNamespace_ChipConfig, "group-key-index" };
68 const ESP32Config::Key ESP32Config::kConfigKey_LastUsedEpochKeyId = { kConfigNamespace_ChipConfig, "last-ek-id" };
69 const ESP32Config::Key ESP32Config::kConfigKey_FailSafeArmed = { kConfigNamespace_ChipConfig, "fail-safe-armed" };
70 const ESP32Config::Key ESP32Config::kConfigKey_WiFiStationSecType = { kConfigNamespace_ChipConfig, "sta-sec-type" };
71 const ESP32Config::Key ESP32Config::kConfigKey_OperationalDeviceId = { kConfigNamespace_ChipConfig, "op-device-id" };
72 const ESP32Config::Key ESP32Config::kConfigKey_OperationalDeviceCert = { kConfigNamespace_ChipConfig, "op-device-cert" };
73 const ESP32Config::Key ESP32Config::kConfigKey_OperationalDeviceICACerts = { kConfigNamespace_ChipConfig, "op-device-ca-certs" };
74 const ESP32Config::Key ESP32Config::kConfigKey_OperationalDevicePrivateKey = { kConfigNamespace_ChipConfig, "op-device-key" };
76 // Prefix used for NVS keys that contain Chip group encryption keys.
77 const char ESP32Config::kGroupKeyNamePrefix[] = "gk-";
79 CHIP_ERROR ESP32Config::ReadConfigValue(Key key, bool & val)
83 bool needClose = false;
86 err = nvs_open(key.Namespace, NVS_READONLY, &handle);
90 err = nvs_get_u32(handle, key.Name, &intVal);
91 if (err == ESP_ERR_NVS_NOT_FOUND)
93 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
107 CHIP_ERROR ESP32Config::ReadConfigValue(Key key, uint32_t & val)
111 bool needClose = false;
113 err = nvs_open(key.Namespace, NVS_READONLY, &handle);
117 err = nvs_get_u32(handle, key.Name, &val);
118 if (err == ESP_ERR_NVS_NOT_FOUND)
120 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
132 CHIP_ERROR ESP32Config::ReadConfigValue(Key key, uint64_t & val)
136 bool needClose = false;
138 err = nvs_open(key.Namespace, NVS_READONLY, &handle);
142 // Special case the MfrDeviceId value, optionally allowing it to be read as a blob containing
143 // a 64-bit big-endian integer, instead of a u64 value.
145 // The ESP32 development environment provides a tool for pre-populating the NVS partition using
146 // values from a CSV file. This tool is convenient for provisioning devices during manufacturing.
147 // However currently the tool does not support pre-populating u64 values such as MfrDeviceId.
148 // Thus we allow MfrDeviceId to be stored as a blob instead.
150 if (key == kConfigKey_MfrDeviceId)
152 uint8_t deviceIdBytes[sizeof(uint64_t)];
153 size_t deviceIdLen = sizeof(deviceIdBytes);
154 err = nvs_get_blob(handle, key.Name, deviceIdBytes, &deviceIdLen);
157 VerifyOrExit(deviceIdLen == sizeof(deviceIdBytes), err = ESP_ERR_NVS_INVALID_LENGTH);
158 val = Encoding::BigEndian::Get64(deviceIdBytes);
163 err = nvs_get_u64(handle, key.Name, &val);
164 if (err == ESP_ERR_NVS_NOT_FOUND)
166 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
178 CHIP_ERROR ESP32Config::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
182 bool needClose = false;
184 err = nvs_open(key.Namespace, NVS_READONLY, &handle);
189 err = nvs_get_str(handle, key.Name, buf, &outLen);
190 if (err == ESP_ERR_NVS_NOT_FOUND)
193 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
195 else if (err == ESP_ERR_NVS_INVALID_LENGTH)
197 err = (buf == NULL) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
201 outLen -= 1; // Don't count trailing nul.
212 CHIP_ERROR ESP32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
216 bool needClose = false;
218 err = nvs_open(key.Namespace, NVS_READONLY, &handle);
223 err = nvs_get_blob(handle, key.Name, buf, &outLen);
224 if (err == ESP_ERR_NVS_NOT_FOUND)
227 err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
229 else if (err == ESP_ERR_NVS_INVALID_LENGTH)
231 err = (buf == NULL) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
244 CHIP_ERROR ESP32Config::WriteConfigValue(Key key, bool val)
248 bool needClose = false;
250 err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
254 err = nvs_set_u32(handle, key.Name, val ? 1 : 0);
257 // Commit the value to the persistent store.
258 err = nvs_commit(handle);
261 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %s", key.Namespace, key.Name, val ? "true" : "false");
272 CHIP_ERROR ESP32Config::WriteConfigValue(Key key, uint32_t val)
276 bool needClose = false;
278 err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
282 err = nvs_set_u32(handle, key.Name, val);
285 // Commit the value to the persistent store.
286 err = nvs_commit(handle);
289 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu32 " (0x%" PRIX32 ")", key.Namespace, key.Name, val, val);
300 CHIP_ERROR ESP32Config::WriteConfigValue(Key key, uint64_t val)
304 bool needClose = false;
306 err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
310 err = nvs_set_u64(handle, key.Name, val);
313 // Commit the value to the persistent store.
314 err = nvs_commit(handle);
317 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu64 " (0x%" PRIX64 ")", key.Namespace, key.Name, val, val);
328 CHIP_ERROR ESP32Config::WriteConfigValueStr(Key key, const char * str)
332 bool needClose = false;
336 err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
340 err = nvs_set_str(handle, key.Name, str);
343 // Commit the value to the persistent store.
344 err = nvs_commit(handle);
347 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = \"%s\"", key.Namespace, key.Name, str);
352 err = ClearConfigValue(key);
365 CHIP_ERROR ESP32Config::WriteConfigValueStr(Key key, const char * str, size_t strLen)
368 chip::Platform::ScopedMemoryBuffer<char> strCopy;
372 strCopy.Calloc(strLen + 1);
373 VerifyOrExit(strCopy, err = CHIP_ERROR_NO_MEMORY);
374 strncpy(strCopy.Get(), str, strLen);
376 err = ESP32Config::WriteConfigValueStr(key, strCopy.Get());
382 CHIP_ERROR ESP32Config::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
386 bool needClose = false;
390 err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
394 err = nvs_set_blob(handle, key.Name, data, dataLen);
397 // Commit the value to the persistent store.
398 err = nvs_commit(handle);
401 ChipLogProgress(DeviceLayer, "NVS set: %s/%s = (blob length %" PRId32 ")", key.Namespace, key.Name, dataLen);
406 err = ClearConfigValue(key);
419 CHIP_ERROR ESP32Config::ClearConfigValue(Key key)
423 bool needClose = false;
425 err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
429 err = nvs_erase_key(handle, key.Name);
430 if (err == ESP_ERR_NVS_NOT_FOUND)
432 ExitNow(err = CHIP_NO_ERROR);
436 // Commit the value to the persistent store.
437 err = nvs_commit(handle);
440 ChipLogProgress(DeviceLayer, "NVS erase: %s/%s", key.Namespace, key.Name);
451 bool ESP32Config::ConfigValueExists(Key key)
455 bool needClose = false;
457 err = nvs_open(key.Namespace, NVS_READONLY, &handle);
461 // This code is a rather unfortunate consequence of the limitations
462 // in the ESP NVS API. As defined, there is no API for determining
463 // whether a particular key exists. Furthermore, calling one of the
464 // nvs_get_* APIs will result in a ESP_ERR_NVS_NOT_FOUND in the case
465 // where the key exists, but the requested data type does not match.
466 // (This is true despite the existence of the ESP_ERR_NVS_TYPE_MISMATCH
467 // error, which would seem to be the obvious correct response).
469 // Thus the solution is to exhaustively check for the key using
470 // each possible value type.
473 err = nvs_get_u8(handle, key.Name, &v);
475 if (err == ESP_ERR_NVS_NOT_FOUND)
478 err = nvs_get_i8(handle, key.Name, &v);
480 if (err == ESP_ERR_NVS_NOT_FOUND)
483 err = nvs_get_u16(handle, key.Name, &v);
485 if (err == ESP_ERR_NVS_NOT_FOUND)
488 err = nvs_get_i16(handle, key.Name, &v);
490 if (err == ESP_ERR_NVS_NOT_FOUND)
493 err = nvs_get_u32(handle, key.Name, &v);
495 if (err == ESP_ERR_NVS_NOT_FOUND)
498 err = nvs_get_i32(handle, key.Name, &v);
500 if (err == ESP_ERR_NVS_NOT_FOUND)
503 err = nvs_get_u64(handle, key.Name, &v);
505 if (err == ESP_ERR_NVS_NOT_FOUND)
508 err = nvs_get_i64(handle, key.Name, &v);
510 if (err == ESP_ERR_NVS_NOT_FOUND)
513 err = nvs_get_str(handle, key.Name, NULL, &sz);
515 if (err == ESP_ERR_NVS_NOT_FOUND)
518 err = nvs_get_blob(handle, key.Name, NULL, &sz);
521 // In the case of blob and string, ESP_ERR_NVS_INVALID_LENGTH means
523 if (err == ESP_ERR_NVS_INVALID_LENGTH)
533 return err == ESP_OK;
536 CHIP_ERROR ESP32Config::EnsureNamespace(const char * ns)
540 bool needClose = false;
542 err = nvs_open(ns, NVS_READONLY, &handle);
543 if (err == ESP_ERR_NVS_NOT_FOUND)
545 err = nvs_open(ns, NVS_READWRITE, &handle);
549 err = nvs_commit(handle);
563 CHIP_ERROR ESP32Config::ClearNamespace(const char * ns)
567 bool needClose = false;
569 err = nvs_open(ns, NVS_READWRITE, &handle);
573 err = nvs_erase_all(handle);
576 err = nvs_commit(handle);
587 void ESP32Config::RunConfigUnitTest() {}
589 } // namespace Internal
590 } // namespace DeviceLayer