esp_partition_table/
norfl.rs1use crate::{
2 PartitionBuffer, PartitionEntry, PartitionError, PartitionReaderState, PartitionTable,
3 PartitionWriterState,
4};
5use core::{mem::MaybeUninit, ops::Deref};
6use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum NorFlashOpError<S: ReadNorFlash> {
11 PartitionError(PartitionError),
13 StorageError(S::Error),
15}
16
17impl<S: ReadNorFlash> From<PartitionError> for NorFlashOpError<S> {
18 fn from(error: PartitionError) -> Self {
19 Self::PartitionError(error)
20 }
21}
22
23impl PartitionTable {
24 pub fn iter_nor_flash<'s, S>(
28 &self,
29 storage: &'s mut S,
30 calc_md5: bool,
31 ) -> PartitionNorFlashIter<'s, S>
32 where
33 S: ReadNorFlash,
34 {
35 PartitionNorFlashIter {
36 storage,
37 state: PartitionReaderState::new(self.addr, self.size, calc_md5),
38 buffer: MaybeUninit::uninit(),
39 }
40 }
41
42 #[cfg(feature = "embedded-storage")]
51 pub fn read_nor_flash<S, T>(
52 &self,
53 storage: &mut S,
54 check_md5: Option<bool>,
55 ) -> Result<T, NorFlashOpError<S>>
56 where
57 S: ReadNorFlash,
58 T: FromIterator<PartitionEntry>,
59 {
60 let mut iter = self.iter_nor_flash(storage, check_md5.is_some());
61 let result = (&mut iter).collect::<Result<_, _>>()?;
62
63 #[cfg(feature = "md5")]
64 if let Some(mandatory_md5) = check_md5 {
65 if !iter.check_md5().unwrap_or(!mandatory_md5) {
66 return Err(PartitionError::InvalidMd5.into());
67 }
68 }
69
70 Ok(result)
71 }
72
73 #[cfg(feature = "embedded-storage")]
77 pub fn write_nor_flash<S>(
78 &self,
79 storage: &mut S,
80 partitions: impl IntoIterator<Item = impl AsRef<PartitionEntry>>,
81 write_md5: bool,
82 ) -> Result<usize, NorFlashOpError<S>>
83 where
84 S: NorFlash,
85 {
86 const SECTOR_SIZE: usize = PartitionTable::MAX_SIZE;
90
91 let mut sector_data = MaybeUninit::<[u8; SECTOR_SIZE]>::uninit();
92 let sector_data = unsafe { sector_data.assume_init_mut() };
93 let mut data = &mut sector_data[..];
94 let mut state = PartitionWriterState::new(self.addr, self.size, write_md5);
95
96 for partition in partitions {
97 if state.is_done() {
98 return Err(PartitionError::TooManyData.into());
99 }
100
101 let (head, rest) = data
102 .split_first_chunk_mut()
103 .ok_or(PartitionError::NotEnoughData)?;
104
105 state.write(head, partition)?;
106
107 data = rest;
108 }
109
110 #[cfg(feature = "md5")]
111 if write_md5 {
112 if state.is_done() {
113 return Err(PartitionError::TooManyData.into());
114 }
115
116 let (head, rest) = data
117 .split_first_chunk_mut()
118 .ok_or(PartitionError::NotEnoughData)?;
119
120 state.write_md5(head)?;
121
122 data = rest;
123 }
124
125 data.fill(0);
126
127 storage
128 .write(0, sector_data)
129 .map_err(NorFlashOpError::StorageError)?;
130
131 Ok((state.offset() - self.addr) as usize)
132 }
133}
134
135pub struct PartitionNorFlashIter<'s, S> {
137 storage: &'s mut S,
138 state: PartitionReaderState,
139 buffer: MaybeUninit<PartitionBuffer>,
140}
141
142impl<S> PartitionNorFlashIter<'_, S> {
143 pub fn next_partition(&mut self) -> Result<PartitionEntry, NorFlashOpError<S>>
145 where
146 S: ReadNorFlash,
147 {
148 if self.state.is_done() {
149 return Err(NorFlashOpError::PartitionError(
150 PartitionError::NotEnoughData,
151 ));
152 }
153
154 if let Err(error) = self.storage.read(self.state.offset(), unsafe {
156 self.buffer.assume_init_mut()
157 }) {
158 return Err(NorFlashOpError::StorageError(error));
159 }
160
161 self.state
162 .read(unsafe { self.buffer.assume_init_ref() })
163 .map_err(From::from)
164 }
165}
166
167impl<S> Deref for PartitionNorFlashIter<'_, S> {
168 type Target = PartitionReaderState;
169
170 fn deref(&self) -> &Self::Target {
171 &self.state
172 }
173}
174
175impl<S> Iterator for PartitionNorFlashIter<'_, S>
176where
177 S: ReadNorFlash,
178{
179 type Item = Result<PartitionEntry, NorFlashOpError<S>>;
180
181 fn next(&mut self) -> Option<Self::Item> {
182 self.next_partition()
183 .map(Some)
184 .or_else(|error| {
185 if matches!(
186 error,
187 NorFlashOpError::PartitionError(PartitionError::NotEnoughData)
188 ) {
189 Ok(None)
190 } else {
191 Err(error)
192 }
193 })
194 .transpose()
195 }
196}