esp_storage/
storage.rs

1use embedded_storage::{ReadStorage, Storage};
2
3use crate::{FlashStorage, FlashStorageError, buffer::FlashSectorBuffer};
4
5impl ReadStorage for FlashStorage {
6    type Error = FlashStorageError;
7
8    fn read(&mut self, offset: u32, mut bytes: &mut [u8]) -> Result<(), Self::Error> {
9        self.check_bounds(offset, bytes.len())?;
10
11        let mut data_offset = offset % Self::WORD_SIZE;
12        let mut aligned_offset = offset - data_offset;
13
14        // Bypass clearing sector buffer for performance reasons
15        let mut sector_data = FlashSectorBuffer::uninit();
16
17        while !bytes.is_empty() {
18            let len = bytes.len().min((Self::SECTOR_SIZE - data_offset) as _);
19
20            let aligned_end = (data_offset as usize + len + (Self::WORD_SIZE - 1) as usize)
21                & !(Self::WORD_SIZE - 1) as usize;
22
23            // Read only needed data words
24            let sector_data = &mut sector_data.as_bytes_mut()[..aligned_end];
25            self.internal_read(aligned_offset, sector_data)?;
26            let sector_data = unsafe {
27                core::slice::from_raw_parts_mut(sector_data.as_ptr() as *mut u8, sector_data.len())
28            };
29            bytes[..len].copy_from_slice(&sector_data[data_offset as usize..][..len]);
30
31            aligned_offset += Self::SECTOR_SIZE;
32            data_offset = 0;
33            bytes = &mut bytes[len..];
34        }
35
36        Ok(())
37    }
38
39    /// The SPI flash size is configured by writing a field in the software
40    /// bootloader image header. This is done during flashing in espflash /
41    /// esptool.
42    fn capacity(&self) -> usize {
43        self.capacity
44    }
45}
46
47impl Storage for FlashStorage {
48    fn write(&mut self, offset: u32, mut bytes: &[u8]) -> Result<(), Self::Error> {
49        self.check_bounds(offset, bytes.len())?;
50
51        let mut data_offset = offset % Self::SECTOR_SIZE;
52        let mut aligned_offset = offset - data_offset;
53
54        // Bypass clearing sector buffer for performance reasons
55        let mut sector_data = FlashSectorBuffer::uninit();
56
57        while !bytes.is_empty() {
58            self.internal_read(aligned_offset, sector_data.as_bytes_mut())?;
59            let sector_data = unsafe { sector_data.assume_init_bytes_mut() };
60
61            let len = bytes.len().min((Self::SECTOR_SIZE - data_offset) as _);
62
63            sector_data[data_offset as usize..][..len].copy_from_slice(&bytes[..len]);
64            self.internal_erase(aligned_offset / Self::SECTOR_SIZE)?;
65            self.internal_write(aligned_offset, sector_data)?;
66
67            aligned_offset += Self::SECTOR_SIZE;
68            data_offset = 0;
69            bytes = &bytes[len..];
70        }
71
72        Ok(())
73    }
74}