From 936eceded2d08f4eb7318b28bd1be6cd3b06a7b3 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 8 Jun 2020 21:01:31 -0700 Subject: [PATCH] altos: Move ao_storage_erase to shared code. Add len This makes ao_storage_erase take an arbitrary length. The new version erases each storage block if there's any un-erased data present, and then also checks after erasing to make sure the block is clear. Signed-off-by: Keith Packard --- src/drivers/ao_m25.c | 2 +- src/kernel/ao_config.h | 2 +- src/kernel/ao_storage.c | 100 ++++++++++++++++++++++++++---- src/kernel/ao_storage.h | 12 +++- src/micropeak-v2.0/ao_micropeak.c | 4 +- src/stmf0/ao_storage_stm.c | 17 +---- 6 files changed, 103 insertions(+), 34 deletions(-) diff --git a/src/drivers/ao_m25.c b/src/drivers/ao_m25.c index 72617cc4..ca0615e7 100644 --- a/src/drivers/ao_m25.c +++ b/src/drivers/ao_m25.c @@ -239,7 +239,7 @@ ao_m25_scan(void) * Erase the specified sector */ uint8_t -ao_storage_erase(uint32_t pos) +ao_storage_device_erase(uint32_t pos) { ao_port_t cs; diff --git a/src/kernel/ao_config.h b/src/kernel/ao_config.h index 7e8e62f3..87509dff 100644 --- a/src/kernel/ao_config.h +++ b/src/kernel/ao_config.h @@ -38,7 +38,7 @@ #include #define ao_config_setup() ao_storage_setup() -#define ao_config_erase() ao_storage_erase(ao_storage_config) +#define ao_config_erase() ao_storage_erase(ao_storage_config, ao_storage_block) #define ao_config_write(pos,bytes, len) ao_storage_write(ao_storage_config+(pos), bytes, len) #define ao_config_read(pos,bytes, len) ao_storage_read(ao_storage_config+(pos), bytes, len) #define ao_config_flush() ao_storage_flush() diff --git a/src/kernel/ao_storage.c b/src/kernel/ao_storage.c index cfd116f9..73b31c64 100644 --- a/src/kernel/ao_storage.c +++ b/src/kernel/ao_storage.c @@ -19,8 +19,12 @@ #include #include +#define AO_STORAGE_DATA_SIZE 256 + +static uint8_t storage_data[AO_STORAGE_DATA_SIZE]; + uint8_t -ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len) +ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len) { uint8_t *buf = v_buf; uint16_t this_len; @@ -81,7 +85,60 @@ ao_storage_write(ao_pos_t pos, void *v_buf, uint16_t len) return 1; } -static uint8_t storage_data[128]; +uint8_t +ao_storage_is_erased(uint32_t pos) +{ + uint32_t read_pos; + uint32_t read_len; + uint32_t i; + + read_pos = pos; + read_len = ao_storage_block; + while (read_len) { + uint32_t this_time = AO_STORAGE_DATA_SIZE; + if (this_time > read_len) + this_time = read_len; + if (!ao_storage_read(read_pos, storage_data, this_time)) + return 0; + for (i = 0; i < this_time; i++) + if (storage_data[i] != 0xff) + return 0; + read_pos += this_time; + read_len -= this_time; + } + return 1; +} + +uint8_t +ao_storage_erase(uint32_t start_pos, uint32_t len) +{ + /* Round 'len' up to ao_storage_block units */ + len = ((len + ao_storage_block - 1) / ao_storage_block) * ao_storage_block; + + /* + * Start at the end of the area to erase so that the + * last block cleared is the first block; this will ensure + * that partially erased flight logs still appear in the list + * and can be re-erased. + */ + uint32_t pos = start_pos + len - ao_storage_block; + while (len) { + int tries; + +#define MAX_TRIES 4 /* needs to be at least 2 */ + for (tries = 0; tries < MAX_TRIES; tries++) { + if (ao_storage_is_erased(pos)) + break; + if (!ao_storage_device_erase(pos)) + return 0; + } + if (tries == MAX_TRIES) + return 0; + pos -= ao_storage_block; + len -= ao_storage_block; + } + return 1; +} static void ao_storage_dump(void) @@ -143,19 +200,16 @@ ao_storage_zap(void) uint32_t v = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - ao_storage_erase((uint32_t) v << 8); + ao_storage_erase((uint32_t) v << 8, ao_storage_block); } static void ao_storage_zapall(void) { - uint32_t pos; - ao_cmd_white(); if (!ao_match_word("DoIt")) return; - for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) - ao_storage_erase(pos); + ao_storage_erase(0, ao_storage_log_max); } #if AO_STORAGE_TEST @@ -265,26 +319,26 @@ ao_storage_incr_check_block(uint32_t pos) static uint8_t ao_storage_test_block(uint32_t pos) { - ao_storage_erase(pos); + ao_storage_erase(pos, ao_storage_block); printf(" erase"); flush(); if (!ao_storage_check_block(pos, 0xff)) return 0; printf(" zero"); flush(); if (!ao_storage_fill_check_block(pos, 0x00)) return 0; - ao_storage_erase(pos); + ao_storage_erase(pos, ao_storage_block); printf(" 0xaa"); flush(); if (!ao_storage_fill_check_block(pos, 0xaa)) return 0; - ao_storage_erase(pos); + ao_storage_erase(pos, ao_storage_block); printf(" 0x55"); flush(); if (!ao_storage_fill_check_block(pos, 0x55)) return 0; - ao_storage_erase(pos); + ao_storage_erase(pos, ao_storage_block); printf(" increment"); flush(); if (!ao_storage_incr_check_block(pos)) return 0; - ao_storage_erase(pos); + ao_storage_erase(pos, ao_storage_block); printf(" pass\n"); flush(); return 1; } @@ -304,6 +358,27 @@ ao_storage_test(void) } printf("Test complete\n"); } + +static void +ao_storage_fill(void) +{ + uint32_t pos; + + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + printf("erase "); flush(); + ao_storage_erase(0, ao_storage_log_max); + for (pos = 0; pos < sizeof (storage_data); pos++) + storage_data[pos] = (uint8_t) pos; + for (pos = 0; pos < ao_storage_log_max; pos += sizeof (storage_data)) { + if ((pos & 0xffff) == 0) { + printf("Fill 0x%x\n", pos); flush(); + } + ao_storage_write(pos, storage_data, sizeof (storage_data)); + } + printf("Fill complete\n"); +} #endif /* AO_STORAGE_TEST */ static void @@ -325,6 +400,7 @@ const struct ao_cmds ao_storage_cmds[] = { { ao_storage_zapall,"Z \0Erase all. is doit with D&I" }, #if AO_STORAGE_TEST { ao_storage_test, "V \0Validate flash (destructive). is doit with D&I" }, + { ao_storage_fill, "F \0Fill flash with data. is doit with D&I" }, #endif { 0, NULL }, }; diff --git a/src/kernel/ao_storage.h b/src/kernel/ao_storage.h index cf37a824..1c5867e0 100644 --- a/src/kernel/ao_storage.h +++ b/src/kernel/ao_storage.h @@ -66,7 +66,13 @@ ao_storage_read(ao_pos_t pos, void *buf, uint16_t len); /* Erase a block of storage. This always clears ao_storage_block bytes */ uint8_t -ao_storage_erase(ao_pos_t pos); +ao_storage_erase(ao_pos_t pos, uint32_t len); + +/* Check storage starting at pos to see if the chunk there + * is erased + */ +uint8_t +ao_storage_is_erased(uint32_t pos); /* Flush any pending writes to stable storage */ void @@ -88,6 +94,10 @@ ao_storage_device_read(ao_pos_t pos, void *buf, uint16_t len); uint8_t ao_storage_device_write(ao_pos_t pos, void *buf, uint16_t len); +/* Erase device from pos through pos + ao_storage_block */ +uint8_t +ao_storage_device_erase(uint32_t pos); + /* Initialize low-level device bits */ void ao_storage_device_init(void); diff --git a/src/micropeak-v2.0/ao_micropeak.c b/src/micropeak-v2.0/ao_micropeak.c index f3fbc9f4..c0242b91 100644 --- a/src/micropeak-v2.0/ao_micropeak.c +++ b/src/micropeak-v2.0/ao_micropeak.c @@ -167,9 +167,7 @@ ao_battery_voltage(void) static void ao_log_erase(void) { - uint32_t pos; - for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) - ao_storage_erase(pos); + ao_storage_erase(0, ao_storage_log_max); } uint8_t ao_on_battery; diff --git a/src/stmf0/ao_storage_stm.c b/src/stmf0/ao_storage_stm.c index 111db04a..4ecdc7a5 100644 --- a/src/stmf0/ao_storage_stm.c +++ b/src/stmf0/ao_storage_stm.c @@ -128,24 +128,9 @@ _ao_flash_write(uint32_t pos, void *sv, uint16_t len) stm_flash.cr &= ~(1 << STM_FLASH_CR_PG); } -static bool -ao_storage_is_erased(uint32_t pos) -{ - uint16_t *flash = _ao_flash_addr(pos); - uint32_t i = ao_storage_block >> 1; - - while (i--) - if (*flash++ != 0xffff) - return false; - return true; -} - uint8_t -ao_storage_erase(uint32_t pos) +ao_storage_device_erase(uint32_t pos) { - if (ao_storage_is_erased(pos)) - return 1; - ao_arch_block_interrupts(); ao_flash_unlock(); -- 2.30.2