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