123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- #include <AP_HAL/AP_HAL.h>
- #include <AP_FlashStorage/AP_FlashStorage.h>
- #include <AP_Math/AP_Math.h>
- #include <stdio.h>
- #define FLASHSTORAGE_DEBUG 0
- #if FLASHSTORAGE_DEBUG
- #define debug(fmt, args...) do { printf(fmt, ##args); } while(0)
- #else
- #define debug(fmt, args...) do { } while(0)
- #endif
- AP_FlashStorage::AP_FlashStorage(uint8_t *_mem_buffer,
- uint32_t _flash_sector_size,
- FlashWrite _flash_write,
- FlashRead _flash_read,
- FlashErase _flash_erase,
- FlashEraseOK _flash_erase_ok) :
- mem_buffer(_mem_buffer),
- flash_sector_size(_flash_sector_size),
- flash_write(_flash_write),
- flash_read(_flash_read),
- flash_erase(_flash_erase),
- flash_erase_ok(_flash_erase_ok) {}
- bool AP_FlashStorage::init(void)
- {
- debug("running init()\n");
-
-
- memset(mem_buffer, 0, storage_size);
-
- struct sector_header header[2];
-
- for (uint8_t i=0; i<2; i++) {
- if (!flash_read(i, 0, (uint8_t *)&header[i], sizeof(header[i]))) {
- return false;
- }
- bool bad_header = (header[i].signature != signature);
- enum SectorState state = (enum SectorState)header[i].state;
- if (state != SECTOR_STATE_AVAILABLE &&
- state != SECTOR_STATE_IN_USE &&
- state != SECTOR_STATE_FULL) {
- bad_header = true;
- }
-
- if (bad_header) {
- return erase_all();
- }
- }
-
- enum SectorState states[2] {(enum SectorState)header[0].state, (enum SectorState)header[1].state};
- uint8_t first_sector;
- if (states[0] == states[1]) {
- if (states[0] != SECTOR_STATE_AVAILABLE) {
- return erase_all();
- }
- first_sector = 0;
- } else if (states[0] == SECTOR_STATE_FULL) {
- first_sector = 0;
- } else if (states[1] == SECTOR_STATE_FULL) {
- first_sector = 1;
- } else if (states[0] == SECTOR_STATE_IN_USE) {
- first_sector = 0;
- } else if (states[1] == SECTOR_STATE_IN_USE) {
- first_sector = 1;
- } else {
-
- first_sector = 0;
- }
-
- for (uint8_t i=0; i<2; i++) {
- uint8_t sector = (first_sector + i) & 1;
- if (states[sector] == SECTOR_STATE_IN_USE ||
- states[sector] == SECTOR_STATE_FULL) {
- if (!load_sector(sector)) {
- return erase_all();
- }
- }
- }
-
- write_error = false;
- reserved_space = 0;
-
-
- if (states[first_sector] == SECTOR_STATE_FULL) {
- current_sector = first_sector ^ 1;
- if (!write_all()) {
- return erase_all();
- }
- }
-
- for (uint8_t i=0; i<2; i++) {
- if (states[i] == SECTOR_STATE_FULL) {
- if (!erase_sector(i)) {
- return false;
- }
- }
- }
- reserved_space = 0;
-
-
- return true;
- }
- bool AP_FlashStorage::switch_full_sector(void)
- {
- debug("running switch_full_sector()\n");
-
-
- write_error = false;
- reserved_space = 0;
-
- if (!write_all()) {
- return false;
- }
- if (!erase_sector(current_sector ^ 1)) {
- return false;
- }
- return switch_sectors();
- }
- bool AP_FlashStorage::write(uint16_t offset, uint16_t length)
- {
- if (write_error) {
- return false;
- }
-
-
- while (length > 0) {
- uint8_t n = max_write;
- if (length < n) {
- n = length;
- }
- if (write_offset > flash_sector_size - (sizeof(struct block_header) + max_write + reserved_space)) {
- if (!switch_sectors()) {
- if (!flash_erase_ok()) {
- return false;
- }
- if (!switch_full_sector()) {
- return false;
- }
- }
- }
-
- struct block_header header;
- header.state = BLOCK_STATE_WRITING;
- header.block_num = offset / block_size;
- header.num_blocks_minus_one = ((n + (block_size - 1)) / block_size)-1;
- uint16_t block_ofs = header.block_num*block_size;
- uint16_t block_nbytes = (header.num_blocks_minus_one+1)*block_size;
-
- #if AP_FLASHSTORAGE_MULTI_WRITE
- if (!flash_write(current_sector, write_offset, (uint8_t*)&header, sizeof(header))) {
- return false;
- }
- #endif
- if (!flash_write(current_sector, write_offset+sizeof(header), &mem_buffer[block_ofs], block_nbytes)) {
- return false;
- }
- header.state = BLOCK_STATE_VALID;
- if (!flash_write(current_sector, write_offset, (uint8_t*)&header, sizeof(header))) {
- return false;
- }
- write_offset += sizeof(header) + block_nbytes;
- uint8_t n2 = block_nbytes - (offset % block_size);
-
- if (n2 > length) {
- break;
- }
- offset += n2;
- length -= n2;
- }
-
-
-
-
- return true;
- }
- bool AP_FlashStorage::load_sector(uint8_t sector)
- {
- uint32_t ofs = sizeof(sector_header);
- while (ofs < flash_sector_size - sizeof(struct block_header)) {
- struct block_header header;
- if (!flash_read(sector, ofs, (uint8_t *)&header, sizeof(header))) {
- return false;
- }
- enum BlockState state = (enum BlockState)header.state;
- switch (state) {
- case BLOCK_STATE_AVAILABLE:
-
- write_offset = ofs;
- return true;
- case BLOCK_STATE_WRITING: {
-
- uint16_t block_nbytes = (header.num_blocks_minus_one+1)*block_size;
- ofs += block_nbytes + sizeof(header);
- break;
- }
-
- case BLOCK_STATE_VALID: {
- uint16_t block_nbytes = (header.num_blocks_minus_one+1)*block_size;
- uint16_t block_ofs = header.block_num*block_size;
- if (block_ofs + block_nbytes > storage_size) {
-
- return false;
- }
- if (!flash_read(sector, ofs+sizeof(header), &mem_buffer[block_ofs], block_nbytes)) {
- return false;
- }
-
- ofs += block_nbytes + sizeof(header);
- break;
- }
- default:
-
- return false;
- }
- }
- write_offset = ofs;
- return true;
- }
- bool AP_FlashStorage::erase_sector(uint8_t sector)
- {
- if (!flash_erase(sector)) {
- return false;
- }
- struct sector_header header;
- header.signature = signature;
- header.state = SECTOR_STATE_AVAILABLE;
- return flash_write(sector, 0, (const uint8_t *)&header, sizeof(header));
- }
- bool AP_FlashStorage::erase_all(void)
- {
- write_error = false;
- current_sector = 0;
- write_offset = sizeof(struct sector_header);
-
- if (!erase_sector(0) || !erase_sector(1)) {
- return false;
- }
-
-
- struct sector_header header;
- header.signature = signature;
- header.state = SECTOR_STATE_IN_USE;
- return flash_write(current_sector, 0, (const uint8_t *)&header, sizeof(header));
- }
- bool AP_FlashStorage::write_all()
- {
- debug("write_all to sector %u at %u with reserved_space=%u\n",
- current_sector, write_offset, reserved_space);
- for (uint16_t ofs=0; ofs<storage_size; ofs += max_write) {
-
- const uint8_t max_write_local = max_write;
- uint8_t n = MIN(max_write_local, storage_size-ofs);
- if (!all_zero(ofs, n)) {
- if (!write(ofs, n)) {
- return false;
- }
- }
- }
- return true;
- }
- bool AP_FlashStorage::all_zero(uint16_t ofs, uint16_t size)
- {
- while (size--) {
- if (mem_buffer[ofs++] != 0) {
- return false;
- }
- }
- return true;
- }
- bool AP_FlashStorage::switch_sectors(void)
- {
- if (reserved_space != 0) {
-
- debug("both sectors are full\n");
- return false;
- }
- struct sector_header header;
- header.signature = signature;
- uint8_t new_sector = current_sector ^ 1;
- debug("switching to sector %u\n", new_sector);
-
-
- if (!flash_read(new_sector, 0, (uint8_t *)&header, sizeof(header))) {
- return false;
- }
- if (header.signature != signature) {
- write_error = true;
- return false;
- }
- if (SECTOR_STATE_AVAILABLE != (enum SectorState)header.state) {
- write_error = true;
- debug("both sectors full\n");
- return false;
- }
-
-
-
-
- header.state = SECTOR_STATE_FULL;
- if (!flash_write(current_sector, 0, (const uint8_t *)&header, sizeof(header))) {
- return false;
- }
-
- header.state = SECTOR_STATE_IN_USE;
- if (!flash_write(new_sector, 0, (const uint8_t *)&header, sizeof(header))) {
- return false;
- }
-
- current_sector = new_sector;
-
-
-
- reserved_space = reserve_size;
-
- write_offset = sizeof(header);
- return true;
- }
- bool AP_FlashStorage::re_initialise(void)
- {
- if (!flash_erase_ok()) {
- return false;
- }
- if (!erase_all()) {
- return false;
- }
- return write_all();
- }
|