| 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 | |