1use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
33use capsules_extra::log;
34use core::cell::Cell;
35use core::ptr::addr_of_mut;
36use kernel::debug;
37use kernel::hil::flash;
38use kernel::hil::gpio::{self, Interrupt};
39use kernel::hil::log::{LogRead, LogReadClient, LogWrite, LogWriteClient};
40use kernel::hil::time::{Alarm, AlarmClient, ConvertTicks};
41use kernel::static_init;
42use kernel::storage_volume;
43use kernel::utilities::cells::{NumericCellExt, TakeCell};
44use kernel::ErrorCode;
45use sam4l::ast::Ast;
46use sam4l::flashcalw;
47
48storage_volume!(TEST_LOG, 2);
50
51pub unsafe fn run(
52 mux_alarm: &'static MuxAlarm<'static, Ast>,
53 flash_controller: &'static sam4l::flashcalw::FLASHCALW,
54) {
55 flash_controller.configure();
57 let pagebuffer = static_init!(flashcalw::Sam4lPage, flashcalw::Sam4lPage::default());
58
59 let log = static_init!(
61 Log,
62 log::Log::new(&TEST_LOG, flash_controller, pagebuffer, true)
63 );
64 kernel::deferred_call::DeferredCallClient::register(log);
65 flash::HasClient::set_client(flash_controller, log);
66
67 let alarm = static_init!(
68 VirtualMuxAlarm<'static, Ast>,
69 VirtualMuxAlarm::new(mux_alarm)
70 );
71 alarm.setup();
72
73 let test = static_init!(
75 LogTest<VirtualMuxAlarm<'static, Ast>>,
76 LogTest::new(log, &mut *addr_of_mut!(BUFFER), alarm, &TEST_OPS)
77 );
78 log.set_read_client(test);
79 log.set_append_client(test);
80 test.alarm.set_alarm_client(test);
81
82 let button_pin = sam4l::gpio::GPIOPin::new(sam4l::gpio::Pin::PC24);
84 button_pin.enable_interrupts(gpio::InterruptEdge::RisingEdge);
85 button_pin.set_client(test);
86
87 test.run();
88}
89
90static TEST_OPS: [TestOp; 24] = [
91 TestOp::BadRead,
93 TestOp::Read,
94 TestOp::BadWrite,
96 TestOp::Write,
97 TestOp::Read,
98 TestOp::BadWrite,
99 TestOp::Write,
100 TestOp::Read,
101 TestOp::SeekBeginning,
103 TestOp::Read,
104 TestOp::SeekBeginning,
106 TestOp::Write,
107 TestOp::BadRead,
109 TestOp::Read,
110 TestOp::Write,
113 TestOp::Sync,
114 TestOp::Read,
115 TestOp::Write,
117 TestOp::BadSeek(0),
118 TestOp::BadSeek(usize::MAX),
119 TestOp::Read,
120 TestOp::BadWrite,
122 TestOp::Read,
123 TestOp::Sync,
125];
126
127static mut BUFFER: [u8; 8] = [0; 8];
129const BUFFER_LEN: usize = 8;
131const VALUE_SHIFT: usize = 8 * (8 - BUFFER_LEN);
133static mut DUMMY_BUFFER: [u8; 520] = [0; 520];
135const WAIT_MS: u32 = 2;
137const MAGIC: u64 = 0x0102030405060708;
139const ENTRIES_PER_WRITE: u64 = 120;
141
142#[derive(Clone, Copy, PartialEq)]
144enum TestState {
145 Operate, Erase, CleanUp, }
149
150#[derive(Clone, Copy, PartialEq)]
152enum TestOp {
153 Read,
154 BadRead,
155 Write,
156 BadWrite,
157 Sync,
158 SeekBeginning,
159 BadSeek(usize),
160}
161
162type Log = log::Log<'static, flashcalw::FLASHCALW>;
163struct LogTest<A: 'static + Alarm<'static>> {
164 log: &'static Log,
165 buffer: TakeCell<'static, [u8]>,
166 alarm: &'static A,
167 state: Cell<TestState>,
168 ops: &'static [TestOp],
169 op_index: Cell<usize>,
170 op_start: Cell<bool>,
171 read_val: Cell<u64>,
172 write_val: Cell<u64>,
173}
174
175impl<A: 'static + Alarm<'static>> LogTest<A> {
176 fn new(
177 log: &'static Log,
178 buffer: &'static mut [u8],
179 alarm: &'static A,
180 ops: &'static [TestOp],
181 ) -> LogTest<A> {
182 let read_val = entry_id_to_test_value(log.next_read_entry_id());
184 let write_val = entry_id_to_test_value(log.log_end());
185
186 debug!(
187 "Log recovered from flash (Start and end entry IDs: {:?} to {:?}; read and write values: {} and {})",
188 log.next_read_entry_id(),
189 log.log_end(),
190 read_val,
191 write_val
192 );
193
194 LogTest {
195 log,
196 buffer: TakeCell::new(buffer),
197 alarm,
198 state: Cell::new(TestState::Operate),
199 ops,
200 op_index: Cell::new(0),
201 op_start: Cell::new(true),
202 read_val: Cell::new(read_val),
203 write_val: Cell::new(write_val),
204 }
205 }
206
207 fn run(&self) {
208 match self.state.get() {
209 TestState::Operate => {
210 let op_index = self.op_index.get();
211 if op_index == self.ops.len() {
212 self.state.set(TestState::CleanUp);
213 let _ = self.log.seek(self.log.log_start());
214 return;
215 }
216
217 match self.ops[op_index] {
218 TestOp::Read => self.read(),
219 TestOp::BadRead => self.bad_read(),
220 TestOp::Write => self.write(),
221 TestOp::BadWrite => self.bad_write(),
222 TestOp::Sync => self.sync(),
223 TestOp::SeekBeginning => self.seek_beginning(),
224 TestOp::BadSeek(entry_id) => self.bad_seek(entry_id),
225 }
226 }
227 TestState::Erase => self.erase(),
228 TestState::CleanUp => {
229 debug!(
230 "Log Storage test succeeded! (Final log start and end entry IDs: {:?} to {:?})",
231 self.log.next_read_entry_id(),
232 self.log.log_end()
233 );
234 }
235 }
236 }
237
238 fn next_op(&self) {
239 self.op_index.increment();
240 self.op_start.set(true);
241 }
242
243 fn erase(&self) {
244 match self.log.erase() {
245 Ok(()) => (),
246 Err(ErrorCode::BUSY) => {
247 self.wait();
248 }
249 _ => panic!("Could not erase log storage!"),
250 }
251 }
252
253 fn read(&self) {
254 if self.op_start.get() {
256 let next_read_val = entry_id_to_test_value(self.log.next_read_entry_id());
257 if self.read_val.get() < next_read_val {
258 debug!(
259 "Increasing read value from {} to {} due to clobbering (read entry ID is {:?})!",
260 self.read_val.get(),
261 next_read_val,
262 self.log.next_read_entry_id()
263 );
264 self.read_val.set(next_read_val);
265 }
266 }
267
268 self.buffer.take().map_or_else(
269 || panic!("NO BUFFER"),
270 move |buffer| {
271 buffer.clone_from_slice(&0u64.to_be_bytes());
273
274 if let Err((error, original_buffer)) = self.log.read(buffer, BUFFER_LEN) {
275 self.buffer.replace(original_buffer);
276 match error {
277 ErrorCode::FAIL => {
278 debug!(
280 "READ DONE: READ OFFSET: {:?} / WRITE OFFSET: {:?}",
281 self.log.next_read_entry_id(),
282 self.log.log_end()
283 );
284 self.next_op();
285 self.run();
286 }
287 ErrorCode::BUSY => {
288 debug!("Flash busy, waiting before reattempting read");
289 self.wait();
290 }
291 _ => panic!("READ #{} FAILED: {:?}", self.read_val.get(), error),
292 }
293 }
294 },
295 );
296 }
297
298 fn bad_read(&self) {
299 self.buffer
301 .take()
302 .map(
303 move |buffer| match self.log.read(buffer, buffer.len() + 1) {
304 Ok(()) => panic!("Read with too-large max read length succeeded unexpectedly!"),
305 Err((error, original_buffer)) => {
306 self.buffer.replace(original_buffer);
307 assert_eq!(error, ErrorCode::INVAL);
308 }
309 },
310 )
311 .unwrap();
312
313 self.buffer
315 .take()
316 .map(move |buffer| match self.log.read(buffer, BUFFER_LEN - 1) {
317 Ok(()) => panic!("Read with too-small buffer succeeded unexpectedly!"),
318 Err((error, original_buffer)) => {
319 self.buffer.replace(original_buffer);
320 if self.read_val.get() == self.write_val.get() {
321 assert_eq!(error, ErrorCode::FAIL);
322 } else {
323 assert_eq!(error, ErrorCode::FAIL);
324 }
325 }
326 })
327 .unwrap();
328
329 self.next_op();
330 self.run();
331 }
332
333 fn write(&self) {
334 self.buffer
335 .take()
336 .map(move |buffer| {
337 buffer.clone_from_slice(
338 &(MAGIC + (self.write_val.get() << VALUE_SHIFT)).to_be_bytes(),
339 );
340 if let Err((error, original_buffer)) = self.log.append(buffer, BUFFER_LEN) {
341 self.buffer.replace(original_buffer);
342
343 match error {
344 ErrorCode::BUSY => self.wait(),
345 _ => panic!("WRITE FAILED: {:?}", error),
346 }
347 }
348 })
349 .unwrap();
350 }
351
352 fn bad_write(&self) {
353 let original_offset = self.log.log_end();
354
355 self.buffer
357 .take()
358 .map(move |buffer| match self.log.append(buffer, 0) {
359 Ok(()) => panic!("Appending entry of size 0 succeeded unexpectedly!"),
360 Err((error, original_buffer)) => {
361 self.buffer.replace(original_buffer);
362 assert_eq!(error, ErrorCode::INVAL);
363 }
364 })
365 .unwrap();
366
367 self.buffer
369 .take()
370 .map(
371 move |buffer| match self.log.append(buffer, buffer.len() + 1) {
372 Ok(()) => panic!("Appending with too-small buffer succeeded unexpectedly!"),
373 Err((error, original_buffer)) => {
374 self.buffer.replace(original_buffer);
375 assert_eq!(error, ErrorCode::INVAL);
376 }
377 },
378 )
379 .unwrap();
380
381 unsafe {
383 let dummy_buffer = &mut *addr_of_mut!(DUMMY_BUFFER);
384 let len = dummy_buffer.len();
385 match self.log.append(dummy_buffer, len) {
386 Ok(()) => panic!("Appending with too-small buffer succeeded unexpectedly!"),
387 Err((ecode, _original_buffer)) => assert_eq!(ecode, ErrorCode::SIZE),
388 }
389 }
390
391 assert_eq!(original_offset, self.log.log_end());
393 self.next_op();
394 self.run();
395 }
396
397 fn sync(&self) {
398 match self.log.sync() {
399 Ok(()) => (),
400 error => panic!("Sync failed: {:?}", error),
401 }
402 }
403
404 fn seek_beginning(&self) {
405 let entry_id = self.log.log_start();
406 match self.log.seek(entry_id) {
407 Ok(()) => debug!("Seeking to {:?}...", entry_id),
408 error => panic!("Seek failed: {:?}", error),
409 }
410 }
411
412 fn bad_seek(&self, entry_id: usize) {
413 let original_offset = self.log.next_read_entry_id();
415 match self.log.seek(entry_id) {
416 Err(ErrorCode::INVAL) => (),
417 Ok(()) => panic!(
418 "Seek to invalid entry ID {:?} succeeded unexpectedly!",
419 entry_id
420 ),
421 error => panic!(
422 "Seek to invalid entry ID {:?} failed with unexpected error {:?}!",
423 entry_id, error
424 ),
425 }
426
427 assert_eq!(original_offset, self.log.next_read_entry_id());
429 self.next_op();
430 self.run();
431 }
432
433 fn wait(&self) {
434 let delay = self.alarm.ticks_from_ms(WAIT_MS);
435 let now = self.alarm.now();
436 self.alarm.set_alarm(now, delay);
437 }
438}
439
440impl<A: Alarm<'static>> LogReadClient for LogTest<A> {
441 fn read_done(&self, buffer: &'static mut [u8], length: usize, error: Result<(), ErrorCode>) {
442 match error {
443 Ok(()) => {
444 if length != BUFFER_LEN {
446 panic!(
447 "{} bytes read, expected {} on read number {} (offset {:?}). Value read was {:?}",
448 length,
449 BUFFER_LEN,
450 self.read_val.get(),
451 self.log.next_read_entry_id(),
452 &buffer[0..length],
453 );
454 }
455
456 let expected = (MAGIC + (self.read_val.get() << VALUE_SHIFT)).to_be_bytes();
458 for i in 0..BUFFER_LEN {
459 if buffer[i] != expected[i] {
460 panic!(
461 "Expected {:?}, read {:?} on read number {} (offset {:?})",
462 &expected[0..BUFFER_LEN],
463 &buffer[0..BUFFER_LEN],
464 self.read_val.get(),
465 self.log.next_read_entry_id(),
466 );
467 }
468 }
469
470 self.buffer.replace(buffer);
471 self.read_val.set(self.read_val.get() + 1);
472 self.op_start.set(false);
473 self.wait();
474 }
475 _ => {
476 panic!("Read failed unexpectedly!");
477 }
478 }
479 }
480
481 fn seek_done(&self, error: Result<(), ErrorCode>) {
482 if error == Ok(()) {
483 debug!("Seeked");
484 self.read_val
485 .set(entry_id_to_test_value(self.log.next_read_entry_id()));
486 } else {
487 panic!("Seek failed: {:?}", error);
488 }
489
490 if self.state.get() == TestState::Operate {
491 self.next_op();
492 }
493 self.run();
494 }
495}
496
497impl<A: Alarm<'static>> LogWriteClient for LogTest<A> {
498 fn append_done(
499 &self,
500 buffer: &'static mut [u8],
501 length: usize,
502 records_lost: bool,
503 error: Result<(), ErrorCode>,
504 ) {
505 self.buffer.replace(buffer);
506 self.op_start.set(false);
507
508 match error {
509 Ok(()) => {
510 if length != BUFFER_LEN {
511 panic!(
512 "Appended {} bytes, expected {} (write #{}, offset {:?})!",
513 length,
514 BUFFER_LEN,
515 self.write_val.get(),
516 self.log.log_end()
517 );
518 }
519 let expected_records_lost =
520 self.write_val.get() > entry_id_to_test_value(TEST_LOG.len());
521 if records_lost && records_lost != expected_records_lost {
522 panic!("Append callback states records_lost = {}, expected {} (write #{}, offset {:?})!",
523 records_lost,
524 expected_records_lost,
525 self.write_val.get(),
526 self.log.log_end()
527 );
528 }
529
530 if (self.write_val.get() + 1) % ENTRIES_PER_WRITE == 0 {
532 debug!(
533 "WRITE DONE: READ OFFSET: {:?} / WRITE OFFSET: {:?}",
534 self.log.next_read_entry_id(),
535 self.log.log_end()
536 );
537 self.next_op();
538 }
539
540 self.write_val.set(self.write_val.get() + 1);
541 }
542 Err(ErrorCode::FAIL) => {
543 assert_eq!(length, 0);
544 assert!(!records_lost);
545 debug!("Append failed due to flash error, retrying...");
546 }
547 error => panic!("UNEXPECTED APPEND FAILURE: {:?}", error),
548 }
549
550 self.wait();
551 }
552
553 fn sync_done(&self, error: Result<(), ErrorCode>) {
554 if error == Ok(()) {
555 debug!(
556 "SYNC DONE: READ OFFSET: {:?} / WRITE OFFSET: {:?}",
557 self.log.next_read_entry_id(),
558 self.log.log_end()
559 );
560 } else {
561 panic!("Sync failed: {:?}", error);
562 }
563
564 self.next_op();
565 self.run();
566 }
567
568 fn erase_done(&self, error: Result<(), ErrorCode>) {
569 match error {
570 Ok(()) => {
571 self.op_index.set(0);
573 self.op_start.set(true);
574 self.read_val.set(0);
575 self.write_val.set(0);
576
577 for i in 0..TEST_LOG.len() {
579 if TEST_LOG[i] != 0xFF {
580 panic!(
581 "Log not properly erased, read {} at byte {}. SUMMARY: {:?}",
582 TEST_LOG[i],
583 i,
584 &TEST_LOG[i..i + 8]
585 );
586 }
587 }
588
589 self.buffer.take().map(move |buffer| {
591 if let Err((error, original_buffer)) = self.log.read(buffer, BUFFER_LEN) {
592 self.buffer.replace(original_buffer);
593 match error {
594 ErrorCode::FAIL => (),
595 ErrorCode::BUSY => {
596 self.wait();
597 }
598 _ => panic!("Read on empty log did not fail as expected: {:?}", error),
599 }
600 } else {
601 panic!("Read on empty log succeeded! (it shouldn't)");
602 }
603 });
604
605 debug!("Log Storage erased");
607 self.state.set(TestState::Operate);
608 self.run();
609 }
610 Err(ErrorCode::BUSY) => {
611 self.wait();
613 }
614 _ => {
615 panic!("Erase failed: {:?}", error);
616 }
617 }
618 }
619}
620
621impl<A: Alarm<'static>> AlarmClient for LogTest<A> {
622 fn alarm(&self) {
623 self.run();
624 }
625}
626
627impl<A: Alarm<'static>> gpio::Client for LogTest<A> {
628 fn fired(&self) {
629 self.state.set(TestState::Erase);
631 self.erase();
632 }
633}
634
635fn entry_id_to_test_value(entry_id: usize) -> u64 {
636 const PAGE_SIZE: usize = 512;
638
639 let pages_written = entry_id / PAGE_SIZE;
640 let entry_size = log::ENTRY_HEADER_SIZE + BUFFER_LEN;
641 let entries_per_page = (PAGE_SIZE - log::PAGE_HEADER_SIZE) / entry_size;
642 let entries_last_page = if entry_id % PAGE_SIZE >= log::PAGE_HEADER_SIZE {
643 (entry_id % PAGE_SIZE - log::PAGE_HEADER_SIZE) / entry_size
644 } else {
645 0
646 };
647 (pages_written * entries_per_page + entries_last_page) as u64
648}