Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / platform / ESP32 / ESP32Config.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2019-2020 Google LLC.
5  *    Copyright (c) 2018 Nest Labs, Inc.
6  *    All rights reserved.
7  *
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
11  *
12  *        http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  */
20
21 /**
22  *    @file
23  *          Utilities for interacting with the the ESP32 "NVS" key-value store.
24  */
25 /* this file behaves like a config.h, comes first */
26 #include <platform/internal/CHIPDeviceLayerInternal.h>
27
28 #include <platform/ESP32/ESP32Config.h>
29
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>
36
37 #include "nvs.h"
38 #include "nvs_flash.h"
39
40 namespace chip {
41 namespace DeviceLayer {
42 namespace Internal {
43
44 // *** CAUTION ***: Changing the names or namespaces of these values will *break* existing devices.
45
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";
50
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" };
61
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" };
75
76 // Prefix used for NVS keys that contain Chip group encryption keys.
77 const char ESP32Config::kGroupKeyNamePrefix[] = "gk-";
78
79 CHIP_ERROR ESP32Config::ReadConfigValue(Key key, bool & val)
80 {
81     CHIP_ERROR err;
82     nvs_handle handle;
83     bool needClose = false;
84     uint32_t intVal;
85
86     err = nvs_open(key.Namespace, NVS_READONLY, &handle);
87     SuccessOrExit(err);
88     needClose = true;
89
90     err = nvs_get_u32(handle, key.Name, &intVal);
91     if (err == ESP_ERR_NVS_NOT_FOUND)
92     {
93         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
94     }
95     SuccessOrExit(err);
96
97     val = (intVal != 0);
98
99 exit:
100     if (needClose)
101     {
102         nvs_close(handle);
103     }
104     return err;
105 }
106
107 CHIP_ERROR ESP32Config::ReadConfigValue(Key key, uint32_t & val)
108 {
109     CHIP_ERROR err;
110     nvs_handle handle;
111     bool needClose = false;
112
113     err = nvs_open(key.Namespace, NVS_READONLY, &handle);
114     SuccessOrExit(err);
115     needClose = true;
116
117     err = nvs_get_u32(handle, key.Name, &val);
118     if (err == ESP_ERR_NVS_NOT_FOUND)
119     {
120         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
121     }
122     SuccessOrExit(err);
123
124 exit:
125     if (needClose)
126     {
127         nvs_close(handle);
128     }
129     return err;
130 }
131
132 CHIP_ERROR ESP32Config::ReadConfigValue(Key key, uint64_t & val)
133 {
134     CHIP_ERROR err;
135     nvs_handle handle;
136     bool needClose = false;
137
138     err = nvs_open(key.Namespace, NVS_READONLY, &handle);
139     SuccessOrExit(err);
140     needClose = true;
141
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.
144     //
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.
149     //
150     if (key == kConfigKey_MfrDeviceId)
151     {
152         uint8_t deviceIdBytes[sizeof(uint64_t)];
153         size_t deviceIdLen = sizeof(deviceIdBytes);
154         err                = nvs_get_blob(handle, key.Name, deviceIdBytes, &deviceIdLen);
155         if (err == ESP_OK)
156         {
157             VerifyOrExit(deviceIdLen == sizeof(deviceIdBytes), err = ESP_ERR_NVS_INVALID_LENGTH);
158             val = Encoding::BigEndian::Get64(deviceIdBytes);
159             ExitNow();
160         }
161     }
162
163     err = nvs_get_u64(handle, key.Name, &val);
164     if (err == ESP_ERR_NVS_NOT_FOUND)
165     {
166         err = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
167     }
168     SuccessOrExit(err);
169
170 exit:
171     if (needClose)
172     {
173         nvs_close(handle);
174     }
175     return err;
176 }
177
178 CHIP_ERROR ESP32Config::ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen)
179 {
180     CHIP_ERROR err;
181     nvs_handle handle;
182     bool needClose = false;
183
184     err = nvs_open(key.Namespace, NVS_READONLY, &handle);
185     SuccessOrExit(err);
186     needClose = true;
187
188     outLen = bufSize;
189     err    = nvs_get_str(handle, key.Name, buf, &outLen);
190     if (err == ESP_ERR_NVS_NOT_FOUND)
191     {
192         outLen = 0;
193         err    = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
194     }
195     else if (err == ESP_ERR_NVS_INVALID_LENGTH)
196     {
197         err = (buf == NULL) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
198     }
199     SuccessOrExit(err);
200
201     outLen -= 1; // Don't count trailing nul.
202
203 exit:
204     if (needClose)
205     {
206         nvs_close(handle);
207     }
208
209     return err;
210 }
211
212 CHIP_ERROR ESP32Config::ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen)
213 {
214     CHIP_ERROR err;
215     nvs_handle handle;
216     bool needClose = false;
217
218     err = nvs_open(key.Namespace, NVS_READONLY, &handle);
219     SuccessOrExit(err);
220     needClose = true;
221
222     outLen = bufSize;
223     err    = nvs_get_blob(handle, key.Name, buf, &outLen);
224     if (err == ESP_ERR_NVS_NOT_FOUND)
225     {
226         outLen = 0;
227         err    = CHIP_DEVICE_ERROR_CONFIG_NOT_FOUND;
228     }
229     else if (err == ESP_ERR_NVS_INVALID_LENGTH)
230     {
231         err = (buf == NULL) ? CHIP_NO_ERROR : CHIP_ERROR_BUFFER_TOO_SMALL;
232     }
233     SuccessOrExit(err);
234
235 exit:
236     if (needClose)
237     {
238         nvs_close(handle);
239     }
240
241     return err;
242 }
243
244 CHIP_ERROR ESP32Config::WriteConfigValue(Key key, bool val)
245 {
246     CHIP_ERROR err;
247     nvs_handle handle;
248     bool needClose = false;
249
250     err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
251     SuccessOrExit(err);
252     needClose = true;
253
254     err = nvs_set_u32(handle, key.Name, val ? 1 : 0);
255     SuccessOrExit(err);
256
257     // Commit the value to the persistent store.
258     err = nvs_commit(handle);
259     SuccessOrExit(err);
260
261     ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %s", key.Namespace, key.Name, val ? "true" : "false");
262
263 exit:
264     if (needClose)
265     {
266         nvs_close(handle);
267     }
268
269     return err;
270 }
271
272 CHIP_ERROR ESP32Config::WriteConfigValue(Key key, uint32_t val)
273 {
274     CHIP_ERROR err;
275     nvs_handle handle;
276     bool needClose = false;
277
278     err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
279     SuccessOrExit(err);
280     needClose = true;
281
282     err = nvs_set_u32(handle, key.Name, val);
283     SuccessOrExit(err);
284
285     // Commit the value to the persistent store.
286     err = nvs_commit(handle);
287     SuccessOrExit(err);
288
289     ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu32 " (0x%" PRIX32 ")", key.Namespace, key.Name, val, val);
290
291 exit:
292     if (needClose)
293     {
294         nvs_close(handle);
295     }
296
297     return err;
298 }
299
300 CHIP_ERROR ESP32Config::WriteConfigValue(Key key, uint64_t val)
301 {
302     CHIP_ERROR err;
303     nvs_handle handle;
304     bool needClose = false;
305
306     err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
307     SuccessOrExit(err);
308     needClose = true;
309
310     err = nvs_set_u64(handle, key.Name, val);
311     SuccessOrExit(err);
312
313     // Commit the value to the persistent store.
314     err = nvs_commit(handle);
315     SuccessOrExit(err);
316
317     ChipLogProgress(DeviceLayer, "NVS set: %s/%s = %" PRIu64 " (0x%" PRIX64 ")", key.Namespace, key.Name, val, val);
318
319 exit:
320     if (needClose)
321     {
322         nvs_close(handle);
323     }
324
325     return err;
326 }
327
328 CHIP_ERROR ESP32Config::WriteConfigValueStr(Key key, const char * str)
329 {
330     CHIP_ERROR err;
331     nvs_handle handle;
332     bool needClose = false;
333
334     if (str != NULL)
335     {
336         err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
337         SuccessOrExit(err);
338         needClose = true;
339
340         err = nvs_set_str(handle, key.Name, str);
341         SuccessOrExit(err);
342
343         // Commit the value to the persistent store.
344         err = nvs_commit(handle);
345         SuccessOrExit(err);
346
347         ChipLogProgress(DeviceLayer, "NVS set: %s/%s = \"%s\"", key.Namespace, key.Name, str);
348     }
349
350     else
351     {
352         err = ClearConfigValue(key);
353         SuccessOrExit(err);
354     }
355
356 exit:
357     if (needClose)
358     {
359         nvs_close(handle);
360     }
361
362     return err;
363 }
364
365 CHIP_ERROR ESP32Config::WriteConfigValueStr(Key key, const char * str, size_t strLen)
366 {
367     CHIP_ERROR err;
368     chip::Platform::ScopedMemoryBuffer<char> strCopy;
369
370     if (str != NULL)
371     {
372         strCopy.Calloc(strLen + 1);
373         VerifyOrExit(strCopy, err = CHIP_ERROR_NO_MEMORY);
374         strncpy(strCopy.Get(), str, strLen);
375     }
376     err = ESP32Config::WriteConfigValueStr(key, strCopy.Get());
377
378 exit:
379     return err;
380 }
381
382 CHIP_ERROR ESP32Config::WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen)
383 {
384     CHIP_ERROR err;
385     nvs_handle handle;
386     bool needClose = false;
387
388     if (data != NULL)
389     {
390         err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
391         SuccessOrExit(err);
392         needClose = true;
393
394         err = nvs_set_blob(handle, key.Name, data, dataLen);
395         SuccessOrExit(err);
396
397         // Commit the value to the persistent store.
398         err = nvs_commit(handle);
399         SuccessOrExit(err);
400
401         ChipLogProgress(DeviceLayer, "NVS set: %s/%s = (blob length %" PRId32 ")", key.Namespace, key.Name, dataLen);
402     }
403
404     else
405     {
406         err = ClearConfigValue(key);
407         SuccessOrExit(err);
408     }
409
410 exit:
411     if (needClose)
412     {
413         nvs_close(handle);
414     }
415
416     return err;
417 }
418
419 CHIP_ERROR ESP32Config::ClearConfigValue(Key key)
420 {
421     CHIP_ERROR err;
422     nvs_handle handle;
423     bool needClose = false;
424
425     err = nvs_open(key.Namespace, NVS_READWRITE, &handle);
426     SuccessOrExit(err);
427     needClose = true;
428
429     err = nvs_erase_key(handle, key.Name);
430     if (err == ESP_ERR_NVS_NOT_FOUND)
431     {
432         ExitNow(err = CHIP_NO_ERROR);
433     }
434     SuccessOrExit(err);
435
436     // Commit the value to the persistent store.
437     err = nvs_commit(handle);
438     SuccessOrExit(err);
439
440     ChipLogProgress(DeviceLayer, "NVS erase: %s/%s", key.Namespace, key.Name);
441
442 exit:
443     if (needClose)
444     {
445         nvs_close(handle);
446     }
447
448     return err;
449 }
450
451 bool ESP32Config::ConfigValueExists(Key key)
452 {
453     CHIP_ERROR err;
454     nvs_handle handle;
455     bool needClose = false;
456
457     err = nvs_open(key.Namespace, NVS_READONLY, &handle);
458     SuccessOrExit(err);
459     needClose = true;
460
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).
468     //
469     // Thus the solution is to exhaustively check for the key using
470     // each possible value type.
471     {
472         uint8_t v;
473         err = nvs_get_u8(handle, key.Name, &v);
474     }
475     if (err == ESP_ERR_NVS_NOT_FOUND)
476     {
477         int8_t v;
478         err = nvs_get_i8(handle, key.Name, &v);
479     }
480     if (err == ESP_ERR_NVS_NOT_FOUND)
481     {
482         uint16_t v;
483         err = nvs_get_u16(handle, key.Name, &v);
484     }
485     if (err == ESP_ERR_NVS_NOT_FOUND)
486     {
487         int16_t v;
488         err = nvs_get_i16(handle, key.Name, &v);
489     }
490     if (err == ESP_ERR_NVS_NOT_FOUND)
491     {
492         uint32_t v;
493         err = nvs_get_u32(handle, key.Name, &v);
494     }
495     if (err == ESP_ERR_NVS_NOT_FOUND)
496     {
497         int32_t v;
498         err = nvs_get_i32(handle, key.Name, &v);
499     }
500     if (err == ESP_ERR_NVS_NOT_FOUND)
501     {
502         uint64_t v;
503         err = nvs_get_u64(handle, key.Name, &v);
504     }
505     if (err == ESP_ERR_NVS_NOT_FOUND)
506     {
507         int64_t v;
508         err = nvs_get_i64(handle, key.Name, &v);
509     }
510     if (err == ESP_ERR_NVS_NOT_FOUND)
511     {
512         size_t sz;
513         err = nvs_get_str(handle, key.Name, NULL, &sz);
514     }
515     if (err == ESP_ERR_NVS_NOT_FOUND)
516     {
517         size_t sz;
518         err = nvs_get_blob(handle, key.Name, NULL, &sz);
519     }
520
521     // In the case of blob and string, ESP_ERR_NVS_INVALID_LENGTH means
522     // the key exists.
523     if (err == ESP_ERR_NVS_INVALID_LENGTH)
524     {
525         err = ESP_OK;
526     }
527
528 exit:
529     if (needClose)
530     {
531         nvs_close(handle);
532     }
533     return err == ESP_OK;
534 }
535
536 CHIP_ERROR ESP32Config::EnsureNamespace(const char * ns)
537 {
538     CHIP_ERROR err;
539     nvs_handle handle;
540     bool needClose = false;
541
542     err = nvs_open(ns, NVS_READONLY, &handle);
543     if (err == ESP_ERR_NVS_NOT_FOUND)
544     {
545         err = nvs_open(ns, NVS_READWRITE, &handle);
546         SuccessOrExit(err);
547         needClose = true;
548
549         err = nvs_commit(handle);
550         SuccessOrExit(err);
551     }
552     SuccessOrExit(err);
553     needClose = true;
554
555 exit:
556     if (needClose)
557     {
558         nvs_close(handle);
559     }
560     return err;
561 }
562
563 CHIP_ERROR ESP32Config::ClearNamespace(const char * ns)
564 {
565     CHIP_ERROR err;
566     nvs_handle handle;
567     bool needClose = false;
568
569     err = nvs_open(ns, NVS_READWRITE, &handle);
570     SuccessOrExit(err);
571     needClose = true;
572
573     err = nvs_erase_all(handle);
574     SuccessOrExit(err);
575
576     err = nvs_commit(handle);
577     SuccessOrExit(err);
578
579 exit:
580     if (needClose)
581     {
582         nvs_close(handle);
583     }
584     return err;
585 }
586
587 void ESP32Config::RunConfigUnitTest() {}
588
589 } // namespace Internal
590 } // namespace DeviceLayer
591 } // namespace chip