embassy_embedded_hal/flash/
concat_flash.rs1use embedded_storage::nor_flash::{ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, ReadNorFlash};
2use embedded_storage_async::nor_flash::{
3 MultiwriteNorFlash as AsyncMultiwriteNorFlash, NorFlash as AsyncNorFlash, ReadNorFlash as AsyncReadNorFlash,
4};
5
6pub struct ConcatFlash<First, Second>(First, Second);
10
11impl<First, Second> ConcatFlash<First, Second> {
12 pub fn new(first: First, second: Second) -> Self {
14 Self(first, second)
15 }
16}
17
18const fn get_read_size(first_read_size: usize, second_read_size: usize) -> usize {
19 if first_read_size != second_read_size {
20 panic!("The read size for the concatenated flashes must be the same");
21 }
22 first_read_size
23}
24
25const fn get_write_size(first_write_size: usize, second_write_size: usize) -> usize {
26 if first_write_size != second_write_size {
27 panic!("The write size for the concatenated flashes must be the same");
28 }
29 first_write_size
30}
31
32const fn get_max_erase_size(first_erase_size: usize, second_erase_size: usize) -> usize {
33 let max_erase_size = if first_erase_size > second_erase_size {
34 first_erase_size
35 } else {
36 second_erase_size
37 };
38 if max_erase_size % first_erase_size != 0 || max_erase_size % second_erase_size != 0 {
39 panic!("The erase sizes for the concatenated flashes must have have a gcd equal to the max erase size");
40 }
41 max_erase_size
42}
43
44impl<First, Second, E> ErrorType for ConcatFlash<First, Second>
45where
46 First: ErrorType<Error = E>,
47 Second: ErrorType<Error = E>,
48 E: NorFlashError,
49{
50 type Error = E;
51}
52
53impl<First, Second, E> ReadNorFlash for ConcatFlash<First, Second>
54where
55 First: ReadNorFlash<Error = E>,
56 Second: ReadNorFlash<Error = E>,
57 E: NorFlashError,
58{
59 const READ_SIZE: usize = get_read_size(First::READ_SIZE, Second::READ_SIZE);
60
61 fn read(&mut self, mut offset: u32, mut bytes: &mut [u8]) -> Result<(), E> {
62 if offset < self.0.capacity() as u32 {
63 let len = core::cmp::min(self.0.capacity() - offset as usize, bytes.len());
64 self.0.read(offset, &mut bytes[..len])?;
65 offset += len as u32;
66 bytes = &mut bytes[len..];
67 }
68
69 if !bytes.is_empty() {
70 self.1.read(offset - self.0.capacity() as u32, bytes)?;
71 }
72
73 Ok(())
74 }
75
76 fn capacity(&self) -> usize {
77 self.0.capacity() + self.1.capacity()
78 }
79}
80
81impl<First, Second, E> NorFlash for ConcatFlash<First, Second>
82where
83 First: NorFlash<Error = E>,
84 Second: NorFlash<Error = E>,
85 E: NorFlashError,
86{
87 const WRITE_SIZE: usize = get_write_size(First::WRITE_SIZE, Second::WRITE_SIZE);
88 const ERASE_SIZE: usize = get_max_erase_size(First::ERASE_SIZE, Second::ERASE_SIZE);
89
90 fn write(&mut self, mut offset: u32, mut bytes: &[u8]) -> Result<(), E> {
91 if offset < self.0.capacity() as u32 {
92 let len = core::cmp::min(self.0.capacity() - offset as usize, bytes.len());
93 self.0.write(offset, &bytes[..len])?;
94 offset += len as u32;
95 bytes = &bytes[len..];
96 }
97
98 if !bytes.is_empty() {
99 self.1.write(offset - self.0.capacity() as u32, bytes)?;
100 }
101
102 Ok(())
103 }
104
105 fn erase(&mut self, mut from: u32, to: u32) -> Result<(), E> {
106 if from < self.0.capacity() as u32 {
107 let to = core::cmp::min(self.0.capacity() as u32, to);
108 self.0.erase(from, to)?;
109 from = self.0.capacity() as u32;
110 }
111
112 if from < to {
113 self.1
114 .erase(from - self.0.capacity() as u32, to - self.0.capacity() as u32)?;
115 }
116
117 Ok(())
118 }
119}
120
121impl<First, Second, E> MultiwriteNorFlash for ConcatFlash<First, Second>
122where
123 First: MultiwriteNorFlash<Error = E>,
124 Second: MultiwriteNorFlash<Error = E>,
125 E: NorFlashError,
126{
127}
128
129impl<First, Second, E> AsyncReadNorFlash for ConcatFlash<First, Second>
130where
131 First: AsyncReadNorFlash<Error = E>,
132 Second: AsyncReadNorFlash<Error = E>,
133 E: NorFlashError,
134{
135 const READ_SIZE: usize = get_read_size(First::READ_SIZE, Second::READ_SIZE);
136
137 async fn read(&mut self, mut offset: u32, mut bytes: &mut [u8]) -> Result<(), E> {
138 if offset < self.0.capacity() as u32 {
139 let len = core::cmp::min(self.0.capacity() - offset as usize, bytes.len());
140 self.0.read(offset, &mut bytes[..len]).await?;
141 offset += len as u32;
142 bytes = &mut bytes[len..];
143 }
144
145 if !bytes.is_empty() {
146 self.1.read(offset - self.0.capacity() as u32, bytes).await?;
147 }
148
149 Ok(())
150 }
151
152 fn capacity(&self) -> usize {
153 self.0.capacity() + self.1.capacity()
154 }
155}
156
157impl<First, Second, E> AsyncNorFlash for ConcatFlash<First, Second>
158where
159 First: AsyncNorFlash<Error = E>,
160 Second: AsyncNorFlash<Error = E>,
161 E: NorFlashError,
162{
163 const WRITE_SIZE: usize = get_write_size(First::WRITE_SIZE, Second::WRITE_SIZE);
164 const ERASE_SIZE: usize = get_max_erase_size(First::ERASE_SIZE, Second::ERASE_SIZE);
165
166 async fn write(&mut self, mut offset: u32, mut bytes: &[u8]) -> Result<(), E> {
167 if offset < self.0.capacity() as u32 {
168 let len = core::cmp::min(self.0.capacity() - offset as usize, bytes.len());
169 self.0.write(offset, &bytes[..len]).await?;
170 offset += len as u32;
171 bytes = &bytes[len..];
172 }
173
174 if !bytes.is_empty() {
175 self.1.write(offset - self.0.capacity() as u32, bytes).await?;
176 }
177
178 Ok(())
179 }
180
181 async fn erase(&mut self, mut from: u32, to: u32) -> Result<(), E> {
182 if from < self.0.capacity() as u32 {
183 let to = core::cmp::min(self.0.capacity() as u32, to);
184 self.0.erase(from, to).await?;
185 from = self.0.capacity() as u32;
186 }
187
188 if from < to {
189 self.1
190 .erase(from - self.0.capacity() as u32, to - self.0.capacity() as u32)
191 .await?;
192 }
193
194 Ok(())
195 }
196}
197
198impl<First, Second, E> AsyncMultiwriteNorFlash for ConcatFlash<First, Second>
199where
200 First: AsyncMultiwriteNorFlash<Error = E>,
201 Second: AsyncMultiwriteNorFlash<Error = E>,
202 E: NorFlashError,
203{
204}
205
206#[cfg(test)]
207mod tests {
208 use embedded_storage::nor_flash::{NorFlash, ReadNorFlash};
209
210 use super::ConcatFlash;
211 use crate::flash::mem_flash::MemFlash;
212
213 #[test]
214 fn can_write_and_read_across_flashes() {
215 let first = MemFlash::<64, 16, 4>::default();
216 let second = MemFlash::<64, 64, 4>::default();
217 let mut f = ConcatFlash::new(first, second);
218
219 f.write(60, &[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]).unwrap();
220
221 assert_eq!(&[0x11, 0x22, 0x33, 0x44], &f.0.mem[60..]);
222 assert_eq!(&[0x55, 0x66, 0x77, 0x88], &f.1.mem[0..4]);
223
224 let mut read_buf = [0; 8];
225 f.read(60, &mut read_buf).unwrap();
226
227 assert_eq!(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], &read_buf);
228 }
229
230 #[test]
231 fn can_erase_across_flashes() {
232 let first = MemFlash::<128, 16, 4>::new(0x00);
233 let second = MemFlash::<128, 64, 4>::new(0x00);
234 let mut f = ConcatFlash::new(first, second);
235
236 f.erase(64, 192).unwrap();
237
238 assert_eq!(&[0x00; 64], &f.0.mem[0..64]);
239 assert_eq!(&[0xff; 64], &f.0.mem[64..128]);
240 assert_eq!(&[0xff; 64], &f.1.mem[0..64]);
241 assert_eq!(&[0x00; 64], &f.1.mem[64..128]);
242 }
243}