Skip to main content

esp_storage/
storage.rs

1use crate::{FlashStorage, FlashStorageError, buffer::FlashSectorBuffer};
2
3impl FlashStorage<'_> {
4    /// Read bytes from flash.
5    ///
6    /// Unaligned offsets and lengths are supported.
7    ///
8    /// # Note
9    ///
10    /// This function always allocates a [`Self::SECTOR_SIZE`]-byte buffer on
11    /// the stack. See the
12    /// [crate-level documentation](crate#buffer-alignment-and-stack-usage).
13    ///
14    /// # Errors
15    ///
16    /// Returns [`FlashStorageError::OutOfBounds`] if the read would extend past
17    /// the end of the flash.
18    pub fn read(&mut self, offset: u32, mut bytes: &mut [u8]) -> Result<(), FlashStorageError> {
19        self.check_bounds(offset, bytes.len())?;
20
21        let mut data_offset = offset % Self::WORD_SIZE;
22        let mut aligned_offset = offset - data_offset;
23
24        // Bypass clearing sector buffer for performance reasons
25        let mut sector_data = FlashSectorBuffer::uninit();
26
27        while !bytes.is_empty() {
28            let len = bytes.len().min((Self::SECTOR_SIZE - data_offset) as _);
29
30            let aligned_end = (data_offset as usize + len + (Self::WORD_SIZE - 1) as usize)
31                & !(Self::WORD_SIZE - 1) as usize;
32
33            // Read only needed data words
34            let sector_data = &mut sector_data.as_bytes_mut()[..aligned_end];
35            self.internal_read(aligned_offset, sector_data)?;
36            let sector_data = unsafe {
37                core::slice::from_raw_parts_mut(sector_data.as_ptr() as *mut u8, sector_data.len())
38            };
39            bytes[..len].copy_from_slice(&sector_data[data_offset as usize..][..len]);
40
41            aligned_offset += Self::SECTOR_SIZE;
42            data_offset = 0;
43            bytes = &mut bytes[len..];
44        }
45
46        Ok(())
47    }
48
49    /// The SPI flash size is configured by writing a field in the software
50    /// bootloader image header. This is done during flashing in espflash /
51    /// esptool.
52    pub fn capacity(&self) -> usize {
53        self.capacity
54    }
55
56    /// Write bytes to flash.
57    ///
58    /// Performs read-modify-write on affected sectors and erases each sector
59    /// before writing. Unlike [`FlashStorage::write_nor`], alignment is not
60    /// required and erasure is handled automatically.
61    ///
62    /// # Note
63    ///
64    /// This function always allocates a [`Self::SECTOR_SIZE`]-byte buffer on
65    /// the stack. See the
66    /// [crate-level documentation](crate#buffer-alignment-and-stack-usage).
67    ///
68    /// # Errors
69    ///
70    /// Returns [`FlashStorageError::OutOfBounds`] if the write would extend past
71    /// the end of the flash.
72    pub fn write(&mut self, offset: u32, mut bytes: &[u8]) -> Result<(), FlashStorageError> {
73        self.check_bounds(offset, bytes.len())?;
74
75        let mut data_offset = offset % Self::SECTOR_SIZE;
76        let mut aligned_offset = offset - data_offset;
77
78        // Bypass clearing sector buffer for performance reasons
79        let mut sector_data = FlashSectorBuffer::uninit();
80
81        while !bytes.is_empty() {
82            self.internal_read(aligned_offset, sector_data.as_bytes_mut())?;
83            let sector_data = unsafe { sector_data.assume_init_bytes_mut() };
84
85            let len = bytes.len().min((Self::SECTOR_SIZE - data_offset) as _);
86
87            sector_data[data_offset as usize..][..len].copy_from_slice(&bytes[..len]);
88            self.internal_erase_sector(aligned_offset / Self::SECTOR_SIZE)?;
89            self.internal_write(aligned_offset, sector_data)?;
90
91            aligned_offset += Self::SECTOR_SIZE;
92            data_offset = 0;
93            bytes = &bytes[len..];
94        }
95
96        Ok(())
97    }
98}
99
100#[cfg(feature = "embedded-storage")]
101mod embedded_storage_traits {
102    use ::embedded_storage::{ReadStorage, Storage};
103
104    use super::*;
105
106    impl ReadStorage for FlashStorage<'_> {
107        type Error = FlashStorageError;
108
109        fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
110            FlashStorage::read(self, offset, bytes)
111        }
112
113        fn capacity(&self) -> usize {
114            FlashStorage::capacity(self)
115        }
116    }
117
118    impl Storage for FlashStorage<'_> {
119        fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
120            FlashStorage::write(self, offset, bytes)
121        }
122    }
123}