@@ -36,7 +36,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3636
3737PrintingSoftWire bus (SDA, SCL);
3838
39- struct {
39+ struct Cfg {
4040 // A single test is done using these values, then they are changed
4141 // into various variations
4242
@@ -56,6 +56,14 @@ struct {
5656 // These are not changed, so set them here
5757 bool printRawData = false ;
5858 bool displayAttached = true ;
59+
60+ enum {
61+ FLASH_ONCE, // Flash random data in the first run
62+ FLASH_ONE_BYTE_PER_RUN, // Additionallly change one byte on each run
63+ FLASH_EVERY_TIME, // Change every byte on every run. This will wear out the flash!
64+ };
65+ uint8_t flashWear = FLASH_ONCE;
66+
5967 // When non-zero, only write this much bytes to flash on each test, to
6068 // speed up testing
6169 uint16_t maxWriteSize = 0 ;
@@ -413,7 +421,7 @@ bool write_flash_cmd(uint16_t address, uint8_t *data, uint8_t len, uint8_t *stat
413421 return true ;
414422}
415423
416- bool write_flash (uint8_t *data, uint16_t len, uint8_t writelen) {
424+ bool write_flash (uint8_t *data, uint16_t len, uint8_t writelen, uint8_t *erase_count ) {
417425 uint16_t offset = 0 ;
418426 auto on_failure = [&offset]() {
419427 Serial.print (" offset = 0x" );
@@ -428,11 +436,11 @@ bool write_flash(uint8_t *data, uint16_t len, uint8_t writelen) {
428436 assertOk (status);
429437 offset += nextlen;
430438 }
431- assertTrue (run_transaction_ok (Commands::FINALIZE_FLASH));
439+ assertTrue (run_transaction_ok (Commands::FINALIZE_FLASH, nullptr , 0 , erase_count, 1 , 1 ));
432440 return true ;
433441}
434442
435- bool write_and_verify_flash (uint8_t *data, uint16_t len, uint8_t writelen, uint8_t readlen) {
443+ bool write_and_verify_flash (uint8_t *data, uint16_t len, uint8_t writelen, uint8_t readlen, uint8_t *erase_count ) {
436444 auto on_failure = [readlen, writelen]() {
437445 Serial.print (" writelen = " );
438446 Serial.println (writelen);
@@ -443,7 +451,7 @@ bool write_and_verify_flash(uint8_t *data, uint16_t len, uint8_t writelen, uint8
443451#ifdef TIME_WRITE
444452 unsigned long start = millis ();
445453#endif
446- assertTrue (write_flash (data, len, writelen));
454+ assertTrue (write_flash (data, len, writelen, erase_count ));
447455#ifdef TIME_WRITE
448456 unsigned long now = millis ();
449457 Serial.print (" Write took " );
@@ -478,30 +486,57 @@ test(120_write_flash) {
478486 if (cfg.maxWriteSize && cfg.maxWriteSize < flash_size)
479487 flash_size = cfg.maxWriteSize ;
480488
481- uint8_t *data = (uint8_t *)malloc (flash_size);
482- auto on_failure = [data]() { free (data); };
483- assertTrue (data != nullptr );
489+ static uint8_t *data = NULL ;
490+ static size_t data_len = 0 ;
491+ // The first time, we always generate fully random data, flash it, and
492+ // then change one byte. Since the previous testing session will likely have
493+ // generated the same contents (since the random seed is not random),
494+ // this ensures that at leaste one byte will really be different.
495+ bool full_random = (data == NULL ) || (cfg.flashWear == Cfg::FLASH_EVERY_TIME);
496+ bool change_one = (data == NULL ) || (cfg.flashWear == Cfg::FLASH_ONE_BYTE_PER_RUN);
497+ if (data_len == 0 ) {
498+ data = (uint8_t *)malloc (flash_size);
499+ assertTrue (data != nullptr );
500+ data_len = flash_size;
501+ } else {
502+ assertEqual (data_len, flash_size);
503+ }
504+
484505 assertMoreOrEqual (flash_size, 2U );
485- // The bootloader requires a RCALL or RJMP instruction at address 0,
486- // so give it one
487- data[0 ] = 0x00 ;
488- data[1 ] = 0xC0 ;
489- for (uint16_t i = 2 ; i < flash_size; ++i)
490- data[i] = random ();
506+ if (full_random) {
507+ // The bootloader requires a RCALL or RJMP instruction at address 0,
508+ // so give it one
509+ data[0 ] = 0x00 ;
510+ data[1 ] = 0xC0 ;
511+ for (uint16_t i = 2 ; i < flash_size; ++i)
512+ data[i] = random ();
513+ }
514+
515+ // Write flash using various messages sizes
516+ uint8_t erase_count;
517+ assertTrue (write_and_verify_flash (data, flash_size, 1 , 1 , &erase_count));
518+ // If we didn't randomize, nothing should have changed (but if we did
519+ // randomize, we can't be sure that something changed).
520+ if (!full_random)
521+ assertEqual (erase_count, 0 );
491522
492- assertTrue (write_and_verify_flash (data, flash_size, 1 , 1 ));
493- assertTrue (write_and_verify_flash (data, flash_size, 7 , 16 ));
494- assertTrue (write_and_verify_flash (data, flash_size, 16 , 3 ));
523+ if (change_one) {
524+ data[random (2 , flash_size)] += random (256 );
525+ }
526+ assertTrue (write_and_verify_flash (data, flash_size, 7 , 16 , &erase_count));
527+ assertEqual (erase_count, change_one ? 1 : 0 );
528+ assertTrue (write_and_verify_flash (data, flash_size, 16 , 3 , &erase_count));
529+ assertEqual (erase_count, 0 );
495530 // Max write and read size
496531 uint8_t writelen = MAX_MSG_LEN - 4 ; // cmd, 2xaddr, crc
497- uint8_t readlen = MAX_MSG_LEN - 2 ; // cmd, 2xaddr
498- assertTrue (write_and_verify_flash (data, flash_size, writelen, readlen));
532+ uint8_t readlen = MAX_MSG_LEN - 3 ; // status, len, 2xaddr
533+ assertTrue (write_and_verify_flash (data, flash_size, writelen, readlen, &erase_count));
534+ assertEqual (erase_count, 0 );
499535 // Random sizes
500536 writelen = random (1 , writelen);
501537 readlen = random (1 , readlen);
502- assertTrue (write_and_verify_flash (data, flash_size, writelen, readlen));
503-
504- free (data);
538+ assertTrue (write_and_verify_flash (data, flash_size, writelen, readlen, &erase_count));
539+ assertEqual (erase_count, 0 );
505540}
506541
507542test (130_invalid_writes) {
@@ -543,9 +578,10 @@ test(130_invalid_writes) {
543578 assertEqual (status, Status::COMMAND_FAILED);
544579 assertEqual (reason, 2 );
545580
581+ // FINALIZE_FLASH should also fail with an invalid address 0/1
546582 assertTrue (write_flash_cmd (0 , data, 2 , &status, &reason));
547583 assertOk (status);
548- assertTrue (run_transaction (Commands::FINALIZE_FLASH, nullptr , 0 , &status, &reason, 0 , 1 ));
584+ assertTrue (run_transaction (Commands::FINALIZE_FLASH, nullptr , 0 , &status, &reason, 1 , 1 ));
549585 assertEqual (status, Status::COMMAND_FAILED);
550586 assertEqual (reason, 2 );
551587}
0 commit comments