capsules_extra/
nonvolatile_to_pages.rs1use core::cell::Cell;
44use core::cmp;
45use kernel::hil;
46use kernel::utilities::cells::NumericCellExt;
47use kernel::utilities::cells::{OptionalCell, TakeCell};
48use kernel::ErrorCode;
49
50#[derive(Clone, Copy, Debug, PartialEq)]
52enum State {
53 Idle,
54 Read,
55 Write,
56}
57
58pub struct NonvolatileToPages<'a, F: hil::flash::Flash + 'static> {
59 driver: &'a F,
61 client: OptionalCell<&'a dyn hil::nonvolatile_storage::NonvolatileStorageClient>,
63 pagebuffer: TakeCell<'static, F::Page>,
65 state: Cell<State>,
67 buffer: TakeCell<'static, [u8]>,
69 address: Cell<usize>,
72 length: Cell<usize>,
75 remaining_length: Cell<usize>,
77 buffer_index: Cell<usize>,
79}
80
81impl<'a, F: hil::flash::Flash> NonvolatileToPages<'a, F> {
82 pub fn new(driver: &'a F, buffer: &'static mut F::Page) -> NonvolatileToPages<'a, F> {
83 NonvolatileToPages {
84 driver,
85 client: OptionalCell::empty(),
86 pagebuffer: TakeCell::new(buffer),
87 state: Cell::new(State::Idle),
88 buffer: TakeCell::empty(),
89 address: Cell::new(0),
90 length: Cell::new(0),
91 remaining_length: Cell::new(0),
92 buffer_index: Cell::new(0),
93 }
94 }
95}
96
97impl<'a, F: hil::flash::Flash> hil::nonvolatile_storage::NonvolatileStorage<'a>
98 for NonvolatileToPages<'a, F>
99{
100 fn set_client(&self, client: &'a dyn hil::nonvolatile_storage::NonvolatileStorageClient) {
101 self.client.set(client);
102 }
103
104 fn read(
105 &self,
106 buffer: &'static mut [u8],
107 address: usize,
108 length: usize,
109 ) -> Result<(), ErrorCode> {
110 if self.state.get() != State::Idle {
111 return Err(ErrorCode::BUSY);
112 }
113
114 self.pagebuffer
115 .take()
116 .map_or(Err(ErrorCode::RESERVE), move |pagebuffer| {
117 let page_size = pagebuffer.as_mut().len();
118
119 self.state.set(State::Read);
122 self.buffer.replace(buffer);
123 self.address.set(address);
124 self.length.set(length);
125 self.remaining_length.set(length);
126 self.buffer_index.set(0);
127
128 match self.driver.read_page(address / page_size, pagebuffer) {
129 Ok(()) => Ok(()),
130 Err((error_code, pagebuffer)) => {
131 self.pagebuffer.replace(pagebuffer);
132 Err(error_code)
133 }
134 }
135 })
136 }
137
138 fn write(
139 &self,
140 buffer: &'static mut [u8],
141 address: usize,
142 length: usize,
143 ) -> Result<(), ErrorCode> {
144 if self.state.get() != State::Idle {
145 return Err(ErrorCode::BUSY);
146 }
147
148 self.pagebuffer
149 .take()
150 .map_or(Err(ErrorCode::RESERVE), move |pagebuffer| {
151 let page_size = pagebuffer.as_mut().len();
152
153 self.state.set(State::Write);
154 self.length.set(length);
155
156 if address % page_size == 0 && length >= page_size {
157 pagebuffer.as_mut()[..page_size].copy_from_slice(&buffer[..page_size]);
162
163 self.buffer.replace(buffer);
164 self.address.set(address + page_size);
165 self.remaining_length.set(length - page_size);
166 self.buffer_index.set(page_size);
167
168 match self.driver.write_page(address / page_size, pagebuffer) {
169 Ok(()) => Ok(()),
170 Err((error_code, pagebuffer)) => {
171 self.pagebuffer.replace(pagebuffer);
172 Err(error_code)
173 }
174 }
175 } else {
176 self.buffer.replace(buffer);
178 self.address.set(address);
179 self.remaining_length.set(length);
180 self.buffer_index.set(0);
181
182 match self.driver.read_page(address / page_size, pagebuffer) {
183 Ok(()) => Ok(()),
184 Err((error_code, pagebuffer)) => {
185 self.pagebuffer.replace(pagebuffer);
186 Err(error_code)
187 }
188 }
189 }
190 })
191 }
192}
193
194impl<F: hil::flash::Flash> hil::flash::Client<F> for NonvolatileToPages<'_, F> {
195 fn read_complete(
196 &self,
197 pagebuffer: &'static mut F::Page,
198 _result: Result<(), hil::flash::Error>,
199 ) {
200 match self.state.get() {
201 State::Read => {
202 self.buffer.take().map(move |buffer| {
205 let page_size = pagebuffer.as_mut().len();
206 let page_index = self.address.get() % page_size;
208 let len = cmp::min(page_size - page_index, self.remaining_length.get());
210 let buffer_index = self.buffer_index.get();
212
213 buffer[buffer_index..(len + buffer_index)]
215 .copy_from_slice(&pagebuffer.as_mut()[page_index..(len + page_index)]);
216
217 let new_len = self.remaining_length.get() - len;
219 if new_len == 0 {
220 self.pagebuffer.replace(pagebuffer);
222 self.state.set(State::Idle);
223 self.client
224 .map(move |client| client.read_done(buffer, self.length.get()));
225 } else {
226 self.buffer.replace(buffer);
228 self.remaining_length.subtract(len);
230 self.address.add(len);
231 self.buffer_index.set(buffer_index + len);
232
233 if let Err((_, pagebuffer)) = self
234 .driver
235 .read_page(self.address.get() / page_size, pagebuffer)
236 {
237 self.pagebuffer.replace(pagebuffer);
238 }
239 }
240 });
241 }
242 State::Write => {
243 self.buffer.take().map(move |buffer| {
246 let page_size = pagebuffer.as_mut().len();
247 let page_index = self.address.get() % page_size;
249 let len = cmp::min(page_size - page_index, self.remaining_length.get());
251 let buffer_index = self.buffer_index.get();
253 let page_number = self.address.get() / page_size;
255
256 pagebuffer.as_mut()[page_index..(len + page_index)]
258 .copy_from_slice(&buffer[buffer_index..(len + buffer_index)]);
259
260 self.buffer.replace(buffer);
262 self.remaining_length.subtract(len);
263 self.address.add(len);
264 self.buffer_index.set(buffer_index + len);
265 if let Err((_, pagebuffer)) = self.driver.write_page(page_number, pagebuffer) {
266 self.pagebuffer.replace(pagebuffer);
267 }
268 });
269 }
270 _ => {}
271 }
272 }
273
274 fn write_complete(
275 &self,
276 pagebuffer: &'static mut F::Page,
277 _result: Result<(), hil::flash::Error>,
278 ) {
279 self.buffer.take().map(move |buffer| {
282 let page_size = pagebuffer.as_mut().len();
283
284 if self.remaining_length.get() == 0 {
285 self.pagebuffer.replace(pagebuffer);
287 self.state.set(State::Idle);
288 self.client
289 .map(move |client| client.write_done(buffer, self.length.get()));
290 } else if self.remaining_length.get() >= page_size {
291 let buffer_index = self.buffer_index.get();
293 let page_number = self.address.get() / page_size;
294
295 pagebuffer.as_mut()[..page_size]
297 .copy_from_slice(&buffer[buffer_index..(page_size + buffer_index)]);
298
299 self.buffer.replace(buffer);
300 self.remaining_length.subtract(page_size);
301 self.address.add(page_size);
302 self.buffer_index.set(buffer_index + page_size);
303 if let Err((_, pagebuffer)) = self.driver.write_page(page_number, pagebuffer) {
304 self.pagebuffer.replace(pagebuffer);
305 }
306 } else {
307 self.buffer.replace(buffer);
309 if let Err((_, pagebuffer)) = self
310 .driver
311 .read_page(self.address.get() / page_size, pagebuffer)
312 {
313 self.pagebuffer.replace(pagebuffer);
314 }
315 }
316 });
317 }
318
319 fn erase_complete(&self, _result: Result<(), hil::flash::Error>) {}
320}