1use core::{borrow::BorrowMut, ffi::CStr};
11
12use esp_idf_hal::sys::*;
13
14use crate::handle::RawHandle;
15
16#[cfg(feature = "embedded-storage")]
17pub use embedded_storage::{EspEncrypted, EspFlashError};
18
19#[non_exhaustive]
21#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
22pub enum EspPartitionType {
23 App(EspAppPartitionSubtype),
25 Data(EspDataPartitionSubtype),
27 Unknown,
29}
30
31impl EspPartitionType {
32 const fn raw(&self) -> (u32, u32) {
33 match self {
34 EspPartitionType::App(subtype) => {
35 let subtype = match subtype {
36 EspAppPartitionSubtype::Factory => {
37 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_FACTORY
38 }
39 EspAppPartitionSubtype::Test => {
40 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_TEST
41 }
42 EspAppPartitionSubtype::Ota(subtype) => {
43 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_OTA_MIN + *subtype as u32
44 }
45 EspAppPartitionSubtype::Unknown => {
46 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_ANY
47 }
48 };
49
50 (esp_partition_type_t_ESP_PARTITION_TYPE_APP, subtype)
51 }
52 EspPartitionType::Data(subtype) => {
53 let subtype = match subtype {
54 EspDataPartitionSubtype::Ota => {
55 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_OTA
56 }
57 EspDataPartitionSubtype::Phy => {
58 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_PHY
59 }
60 EspDataPartitionSubtype::Nvs => {
61 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_NVS
62 }
63 EspDataPartitionSubtype::Coredump => {
64 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_COREDUMP
65 }
66 EspDataPartitionSubtype::NvsKeys => {
67 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS
68 }
69 EspDataPartitionSubtype::Efuse => {
70 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM
71 }
72 EspDataPartitionSubtype::Undefined => {
73 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_UNDEFINED
74 }
75 EspDataPartitionSubtype::EspHttpd => {
76 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD
77 }
78 EspDataPartitionSubtype::Fat => {
79 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_FAT
80 }
81 EspDataPartitionSubtype::Spiffs => {
82 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_SPIFFS
83 }
84 _ => esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_ANY,
90 };
91
92 (esp_partition_type_t_ESP_PARTITION_TYPE_DATA, subtype)
93 }
94 EspPartitionType::Unknown => (
95 esp_partition_type_t_ESP_PARTITION_TYPE_ANY,
96 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_ANY,
97 ),
98 }
99 }
100}
101#[non_exhaustive]
103#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
104pub enum EspAppPartitionSubtype {
105 Factory,
107 Test,
109 Ota(u8),
111 Unknown,
113}
114
115#[non_exhaustive]
117#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
118pub enum EspDataPartitionSubtype {
119 Ota,
121 Phy,
123 Nvs,
125 Coredump,
127 NvsKeys,
129 Efuse,
131 Undefined,
133 EspHttpd,
135 Fat,
137 Spiffs,
139 Unknown,
143}
144
145#[cfg(not(esp_idf_version_major = "4"))]
147#[non_exhaustive]
148#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
149pub enum EspMemMapType {
150 Data,
152 Instruction,
154}
155
156#[cfg(not(esp_idf_version_major = "4"))]
160pub struct EspMemMappedPartition<'a> {
161 handle: esp_partition_mmap_handle_t,
162 start: usize,
163 _t: core::marker::PhantomData<&'a mut ()>,
164}
165
166#[cfg(not(esp_idf_version_major = "4"))]
167impl EspMemMappedPartition<'_> {
168 pub const fn start(&self) -> usize {
170 self.start
171 }
172}
173
174#[cfg(not(esp_idf_version_major = "4"))]
175impl Drop for EspMemMappedPartition<'_> {
176 fn drop(&mut self) {
177 unsafe {
178 esp_partition_munmap(self.handle);
179 }
180 }
181}
182
183pub struct EspPartitionIterator {
185 raw_iter: esp_partition_iterator_t,
186}
187
188impl EspPartitionIterator {
189 pub unsafe fn new(partition_type: Option<EspPartitionType>) -> Result<Self, EspError> {
197 let (partition_type, partition_subtype) = partition_type
198 .map(|partition_type| partition_type.raw())
199 .unwrap_or((
200 esp_partition_type_t_ESP_PARTITION_TYPE_ANY,
201 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_ANY,
202 ));
203
204 let raw_iter = esp_partition_find(partition_type, partition_subtype, core::ptr::null());
205
206 Ok(Self { raw_iter })
207 }
208
209 pub fn next_partition(&mut self) -> Option<EspPartition> {
211 if self.raw_iter.is_null() {
212 return None;
213 }
214
215 let partition = unsafe { esp_partition_get(self.raw_iter) };
216
217 let value = if partition.is_null() {
218 None
219 } else {
220 Some(unsafe { EspPartition::wrap(partition) })
221 };
222
223 self.raw_iter = unsafe { esp_partition_next(self.raw_iter) };
224
225 value
226 }
227}
228
229impl Drop for EspPartitionIterator {
230 fn drop(&mut self) {
231 unsafe {
232 esp_partition_iterator_release(self.raw_iter);
233 }
234 }
235}
236
237impl Iterator for EspPartitionIterator {
238 type Item = EspPartition;
239
240 fn next(&mut self) -> Option<Self::Item> {
241 self.next_partition()
242 }
243}
244
245#[repr(transparent)]
247pub struct EspPartition(*const esp_partition_t);
248
249impl EspPartition {
250 pub unsafe fn wrap(partition: *const esp_partition_t) -> Self {
256 Self(partition)
257 }
258
259 #[cfg(feature = "alloc")]
270 pub unsafe fn new(label: &str) -> Result<Option<Self>, EspError> {
271 let cstr = crate::private::cstr::to_cstring_arg(label)?;
272
273 Self::cnew(&cstr)
274 }
275
276 pub unsafe fn cnew(clabel: &CStr) -> Result<Option<Self>, EspError> {
287 let partition = esp_partition_find_first(
288 esp_partition_type_t_ESP_PARTITION_TYPE_ANY,
289 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_ANY,
290 clabel.as_ptr(),
291 );
292
293 if partition.is_null() {
294 Ok(None)
295 } else {
296 Ok(Some(Self(partition)))
297 }
298 }
299
300 pub unsafe fn find_first(partition_type: EspPartitionType) -> Result<Option<Self>, EspError> {
311 let (partition_type, partition_subtype) = partition_type.raw();
312
313 let partition =
314 esp_partition_find_first(partition_type, partition_subtype, core::ptr::null());
315
316 if partition.is_null() {
317 Ok(None)
318 } else {
319 Ok(Some(Self(partition)))
320 }
321 }
322
323 pub fn clabel(&self) -> &CStr {
325 unsafe { CStr::from_ptr((*self.0).label.as_ptr()) }
326 }
327
328 pub fn label(&self) -> &str {
330 self.clabel().to_str().unwrap()
331 }
332
333 #[allow(non_upper_case_globals)]
335 pub fn partition_type(&self) -> EspPartitionType {
336 match unsafe { (*self.0).type_ } {
337 esp_partition_type_t_ESP_PARTITION_TYPE_APP => {
338 EspPartitionType::App(match unsafe { (*self.0).subtype } {
339 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_FACTORY => {
340 EspAppPartitionSubtype::Factory
341 }
342 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_TEST => {
343 EspAppPartitionSubtype::Test
344 }
345 other => {
346 if (esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_OTA_MIN
347 ..=esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_OTA_MAX)
348 .contains(&other)
349 {
350 EspAppPartitionSubtype::Ota(
351 (other - esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_APP_OTA_MIN)
352 as _,
353 )
354 } else {
355 EspAppPartitionSubtype::Unknown
356 }
357 }
358 })
359 }
360 esp_partition_type_t_ESP_PARTITION_TYPE_DATA => {
361 EspPartitionType::Data(match unsafe { (*self.0).subtype } {
362 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_OTA => {
363 EspDataPartitionSubtype::Ota
364 }
365 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_PHY => {
366 EspDataPartitionSubtype::Phy
367 }
368 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_NVS => {
369 EspDataPartitionSubtype::Nvs
370 }
371 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_COREDUMP => {
372 EspDataPartitionSubtype::Coredump
373 }
374 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_NVS_KEYS => {
375 EspDataPartitionSubtype::NvsKeys
376 }
377 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM => {
378 EspDataPartitionSubtype::Efuse
379 }
380 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_UNDEFINED => {
381 EspDataPartitionSubtype::Undefined
382 }
383 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD => {
384 EspDataPartitionSubtype::EspHttpd
385 }
386 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_FAT => {
387 EspDataPartitionSubtype::Fat
388 }
389 esp_partition_subtype_t_ESP_PARTITION_SUBTYPE_DATA_SPIFFS => {
390 EspDataPartitionSubtype::Spiffs
391 }
392 _ => EspDataPartitionSubtype::Unknown,
397 })
398 }
399 _ => EspPartitionType::Unknown,
400 }
401 }
402
403 pub fn address(&self) -> usize {
405 unsafe { (*self.0).address as _ }
406 }
407
408 pub fn size(&self) -> usize {
410 unsafe { (*self.0).size as _ }
411 }
412
413 #[cfg(not(esp_idf_version_major = "4"))]
415 pub fn erase_size(&self) -> usize {
416 unsafe { (*self.0).erase_size as _ }
417 }
418
419 pub fn encrypted(&self) -> bool {
421 unsafe { (*self.0).encrypted }
422 }
423
424 #[cfg(any(
426 all(not(esp_idf_version_major = "4"), not(esp_idf_version_major = "5")),
427 all(
428 esp_idf_version_major = "5",
429 not(esp_idf_version_minor = "0"),
430 not(esp_idf_version_minor = "1"),
431 )
432 ))]
433 pub fn readonly(&self) -> bool {
434 unsafe { (*self.0).readonly }
435 }
436
437 pub fn read(&mut self, offset: usize, buf: &mut [u8]) -> Result<(), EspError> {
451 esp!(unsafe {
452 esp_partition_read(self.0, offset as _, buf.as_ptr() as *mut _, buf.len() as _)
453 })
454 }
455
456 pub fn write(&mut self, offset: usize, data: &[u8]) -> Result<(), EspError> {
470 esp!(unsafe {
471 esp_partition_write(
472 self.0,
473 offset as _,
474 data.as_ptr() as *const _,
475 data.len() as _,
476 )
477 })
478 }
479
480 pub fn erase(&mut self, offset: usize, size: usize) -> Result<(), EspError> {
493 esp!(unsafe { esp_partition_erase_range(self.0, offset as _, size as _) })
494 }
495
496 pub fn read_raw(&mut self, offset: usize, buf: &mut [u8]) -> Result<(), EspError> {
500 esp!(unsafe {
501 esp_partition_read_raw(self.0, offset as _, buf.as_ptr() as *mut _, buf.len() as _)
502 })
503 }
504
505 pub fn write_raw(&mut self, offset: usize, data: &[u8]) -> Result<(), EspError> {
509 esp!(unsafe {
510 esp_partition_write_raw(
511 self.0,
512 offset as _,
513 data.as_ptr() as *const _,
514 data.len() as _,
515 )
516 })
517 }
518
519 #[cfg(not(esp_idf_version_major = "4"))]
531 pub unsafe fn mmap(
532 &mut self,
533 offset: usize,
534 size: usize,
535 mmap_type: EspMemMapType,
536 ) -> Result<EspMemMappedPartition<'_>, EspError> {
537 let mut handle: esp_partition_mmap_handle_t = Default::default();
538 let mut out: *const core::ffi::c_void = core::ptr::null_mut();
539
540 esp!(esp_partition_mmap(
541 self.0,
542 offset as _,
543 size as _,
544 mmap_type as _,
545 &mut out,
546 &mut handle
547 ))?;
548
549 Ok(EspMemMappedPartition {
550 handle,
551 start: out as _,
552 _t: core::marker::PhantomData,
553 })
554 }
555}
556
557impl RawHandle for EspPartition {
558 type Handle = *const esp_partition_t;
559
560 fn handle(&self) -> Self::Handle {
561 self.0
562 }
563}
564
565unsafe impl Send for EspPartition {}
566
567pub struct EspWlPartition<T> {
569 _partition: T,
570 handle: wl_handle_t,
571}
572
573impl<T> EspWlPartition<T>
574where
575 T: BorrowMut<EspPartition>,
576{
577 pub fn new(mut partition: T) -> Result<Self, EspError> {
585 let mut handle: wl_handle_t = Default::default();
586
587 esp!(unsafe { wl_mount(partition.borrow_mut().0, &mut handle) })?;
588
589 Ok(Self {
590 _partition: partition,
591 handle,
592 })
593 }
594
595 pub fn size(&self) -> usize {
597 unsafe { wl_size(self.handle) as _ }
598 }
599
600 pub fn sector_size(&self) -> usize {
602 unsafe { wl_sector_size(self.handle) as _ }
603 }
604
605 pub fn read(&mut self, offset: usize, buf: &mut [u8]) -> Result<(), EspError> {
618 esp!(unsafe {
619 wl_read(
620 self.handle,
621 offset as _,
622 buf.as_ptr() as *mut _,
623 buf.len() as _,
624 )
625 })
626 }
627
628 pub fn write(&mut self, offset: usize, data: &[u8]) -> Result<(), EspError> {
641 esp!(unsafe {
642 wl_write(
643 self.handle,
644 offset as _,
645 data.as_ptr() as *const _,
646 data.len() as _,
647 )
648 })
649 }
650
651 pub fn erase(&mut self, offset: usize, size: usize) -> Result<(), EspError> {
661 esp!(unsafe { wl_erase_range(self.handle, offset as _, size as _) })
662 }
663}
664
665impl<T> RawHandle for EspWlPartition<T> {
666 type Handle = wl_handle_t;
667
668 fn handle(&self) -> Self::Handle {
669 self.handle
670 }
671}
672
673impl<T> Drop for EspWlPartition<T> {
674 fn drop(&mut self) {
675 esp!(unsafe { wl_unmount(self.handle) }).unwrap();
676 }
677}
678
679unsafe impl<T> Send for EspWlPartition<T> where T: Send {}
680
681#[cfg(feature = "embedded-storage")]
682mod embedded_storage {
683 use core::borrow::BorrowMut;
684 use core::fmt;
685
686 use embedded_storage::nor_flash::{
687 ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
688 };
689 use embedded_storage::ReadStorage;
690
691 use esp_idf_hal::sys::{EspError, ESP_ERR_INVALID_ARG, ESP_ERR_INVALID_SIZE};
692
693 use super::{EspPartition, EspWlPartition};
694
695 impl ReadStorage for EspPartition {
696 type Error = EspError;
697
698 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
699 EspPartition::read(self, offset as _, buf)
700 }
701
702 fn capacity(&self) -> usize {
703 self.size()
704 }
705 }
706
707 impl ErrorType for EspPartition {
708 type Error = EspFlashError;
709 }
710
711 impl ReadNorFlash for EspPartition {
712 const READ_SIZE: usize = 1;
713
714 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
715 EspPartition::read(self, offset as _, buf)?;
716
717 Ok(())
718 }
719
720 fn capacity(&self) -> usize {
721 self.size()
722 }
723 }
724
725 impl NorFlash for EspPartition {
726 const WRITE_SIZE: usize = 1;
727 const ERASE_SIZE: usize = 4096;
728
729 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
730 if to < from {
731 Err(EspFlashError(EspError::from_infallible::<
732 ESP_ERR_INVALID_SIZE,
733 >()))?;
734 }
735
736 EspPartition::erase(self, from as _, (to - from) as _)?;
737
738 Ok(())
739 }
740
741 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
742 EspPartition::write(self, offset as _, bytes)?;
743
744 Ok(())
745 }
746 }
747
748 impl MultiwriteNorFlash for EspPartition {}
749
750 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
751 pub struct EspFlashError(pub EspError);
752
753 impl From<EspError> for EspFlashError {
754 fn from(e: EspError) -> Self {
755 Self(e)
756 }
757 }
758
759 impl fmt::Display for EspFlashError {
760 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
761 self.0.fmt(f)
762 }
763 }
764
765 #[cfg(feature = "std")]
766 impl std::error::Error for EspFlashError {}
767
768 impl NorFlashError for EspFlashError {
769 fn kind(&self) -> NorFlashErrorKind {
770 match self.0.code() as _ {
771 ESP_ERR_INVALID_ARG => NorFlashErrorKind::NotAligned,
772 ESP_ERR_INVALID_SIZE => NorFlashErrorKind::OutOfBounds,
773 _ => NorFlashErrorKind::Other,
774 }
775 }
776 }
777
778 impl<T> ReadStorage for EspWlPartition<T>
779 where
780 T: BorrowMut<EspPartition>,
781 {
782 type Error = EspError;
783
784 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
785 EspWlPartition::read(self, offset as _, buf)
786 }
787
788 fn capacity(&self) -> usize {
789 self.size()
790 }
791 }
792
793 impl<T> ErrorType for EspWlPartition<T> {
794 type Error = EspFlashError;
795 }
796
797 impl<T> ReadNorFlash for EspWlPartition<T>
798 where
799 T: BorrowMut<EspPartition>,
800 {
801 const READ_SIZE: usize = 1;
802
803 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
804 EspWlPartition::read(self, offset as _, buf)?;
805
806 Ok(())
807 }
808
809 fn capacity(&self) -> usize {
810 self.size()
811 }
812 }
813
814 impl<T> NorFlash for EspWlPartition<T>
815 where
816 T: BorrowMut<EspPartition>,
817 {
818 const WRITE_SIZE: usize = 1;
819 const ERASE_SIZE: usize = 4096;
820
821 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
822 if to < from {
823 Err(EspFlashError(EspError::from_infallible::<
824 ESP_ERR_INVALID_SIZE,
825 >()))?;
826 }
827
828 EspWlPartition::erase(self, from as _, (to - from) as _)?;
829
830 Ok(())
831 }
832
833 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
834 EspWlPartition::write(self, offset as _, bytes)?;
835
836 Ok(())
837 }
838 }
839
840 impl<T> MultiwriteNorFlash for EspWlPartition<T> where T: BorrowMut<EspPartition> {}
841
842 pub struct EspEncrypted<T>(T);
848
849 impl<T> EspEncrypted<T> {
850 pub const fn new(partition: T) -> Self {
852 Self(partition)
853 }
854
855 pub fn release(self) -> T {
857 self.0
858 }
859 }
860
861 impl<T> ErrorType for EspEncrypted<T>
862 where
863 T: ErrorType,
864 {
865 type Error = T::Error;
866 }
867
868 impl<T> ReadStorage for EspEncrypted<T>
869 where
870 T: ReadStorage,
871 {
872 type Error = T::Error;
873
874 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
875 self.0.read(offset, buf)
876 }
877
878 fn capacity(&self) -> usize {
879 self.0.capacity()
880 }
881 }
882
883 impl<T> ReadNorFlash for EspEncrypted<T>
884 where
885 T: ReadNorFlash,
886 {
887 const READ_SIZE: usize = T::READ_SIZE;
888
889 fn read(&mut self, offset: u32, buf: &mut [u8]) -> Result<(), Self::Error> {
890 self.0.read(offset, buf)
891 }
892
893 fn capacity(&self) -> usize {
894 self.0.capacity()
895 }
896 }
897
898 impl<T> NorFlash for EspEncrypted<T>
899 where
900 T: NorFlash,
901 {
902 const WRITE_SIZE: usize = 16;
905
906 const ERASE_SIZE: usize = T::ERASE_SIZE;
907
908 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
909 self.0.erase(from, to)
910 }
911
912 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
913 self.0.write(offset, bytes)
914 }
915 }
916}