1#[cfg(esp_idf_version_at_least_5_2_0)]
3use core::marker::PhantomData;
4use core::ptr;
5
6extern crate alloc;
7use alloc::sync::Arc;
8
9use ::log::*;
10
11use embedded_svc::storage::{RawStorage, StorageBase};
12
13use crate::sys::*;
14
15use crate::handle::RawHandle;
16use crate::private::cstr::*;
17use crate::private::mutex;
18
19static DEFAULT_TAKEN: mutex::Mutex<bool> = mutex::Mutex::new(false);
20static NONDEFAULT_LOCKED: mutex::Mutex<alloc::collections::BTreeSet<CString>> =
21 mutex::Mutex::new(alloc::collections::BTreeSet::new());
22
23pub type EspDefaultNvsPartition = EspNvsPartition<NvsDefault>;
24pub type EspCustomNvsPartition = EspNvsPartition<NvsCustom>;
25pub type EspEncryptedNvsPartition = EspNvsPartition<NvsEncrypted>;
26
27pub trait NvsPartitionId {
28 fn is_default(&self) -> bool {
29 self.name().to_bytes().is_empty()
30 }
31
32 fn name(&self) -> &CStr;
33}
34
35pub struct NvsDefault(());
36
37#[repr(u32)]
38#[allow(non_upper_case_globals)]
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub enum NvsDataType {
41 U8 = nvs_type_t_NVS_TYPE_U8,
42 I8 = nvs_type_t_NVS_TYPE_I8,
43 U16 = nvs_type_t_NVS_TYPE_U16,
44 I16 = nvs_type_t_NVS_TYPE_I16,
45 U32 = nvs_type_t_NVS_TYPE_U32,
46 I32 = nvs_type_t_NVS_TYPE_I32,
47 U64 = nvs_type_t_NVS_TYPE_U64,
48 I64 = nvs_type_t_NVS_TYPE_I64,
49 Str = nvs_type_t_NVS_TYPE_STR,
50 Blob = nvs_type_t_NVS_TYPE_BLOB,
51}
52
53#[allow(non_upper_case_globals)]
54impl NvsDataType {
55 #[must_use]
57 pub fn from_nvs_type(nvs_type: nvs_type_t) -> Option<Self> {
58 match nvs_type {
59 nvs_type_t_NVS_TYPE_U8 => Some(Self::U8),
60 nvs_type_t_NVS_TYPE_I8 => Some(Self::I8),
61 nvs_type_t_NVS_TYPE_U16 => Some(Self::U16),
62 nvs_type_t_NVS_TYPE_I16 => Some(Self::I16),
63 nvs_type_t_NVS_TYPE_U32 => Some(Self::U32),
64 nvs_type_t_NVS_TYPE_I32 => Some(Self::I32),
65 nvs_type_t_NVS_TYPE_U64 => Some(Self::U64),
66 nvs_type_t_NVS_TYPE_I64 => Some(Self::I64),
67 nvs_type_t_NVS_TYPE_STR => Some(Self::Str),
68 nvs_type_t_NVS_TYPE_BLOB => Some(Self::Blob),
69 _ => None,
70 }
71 }
72}
73
74impl NvsDefault {
75 fn new(reinit: bool) -> Result<Self, EspError> {
76 let mut taken = DEFAULT_TAKEN.lock();
77
78 if *taken {
79 return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
80 }
81
82 let default_nvs = Self::init(reinit)?;
83
84 *taken = true;
85 Ok(default_nvs)
86 }
87
88 fn init(reinit: bool) -> Result<Self, EspError> {
89 if let Some(err) = EspError::from(unsafe { nvs_flash_init() }) {
90 match err.code() {
91 ESP_ERR_NVS_NO_FREE_PAGES | ESP_ERR_NVS_NEW_VERSION_FOUND if reinit => {
92 if err.code() == ESP_ERR_NVS_NEW_VERSION_FOUND {
93 warn!("NVS partition has a new version, erasing and re-initializing the partition");
94 } else {
95 warn!("NVS partition has no free pages, erasing and re-initializing the partition");
96 }
97
98 esp!(unsafe { nvs_flash_erase() })?;
99 esp!(unsafe { nvs_flash_init() })?;
100 }
101 _ => Err(err)?,
102 }
103 }
104
105 Ok(Self(()))
106 }
107}
108
109impl Drop for NvsDefault {
110 fn drop(&mut self) {
111 *DEFAULT_TAKEN.lock() = false;
113
114 info!("NvsDefault dropped");
115 }
116}
117
118impl NvsPartitionId for NvsDefault {
119 #[allow(clippy::manual_c_str_literals)]
120 fn name(&self) -> &CStr {
121 CStr::from_bytes_with_nul(b"\0").unwrap()
122 }
123}
124
125pub struct NvsCustom(CString);
126
127impl NvsCustom {
128 fn new(partition: &str) -> Result<Self, EspError> {
129 let mut registrations = NONDEFAULT_LOCKED.lock();
130
131 Self::init(partition, &mut registrations)
132 }
133
134 fn init(
135 partition: &str,
136 registrations: &mut alloc::collections::BTreeSet<CString>,
137 ) -> Result<Self, EspError> {
138 let c_partition = to_cstring_arg(partition)?;
139
140 if registrations.contains(c_partition.as_ref()) {
141 return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
142 }
143
144 unsafe {
145 if let Some(err) = EspError::from(nvs_flash_init_partition(c_partition.as_ptr())) {
146 match err.code() {
147 ESP_ERR_NVS_NO_FREE_PAGES | ESP_ERR_NVS_NEW_VERSION_FOUND => {
148 esp!(nvs_flash_erase_partition(c_partition.as_ptr()))?;
149 esp!(nvs_flash_init_partition(c_partition.as_ptr()))?;
150 }
151 _ => Err(err)?,
152 }
153 }
154 }
155
156 registrations.insert(c_partition.clone());
157
158 Ok(Self(c_partition))
159 }
160}
161
162impl Drop for NvsCustom {
163 fn drop(&mut self) {
164 {
165 let mut registrations = NONDEFAULT_LOCKED.lock();
166
167 esp!(unsafe { nvs_flash_deinit_partition(self.0.as_ptr()) }).unwrap();
168 registrations.remove(self.0.as_ref());
169 }
170
171 info!("NvsCustom dropped");
172 }
173}
174
175impl NvsPartitionId for NvsCustom {
176 fn name(&self) -> &CStr {
177 self.0.as_c_str()
178 }
179}
180pub struct NvsEncrypted(CString);
181
182impl NvsEncrypted {
183 fn new(partition: &str, key_partition: Option<&str>) -> Result<Self, EspError> {
184 let mut registrations = NONDEFAULT_LOCKED.lock();
185
186 Self::init(partition, key_partition, &mut registrations)
187 }
188
189 fn init(
190 partition: &str,
191 key_partition: Option<&str>,
192 registrations: &mut alloc::collections::BTreeSet<CString>,
193 ) -> Result<Self, EspError> {
194 let c_partition = to_cstring_arg(partition)?;
195
196 if registrations.contains(c_partition.as_ref()) {
197 return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
198 }
199
200 let c_key_partition = if let Some(key_partition) = key_partition {
201 Some(to_cstring_arg(key_partition)?)
202 } else {
203 None
204 };
205
206 let keys_partition_ptr = unsafe {
207 esp_partition_find_first(
208 esp_partition_type_t_ESP_PARTITION_TYPE_DATA,
209 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS,
210 match c_key_partition {
211 Some(ref v) => v.as_ptr(),
212 None => core::ptr::null(),
213 },
214 )
215 };
216
217 if keys_partition_ptr.is_null() {
218 warn!("No NVS keys partition found");
219 return Err(EspError::from_infallible::<ESP_FAIL>());
220 }
221
222 let mut config = nvs_sec_cfg_t::default();
223 match unsafe { nvs_flash_read_security_cfg(keys_partition_ptr, &mut config as *mut _) } {
224 ESP_ERR_NVS_KEYS_NOT_INITIALIZED | ESP_ERR_NVS_CORRUPT_KEY_PART => {
225 info!("Partition not initialized, generating keys");
226 esp!(unsafe {
227 nvs_flash_generate_keys(keys_partition_ptr, &mut config as *mut _)
228 })?;
229 }
230 other => esp!(other)?,
231 }
232
233 esp!(unsafe {
234 nvs_flash_secure_init_partition(c_partition.as_ptr(), &mut config as *mut _)
235 })?;
236
237 registrations.insert(c_partition.clone());
238
239 Ok(Self(c_partition))
240 }
241}
242
243impl Drop for NvsEncrypted {
245 fn drop(&mut self) {
246 {
247 let mut registrations = NONDEFAULT_LOCKED.lock();
248
249 esp!(unsafe { nvs_flash_deinit_partition(self.0.as_ptr()) }).unwrap();
250 registrations.remove(self.0.as_ref());
251 }
252
253 info!("NvsEncrypted dropped");
254 }
255}
256
257impl NvsPartitionId for NvsEncrypted {
258 fn name(&self) -> &CStr {
259 self.0.as_c_str()
260 }
261}
262
263#[derive(Debug)]
264pub struct EspNvsPartition<T: NvsPartitionId>(Arc<T>);
265
266impl EspNvsPartition<NvsDefault> {
267 pub fn take() -> Result<Self, EspError> {
269 Self::take_with(true)
270 }
271
272 pub fn take_with(reinit: bool) -> Result<Self, EspError> {
277 Ok(Self(Arc::new(NvsDefault::new(reinit)?)))
278 }
279}
280
281impl EspNvsPartition<NvsCustom> {
282 pub fn take(partition: &str) -> Result<Self, EspError> {
283 Ok(Self(Arc::new(NvsCustom::new(partition)?)))
284 }
285}
286
287impl EspNvsPartition<NvsEncrypted> {
288 pub fn take(partition: &str, keys_partition: Option<&str>) -> Result<Self, EspError> {
289 Ok(Self(Arc::new(NvsEncrypted::new(
290 partition,
291 keys_partition,
292 )?)))
293 }
294}
295
296impl<T> Clone for EspNvsPartition<T>
297where
298 T: NvsPartitionId,
299{
300 fn clone(&self) -> Self {
301 Self(self.0.clone())
302 }
303}
304
305impl RawHandle for EspNvsPartition<NvsCustom> {
306 type Handle = *const u8;
307
308 fn handle(&self) -> Self::Handle {
309 self.0.name().as_ptr() as *const _
310 }
311}
312
313impl RawHandle for EspNvsPartition<NvsEncrypted> {
314 type Handle = *const u8;
315
316 fn handle(&self) -> Self::Handle {
317 self.0.name().as_ptr() as *const _
318 }
319}
320
321pub type EspDefaultNvs = EspNvs<NvsDefault>;
322pub type EspCustomNvs = EspNvs<NvsCustom>;
323pub type EspEncryptedNvs = EspNvs<NvsEncrypted>;
324
325#[allow(dead_code)]
326pub struct EspNvs<T: NvsPartitionId>(EspNvsPartition<T>, nvs_handle_t);
327
328impl<T: NvsPartitionId> EspNvs<T> {
329 pub fn new(
330 partition: EspNvsPartition<T>,
331 namespace: &str,
332 read_write: bool,
333 ) -> Result<Self, EspError> {
334 let c_namespace = to_cstring_arg(namespace)?;
335
336 let mut handle: nvs_handle_t = 0;
337
338 if partition.0.is_default() {
339 esp!(unsafe {
340 nvs_open(
341 c_namespace.as_ptr(),
342 if read_write {
343 nvs_open_mode_t_NVS_READWRITE
344 } else {
345 nvs_open_mode_t_NVS_READONLY
346 },
347 &mut handle as *mut _,
348 )
349 })?;
350 } else {
351 esp!(unsafe {
352 nvs_open_from_partition(
353 partition.0.name().as_ptr(),
354 c_namespace.as_ptr(),
355 if read_write {
356 nvs_open_mode_t_NVS_READWRITE
357 } else {
358 nvs_open_mode_t_NVS_READONLY
359 },
360 &mut handle as *mut _,
361 )
362 })?;
363 }
364
365 Ok(Self(partition, handle))
366 }
367
368 #[cfg(all(
369 not(esp_idf_version_major = "4"),
370 not(all(esp_idf_version_major = "5", esp_idf_version_minor = "1"))
371 ))]
372 pub fn find_key(&self, name: &str) -> Result<Option<NvsDataType>, EspError> {
373 let c_key = to_cstring_arg(name)?;
374 let mut entry_type: nvs_type_t = nvs_type_t_NVS_TYPE_ANY;
375
376 let result = unsafe { nvs_find_key(self.1, c_key.as_ptr(), &mut entry_type as *mut _) };
377
378 match result {
379 ESP_OK => Ok(NvsDataType::from_nvs_type(entry_type)),
380 ESP_ERR_NVS_NOT_FOUND => Ok(None),
381 err => {
382 esp!(err)?;
383 Ok(None)
384 }
385 }
386 }
387
388 pub fn remove(&self, name: &str) -> Result<bool, EspError> {
389 let c_key = to_cstring_arg(name)?;
390
391 let result = unsafe { nvs_erase_key(self.1, c_key.as_ptr()) };
393
394 if result == ESP_ERR_NVS_NOT_FOUND {
395 Ok(false)
396 } else {
397 esp!(result)?;
398 esp!(unsafe { nvs_commit(self.1) })?;
399
400 Ok(true)
401 }
402 }
403
404 pub fn blob_len(&self, name: &str) -> Result<Option<usize>, EspError> {
413 let c_key = to_cstring_arg(name)?;
414
415 #[allow(unused_assignments)]
416 let mut len = 0;
417
418 match unsafe { nvs_get_blob(self.1, c_key.as_ptr(), ptr::null_mut(), &mut len as *mut _) } {
419 ESP_ERR_NVS_NOT_FOUND => Ok(None),
420 err => {
421 esp!(err)?;
423
424 Ok(Some(len))
425 }
426 }
427 }
428
429 pub fn get_blob<'a>(
430 &self,
431 name: &str,
432 buf: &'a mut [u8],
433 ) -> Result<Option<&'a [u8]>, EspError> {
434 let c_key = to_cstring_arg(name)?;
435 let mut len = buf.len();
436
437 match unsafe {
438 nvs_get_blob(
439 self.1,
440 c_key.as_ptr(),
441 buf.as_mut_ptr() as *mut _,
442 &mut len as *mut _,
443 )
444 } {
445 ESP_ERR_NVS_NOT_FOUND => Ok(None),
446 err => {
447 esp!(err)?;
449
450 Ok(Some(&buf[..len]))
451 }
452 }
453 }
454
455 pub fn set_blob(&self, name: &str, buf: &[u8]) -> Result<(), EspError> {
456 let c_key = to_cstring_arg(name)?;
457
458 unsafe { nvs_erase_key(self.1, c_key.as_ptr()) };
460
461 esp!(unsafe { nvs_set_blob(self.1, c_key.as_ptr(), buf.as_ptr().cast(), buf.len()) })?;
462
463 esp!(unsafe { nvs_commit(self.1) })?;
464
465 Ok(())
466 }
467
468 pub fn str_len(&self, name: &str) -> Result<Option<usize>, EspError> {
486 let c_key = to_cstring_arg(name)?;
487
488 #[allow(unused_assignments)]
489 let mut len = 0;
490
491 match unsafe { nvs_get_str(self.1, c_key.as_ptr(), ptr::null_mut(), &mut len as *mut _) } {
492 ESP_ERR_NVS_NOT_FOUND => Ok(None),
493 err => {
494 esp!(err)?;
496
497 Ok(Some(len))
498 }
499 }
500 }
501
502 pub fn get_str<'a>(&self, name: &str, buf: &'a mut [u8]) -> Result<Option<&'a str>, EspError> {
503 let c_key = to_cstring_arg(name)?;
504
505 let mut len = buf.len();
506 match unsafe {
507 nvs_get_str(
508 self.1,
509 c_key.as_ptr(),
510 buf.as_mut_ptr() as *mut _,
511 &mut len as *mut _,
512 )
513 } {
514 ESP_ERR_NVS_NOT_FOUND => Ok(None),
515 err => {
516 esp!(err)?;
518
519 Ok(Some(unsafe {
520 core::str::from_utf8_unchecked(&(buf[..len - 1]))
521 }))
522 }
523 }
524 }
525
526 pub fn set_str(&self, name: &str, val: &str) -> Result<(), EspError> {
527 let c_key = to_cstring_arg(name)?;
528 let c_val = to_cstring_arg(val)?;
529
530 unsafe { nvs_erase_key(self.1, c_key.as_ptr()) };
532
533 esp!(unsafe { nvs_set_str(self.1, c_key.as_ptr(), c_val.as_ptr(),) })?;
534
535 esp!(unsafe { nvs_commit(self.1) })?;
536
537 Ok(())
538 }
539
540 pub fn get_u8(&self, name: &str) -> Result<Option<u8>, EspError> {
541 let c_key = to_cstring_arg(name)?;
542 let mut result: [u8; 1] = [0; 1];
543
544 match unsafe { nvs_get_u8(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
545 ESP_ERR_NVS_NOT_FOUND => Ok(None),
546 err => {
547 esp!(err)?;
549
550 Ok(Some(result[0]))
551 }
552 }
553 }
554
555 pub fn set_u8(&self, name: &str, val: u8) -> Result<(), EspError> {
556 let c_key = to_cstring_arg(name)?;
557
558 esp!(unsafe { nvs_set_u8(self.1, c_key.as_ptr(), val) })?;
559
560 esp!(unsafe { nvs_commit(self.1) })?;
561
562 Ok(())
563 }
564
565 pub fn get_i8(&self, name: &str) -> Result<Option<i8>, EspError> {
566 let c_key = to_cstring_arg(name)?;
567 let mut result: [i8; 1] = [0; 1];
568
569 match unsafe { nvs_get_i8(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
570 ESP_ERR_NVS_NOT_FOUND => Ok(None),
571 err => {
572 esp!(err)?;
574
575 Ok(Some(result[0]))
576 }
577 }
578 }
579
580 pub fn set_i8(&self, name: &str, val: i8) -> Result<(), EspError> {
581 let c_key = to_cstring_arg(name)?;
582
583 esp!(unsafe { nvs_set_i8(self.1, c_key.as_ptr(), val) })?;
584
585 esp!(unsafe { nvs_commit(self.1) })?;
586
587 Ok(())
588 }
589
590 pub fn get_u16(&self, name: &str) -> Result<Option<u16>, EspError> {
591 let c_key = to_cstring_arg(name)?;
592 let mut result: [u16; 1] = [0; 1];
593
594 match unsafe { nvs_get_u16(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
595 ESP_ERR_NVS_NOT_FOUND => Ok(None),
596 err => {
597 esp!(err)?;
599
600 Ok(Some(result[0]))
601 }
602 }
603 }
604
605 pub fn set_u16(&self, name: &str, val: u16) -> Result<(), EspError> {
606 let c_key = to_cstring_arg(name)?;
607
608 esp!(unsafe { nvs_set_u16(self.1, c_key.as_ptr(), val) })?;
609
610 esp!(unsafe { nvs_commit(self.1) })?;
611
612 Ok(())
613 }
614
615 pub fn get_i16(&self, name: &str) -> Result<Option<i16>, EspError> {
616 let c_key = to_cstring_arg(name)?;
617 let mut result: [i16; 1] = [0; 1];
618
619 match unsafe { nvs_get_i16(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
620 ESP_ERR_NVS_NOT_FOUND => Ok(None),
621 err => {
622 esp!(err)?;
624
625 Ok(Some(result[0]))
626 }
627 }
628 }
629
630 pub fn set_i16(&self, name: &str, val: i16) -> Result<(), EspError> {
631 let c_key = to_cstring_arg(name)?;
632
633 esp!(unsafe { nvs_set_i16(self.1, c_key.as_ptr(), val) })?;
634
635 esp!(unsafe { nvs_commit(self.1) })?;
636
637 Ok(())
638 }
639
640 pub fn get_u32(&self, name: &str) -> Result<Option<u32>, EspError> {
641 let c_key = to_cstring_arg(name)?;
642 let mut result: [u32; 1] = [0; 1];
643
644 match unsafe { nvs_get_u32(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
645 ESP_ERR_NVS_NOT_FOUND => Ok(None),
646 err => {
647 esp!(err)?;
649
650 Ok(Some(result[0]))
651 }
652 }
653 }
654
655 pub fn set_u32(&self, name: &str, val: u32) -> Result<(), EspError> {
656 let c_key = to_cstring_arg(name)?;
657
658 esp!(unsafe { nvs_set_u32(self.1, c_key.as_ptr(), val) })?;
659
660 esp!(unsafe { nvs_commit(self.1) })?;
661
662 Ok(())
663 }
664
665 pub fn get_i32(&self, name: &str) -> Result<Option<i32>, EspError> {
666 let c_key = to_cstring_arg(name)?;
667 let mut result: [i32; 1] = [0; 1];
668
669 match unsafe { nvs_get_i32(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
670 ESP_ERR_NVS_NOT_FOUND => Ok(None),
671 err => {
672 esp!(err)?;
674
675 Ok(Some(result[0]))
676 }
677 }
678 }
679
680 pub fn set_i32(&self, name: &str, val: i32) -> Result<(), EspError> {
681 let c_key = to_cstring_arg(name)?;
682
683 esp!(unsafe { nvs_set_i32(self.1, c_key.as_ptr(), val) })?;
684
685 esp!(unsafe { nvs_commit(self.1) })?;
686
687 Ok(())
688 }
689
690 pub fn get_u64(&self, name: &str) -> Result<Option<u64>, EspError> {
691 let c_key = to_cstring_arg(name)?;
692 let mut result: [u64; 1] = [0; 1];
693
694 match unsafe { nvs_get_u64(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
695 ESP_ERR_NVS_NOT_FOUND => Ok(None),
696 err => {
697 esp!(err)?;
699
700 Ok(Some(result[0]))
701 }
702 }
703 }
704
705 pub fn set_u64(&self, name: &str, val: u64) -> Result<(), EspError> {
706 let c_key = to_cstring_arg(name)?;
707
708 esp!(unsafe { nvs_set_u64(self.1, c_key.as_ptr(), val) })?;
709
710 esp!(unsafe { nvs_commit(self.1) })?;
711
712 Ok(())
713 }
714
715 pub fn get_i64(&self, name: &str) -> Result<Option<i64>, EspError> {
716 let c_key = to_cstring_arg(name)?;
717 let mut result: [i64; 1] = [0; 1];
718
719 match unsafe { nvs_get_i64(self.1, c_key.as_ptr(), &mut result[0] as *mut _) } {
720 ESP_ERR_NVS_NOT_FOUND => Ok(None),
721 err => {
722 esp!(err)?;
724
725 Ok(Some(result[0]))
726 }
727 }
728 }
729
730 pub fn set_i64(&self, name: &str, val: i64) -> Result<(), EspError> {
731 let c_key = to_cstring_arg(name)?;
732
733 esp!(unsafe { nvs_set_i64(self.1, c_key.as_ptr(), val) })?;
734
735 esp!(unsafe { nvs_commit(self.1) })?;
736
737 Ok(())
738 }
739
740 pub fn erase_all(&self) -> Result<(), EspError> {
749 esp!(unsafe { nvs_erase_all(self.1) })?;
750
751 esp!(unsafe { nvs_commit(self.1) })?;
752
753 Ok(())
754 }
755
756 #[cfg(esp_idf_version_at_least_5_2_0)]
775 pub fn keys(&self, data_type: Option<NvsDataType>) -> Result<EspNvsKeys<'_>, EspError> {
776 let mut raw_iter: nvs_iterator_t = core::ptr::null_mut();
777
778 match unsafe {
779 nvs_entry_find_in_handle(
780 self.1,
781 data_type
782 .map(|ty| ty as u32)
783 .unwrap_or(nvs_type_t_NVS_TYPE_ANY),
784 &mut raw_iter as *mut _,
785 )
786 } {
787 ESP_ERR_NVS_NOT_FOUND => {
788 return Ok(EspNvsKeys {
789 _nvs: PhantomData,
790 raw_iter: core::ptr::null_mut(),
791 is_exhausted: true,
792 key_name_buffer: [0; 16],
793 });
794 }
795 other => esp!(other)?,
796 }
797
798 Ok(EspNvsKeys {
799 _nvs: PhantomData,
800 raw_iter,
801 is_exhausted: false,
802 key_name_buffer: [0; 16],
803 })
804 }
805}
806
807impl<T: NvsPartitionId> Drop for EspNvs<T> {
808 fn drop(&mut self) {
809 unsafe {
810 nvs_close(self.1);
811 }
812
813 info!("EspNvs dropped");
814 }
815}
816
817unsafe impl<T: NvsPartitionId> Send for EspNvs<T> {}
818
819impl RawHandle for EspNvs<NvsCustom> {
820 type Handle = nvs_handle_t;
821
822 fn handle(&self) -> Self::Handle {
823 self.1
824 }
825}
826impl RawHandle for EspNvs<NvsEncrypted> {
827 type Handle = nvs_handle_t;
828
829 fn handle(&self) -> Self::Handle {
830 self.1
831 }
832}
833impl RawHandle for EspNvs<NvsDefault> {
834 type Handle = nvs_handle_t;
835
836 fn handle(&self) -> Self::Handle {
837 self.1
838 }
839}
840
841#[cfg(esp_idf_version_at_least_5_2_0)]
842pub struct EspNvsKeys<'a> {
843 _nvs: PhantomData<&'a ()>,
846 raw_iter: nvs_iterator_t,
847 is_exhausted: bool,
848 key_name_buffer: [u8; 16],
849}
850
851#[cfg(esp_idf_version_at_least_5_2_0)]
852impl<'a> EspNvsKeys<'a> {
853 pub fn next_key(&mut self) -> Option<(&str, NvsDataType)> {
857 if self.is_exhausted || self.raw_iter.is_null() {
858 return None;
859 }
860
861 let mut info: nvs_entry_info_t = Default::default();
862 match unsafe { nvs_entry_info(self.raw_iter, &mut info as *mut _) } {
863 ESP_ERR_NVS_NOT_FOUND => {
864 self.is_exhausted = true;
865 None
866 }
867 ESP_OK => {
868 let _ = esp!(unsafe { nvs_entry_next(&mut self.raw_iter as *mut _) });
879
880 self.key_name_buffer[..info.key.len()].copy_from_slice(&info.key[..]);
883
884 Some((
885 from_cstr(&self.key_name_buffer[..info.key.len()]),
886 NvsDataType::from_nvs_type(info.type_).expect("Unknown NVS data type"),
887 ))
888 }
889 err => unreachable!(
894 "Unexpected error while iterating over NVS entries: {:?}",
895 esp!(err)
896 ),
897 }
898 }
899}
900
901#[cfg(esp_idf_version_at_least_5_2_0)]
902impl<'a> Drop for EspNvsKeys<'a> {
903 fn drop(&mut self) {
904 unsafe { nvs_release_iterator(self.raw_iter) };
905 }
906}
907
908pub struct EspKeyValueStorage<T: NvsPartitionId>(EspNvs<T>);
943
944impl<T: NvsPartitionId> EspKeyValueStorage<T> {
945 pub const fn new(nvs: EspNvs<T>) -> Self {
946 Self(nvs)
947 }
948
949 pub fn contains(&self, name: &str) -> Result<bool, EspError> {
950 self.len(name).map(|v| v.is_some())
951 }
952
953 pub fn remove(&self, name: &str) -> Result<bool, EspError> {
954 self.0.remove(name)
955 }
956
957 fn len(&self, name: &str) -> Result<Option<usize>, EspError> {
958 match self.0.get_u64(name)? {
959 Some(value) => {
960 let len: u8 = (value & 0xff) as u8;
962 Ok(Some(len as _))
963 }
964 None => self.0.blob_len(name),
965 }
966 }
967
968 pub fn get_raw<'a>(&self, name: &str, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, EspError> {
969 match self.0.get_u64(name)? {
970 Some(mut value) => {
971 let len: u8 = (value & 0xff) as u8;
973
974 if buf.len() < len as _ {
975 return Err(EspError::from_infallible::<ESP_ERR_NVS_INVALID_LENGTH>());
976 }
977
978 value >>= 8;
980
981 let array: [u8; 7] = [
982 (value & 0xff) as u8,
983 ((value >> 8) & 0xff) as u8,
984 ((value >> 16) & 0xff) as u8,
985 ((value >> 24) & 0xff) as u8,
986 ((value >> 32) & 0xff) as u8,
987 ((value >> 40) & 0xff) as u8,
988 ((value >> 48) & 0xff) as u8,
989 ];
990
991 buf[..len as usize].copy_from_slice(&array[..len as usize]);
992
993 Ok(Some(&buf[..len as usize]))
994 }
995 None => self.0.get_blob(name, buf),
996 }
997 }
998
999 pub fn set_raw(&self, name: &str, buf: &[u8]) -> Result<bool, EspError> {
1000 _ = self.0.remove(name);
1005
1006 if buf.len() < 8 {
1007 let mut u64value: u_int64_t = 0;
1008
1009 for v in buf.iter().rev() {
1010 u64value <<= 8;
1011 u64value |= *v as u_int64_t;
1012 }
1013
1014 u64value <<= 8;
1015 u64value |= buf.len() as u_int64_t;
1016
1017 self.0.set_u64(name, u64value)?;
1018 Ok(true)
1019 } else {
1020 self.0.set_blob(name, buf)?;
1021 Ok(true)
1022 }
1023 }
1024}
1025
1026impl<T: NvsPartitionId> StorageBase for EspKeyValueStorage<T> {
1027 type Error = EspError;
1028
1029 fn contains(&self, name: &str) -> Result<bool, Self::Error> {
1030 EspKeyValueStorage::contains(self, name)
1031 }
1032
1033 fn remove(&mut self, name: &str) -> Result<bool, Self::Error> {
1034 EspKeyValueStorage::remove(self, name)
1035 }
1036}
1037
1038impl<T: NvsPartitionId> RawStorage for EspKeyValueStorage<T> {
1039 fn len(&self, name: &str) -> Result<Option<usize>, Self::Error> {
1040 EspKeyValueStorage::len(self, name)
1041 }
1042
1043 fn get_raw<'a>(&self, name: &str, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Self::Error> {
1044 EspKeyValueStorage::get_raw(self, name, buf)
1045 }
1046
1047 fn set_raw(&mut self, name: &str, buf: &[u8]) -> Result<bool, Self::Error> {
1048 EspKeyValueStorage::set_raw(self, name, buf)
1049 }
1050}