From: Dmitry Date: Thu, 7 Jun 2018 06:58:06 +0000 (+0300) Subject: The version of WL component changed from 1 to 2. X-Git-Tag: v3.2-beta1~359^2~11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a6d6c58ecadb9759a0bacf35cd7332ac641e598d;p=esp-idf The version of WL component changed from 1 to 2. WL version 2 mark used sectors as 16 bytes block of bytes with CRC. This changes required because old version did not worked with encryption. Additional unit tests are implemented. --- diff --git a/components/wear_levelling/WL_Flash.cpp b/components/wear_levelling/WL_Flash.cpp index 030acd22cc..fec527a627 100644 --- a/components/wear_levelling/WL_Flash.cpp +++ b/components/wear_levelling/WL_Flash.cpp @@ -55,9 +55,10 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv) cfg->version, (uint32_t) cfg->temp_buff_size); - cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, sizeof(wl_config_t) - sizeof(cfg->crc)); + cfg->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (const unsigned char *)cfg, offsetof(wl_config_t, crc)); esp_err_t result = ESP_OK; memcpy(&this->cfg, cfg, sizeof(wl_config_t)); + if (this->cfg.temp_buff_size < this->cfg.wr_size) this->cfg.temp_buff_size = this->cfg.wr_size; this->configured = false; if (cfg == NULL) { result = ESP_ERR_INVALID_ARG; @@ -74,7 +75,6 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv) } WL_RESULT_CHECK(result); - this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size); this->state_size = this->cfg.sector_size; if (this->state_size < (sizeof(wl_state_t) + (this->cfg.full_mem_size / this->cfg.sector_size)*this->cfg.wr_size)) { this->state_size = ((sizeof(wl_state_t) + (this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size) + this->cfg.sector_size - 1) / this->cfg.sector_size; @@ -87,11 +87,27 @@ esp_err_t WL_Flash::config(wl_config_t *cfg, Flash_Access *flash_drv) this->addr_state1 = this->cfg.start_addr + this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size; // allocate data at the end of memory this->addr_state2 = this->cfg.start_addr + this->cfg.full_mem_size - this->state_size * 1 - this->cfg_size; // allocate data at the end of memory + ptrdiff_t flash_sz = ((this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size) / this->cfg.page_size - 1) * this->cfg.page_size; // -1 remove dummy block this->flash_size = ((this->cfg.full_mem_size - this->state_size * 2 - this->cfg_size) / this->cfg.page_size - 1) * this->cfg.page_size; // -1 remove dummy block - ESP_LOGV(TAG, "%s - this->addr_state1=0x%08x", __func__, (uint32_t) this->addr_state1); - ESP_LOGV(TAG, "%s - this->addr_state2=0x%08x", __func__, (uint32_t) this->addr_state2); + ESP_LOGD(TAG, "%s - config result: state_size=0x%08x, cfg_size=0x%08x, addr_cfg=0x%08x, addr_state1=0x%08x, addr_state2=0x%08x, flash_size=0x%08x", __func__, + (uint32_t) this->state_size, + (uint32_t) this->cfg_size, + (uint32_t) this->addr_cfg, + (uint32_t) this->addr_state1, + (uint32_t) this->addr_state2, + (uint32_t) this->flash_size + ); + if (flash_sz <= 0) { + result = ESP_ERR_INVALID_ARG; + } + WL_RESULT_CHECK(result); + this->temp_buff = (uint8_t *)malloc(this->cfg.temp_buff_size); + if (this->temp_buff == NULL) { + result = ESP_ERR_NO_MEM; + } + WL_RESULT_CHECK(result); this->configured = true; return ESP_OK; } @@ -112,12 +128,12 @@ esp_err_t WL_Flash::init() result = this->flash_drv->read(this->addr_state2, state_copy, sizeof(wl_state_t)); WL_RESULT_CHECK(result); - int check_size = sizeof(wl_state_t) - sizeof(uint32_t); + int check_size = offsetof(wl_state_t, crc); // Chech CRC and recover state uint32_t crc1 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, check_size); uint32_t crc2 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_copy, check_size); - ESP_LOGD(TAG, "%s - config ID=%i, stored ID=%i, access_count=%i, block_size=%i, max_count=%i, pos=%i, move_count=%i", + ESP_LOGD(TAG, "%s - config ID=%i, stored ID=%i, access_count=%i, block_size=%i, max_count=%i, pos=%i, move_count=0x%8.8X", __func__, this->cfg.version, this->state.version, @@ -127,8 +143,7 @@ esp_err_t WL_Flash::init() this->state.pos, this->state.move_count); - - ESP_LOGD(TAG, "%s starts: crc1=%i, crc2 = %i, this->state.crc=%i, state_copy->crc=%i", __func__, crc1, crc2, this->state.crc, state_copy->crc); + ESP_LOGD(TAG, "%s starts: crc1=%i, crc2 = %i, this->state.crc=%i, state_copy->crc=%i, version=%i, read_version=%i", __func__, crc1, crc2, this->state.crc, state_copy->crc, this->cfg.version, this->state.version); if ((crc1 == this->state.crc) && (crc2 == state_copy->crc)) { // The state is OK. Check the ID if (this->state.version != this->cfg.version) { @@ -143,11 +158,13 @@ esp_err_t WL_Flash::init() result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t)); WL_RESULT_CHECK(result); for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)*this->cfg.wr_size); i++) { - uint8_t pos_bits = 0; - result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1); + bool pos_bits = 0; + result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); WL_RESULT_CHECK(result); - if (pos_bits != 0xff) { - result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1); + pos_bits = this->OkBuffSet(i); + if (pos_bits == true) { + //this->fillOkBuff(i); + result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); WL_RESULT_CHECK(result); } } @@ -156,9 +173,13 @@ esp_err_t WL_Flash::init() result = this->recoverPos(); WL_RESULT_CHECK(result); } - } else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash - result = this->initSections(); - WL_RESULT_CHECK(result); + } else if ((crc1 != this->state.crc) && (crc2 != state_copy->crc)) { // This is just new flash or new version + // Check if this is new version or just new instance of WL + result = this->updateVersion(); + if (result == ESP_FAIL) { + result = this->initSections(); + WL_RESULT_CHECK(result); + } result = this->recoverPos(); WL_RESULT_CHECK(result); } else { @@ -169,11 +190,12 @@ esp_err_t WL_Flash::init() result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t)); WL_RESULT_CHECK(result); for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size); i++) { - uint8_t pos_bits = 0; - result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1); + bool pos_bits = 0; + result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); WL_RESULT_CHECK(result); - if (pos_bits != 0xff) { - result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1); + pos_bits = this->OkBuffSet(i); + if (pos_bits == true) { + result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); WL_RESULT_CHECK(result); } } @@ -185,11 +207,13 @@ esp_err_t WL_Flash::init() result = this->flash_drv->write(this->addr_state1, state_copy, sizeof(wl_state_t)); WL_RESULT_CHECK(result); for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size) * this->cfg.wr_size); i++) { - uint8_t pos_bits = 0; - result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i, &pos_bits, 1); + bool pos_bits = 0; + result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); + WL_RESULT_CHECK(result); - if (pos_bits != 0xff) { - result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i, &pos_bits, 1); + pos_bits = this->OkBuffSet(i); + if (pos_bits == true) { + result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); WL_RESULT_CHECK(result); } } @@ -206,10 +230,11 @@ esp_err_t WL_Flash::init() } if (result != ESP_OK) { this->initialized = false; - ESP_LOGE(TAG, "%s: returned 0x%x", __func__, result); + ESP_LOGE(TAG, "%s: returned 0x%x", __func__, (uint32_t)result); return result; } this->initialized = true; + ESP_LOGD(TAG, "%s - move_count=%08x", __func__, (uint32_t)this->state.move_count); return ESP_OK; } @@ -217,20 +242,25 @@ esp_err_t WL_Flash::recoverPos() { esp_err_t result = ESP_OK; size_t position = 0; + ESP_LOGV(TAG, "%s start", __func__); for (size_t i = 0; i < this->state.max_pos; i++) { - uint8_t pos_bits = 0; - result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1); - WL_RESULT_CHECK(result); + bool pos_bits = false; position = i; - if (pos_bits == 0xff) { + result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); + pos_bits = this->OkBuffSet(i); + WL_RESULT_CHECK(result); + ESP_LOGV(TAG, "%s - check pos: result=%i, position=%i, pos_bits=0x%08x", __func__, (uint32_t)result, (uint32_t)position, (uint32_t)pos_bits); + if (pos_bits == false) { break; // we have found position } } + this->state.pos = position; if (this->state.pos == this->state.max_pos) { this->state.pos--; } - ESP_LOGD(TAG, "%s - this->state.pos=0x%08x, result=%08x", __func__, this->state.pos, result); + ESP_LOGD(TAG, "%s - this->state.pos=0x%08x, position=0x%08x, result=%08x, max_pos=%08x", __func__, (uint32_t)this->state.pos, (uint32_t)position, (uint32_t)result, (uint32_t)this->state.max_pos); + ESP_LOGV(TAG, "%s done", __func__); return result; } @@ -248,10 +278,11 @@ esp_err_t WL_Flash::initSections() this->state.version = this->cfg.version; this->state.block_size = this->cfg.page_size; this->used_bits = 0; + this->state.device_id = rand(); this->state.max_pos = 1 + this->flash_size / this->cfg.page_size; - this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, sizeof(wl_state_t) - sizeof(uint32_t)); + this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc)); result = this->flash_drv->erase_range(this->addr_state1, this->state_size); WL_RESULT_CHECK(result); @@ -273,6 +304,108 @@ esp_err_t WL_Flash::initSections() return result; } +esp_err_t WL_Flash::updateVersion() +{ + esp_err_t result = ESP_OK; + + result = this->updateV1_V2(); + if (ESP_OK == result) return result; + // check next version + return result; +} + +esp_err_t WL_Flash::updateV1_V2() +{ + esp_err_t result = ESP_OK; + // Check crc for old version and old version + ESP_LOGV(TAG, "%s start", __func__); + int check_size = offsetof(wl_state_t, crc) - sizeof(uint32_t); + // Chech CRC and recover state + uint32_t crc1 = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, check_size); + // For V1 crc in place of device_id and version + uint32_t v1_crc = this->state.device_id; + + ESP_LOGD(TAG, "%s - process crc1=0x%08x v1_crc=0x%08x, version=%i", __func__, crc1, v1_crc, this->state.version); + + if ((crc1 == v1_crc) && (this->state.version == 1)){ + // Here we have to update all internal structures + ESP_LOGV(TAG, "%s Update from V1 to V2", __func__); + uint32_t pos = 0; + + for (size_t i = 0; i < this->state.max_pos; i++) { + uint8_t pos_bits = 0; + result = this->flash_drv->read(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, &pos_bits, 1); + WL_RESULT_CHECK(result); + ESP_LOGV(TAG, "%s- result=%i, pos=%i, pos_bits=0x%08x", __func__, (uint32_t)result, (uint32_t)pos, (uint32_t)pos_bits); + pos = i; + if (pos_bits == 0xff) { + break; // we have found position + } + } + if (pos == this->state.max_pos) { + pos--; + } + WL_RESULT_CHECK(result); + + this->state.version = 2; + this->state.pos = 0; + this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc)); + this->state.device_id = rand(); + + result = this->flash_drv->erase_range(this->addr_state1, this->state_size); + WL_RESULT_CHECK(result); + result = this->flash_drv->write(this->addr_state1, &this->state, sizeof(wl_state_t)); + WL_RESULT_CHECK(result); + + memset(this->temp_buff, 0, this->cfg.wr_size); + for (int i=0 ; i< pos; i++) { + this->fillOkBuff(i); + result = this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); + WL_RESULT_CHECK(result); + } + + result = this->flash_drv->erase_range(this->addr_state2, this->state_size); + WL_RESULT_CHECK(result); + result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t)); + WL_RESULT_CHECK(result); + ESP_LOGD(TAG, "%s - move_count=%08x, pos=%08x, ", __func__, this->state.move_count, this->state.pos); + + memset(this->temp_buff, 0, this->cfg.wr_size); + for (int i=0 ; i< pos; i++) { + this->fillOkBuff(i); + result = this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size); + WL_RESULT_CHECK(result); + } + this->state.pos = pos; + return result; + } + + return ESP_FAIL; +} + +void WL_Flash::fillOkBuff(int n) +{ + uint32_t* buff = (uint32_t*)this->temp_buff; + + for (int i=0 ; i< 4 ; i++) { + buff[i] = this->state.device_id + n*4 + i; + buff[i] = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&buff[i], sizeof(uint32_t)); + } +} + +bool WL_Flash::OkBuffSet(int n) +{ + bool result = true; + uint32_t* data_buff = (uint32_t*)this->temp_buff; + for (int i=0 ; i< 4 ; i++) { + uint32_t data = this->state.device_id + n*4 + i; + uint32_t crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&data, sizeof(uint32_t)); + if (crc != data_buff[i]) result = false; + } + return result; +} + + esp_err_t WL_Flash::updateWL() { esp_err_t result = ESP_OK; @@ -316,15 +449,16 @@ esp_err_t WL_Flash::updateWL() // Here we will update structures... // Update bits and save to flash: uint32_t byte_pos = this->state.pos * this->cfg.wr_size; - this->used_bits = 0; + this->fillOkBuff(this->state.pos); // write state to mem. We updating only affected bits - result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, &this->used_bits, this->cfg.wr_size); + result |= this->flash_drv->write(this->addr_state1 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size); if (result != ESP_OK) { ESP_LOGE(TAG, "%s - update position 1 result=%08x", __func__, result); this->state.access_count = this->state.max_count - 1; // we will update next time return result; } - result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, &this->used_bits, this->cfg.wr_size); + this->fillOkBuff(this->state.pos); + result |= this->flash_drv->write(this->addr_state2 + sizeof(wl_state_t) + byte_pos, this->temp_buff, this->cfg.wr_size); if (result != ESP_OK) { ESP_LOGE(TAG, "%s - update position 2 result=%08x", __func__, result); this->state.access_count = this->state.max_count - 1; // we will update next time @@ -340,7 +474,7 @@ esp_err_t WL_Flash::updateWL() this->state.move_count = 0; } // write main state - this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, sizeof(wl_state_t) - sizeof(uint32_t)); + this->state.crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)&this->state, offsetof(wl_state_t, crc)); result = this->flash_drv->erase_range(this->addr_state1, this->state_size); WL_RESULT_CHECK(result); @@ -350,7 +484,7 @@ esp_err_t WL_Flash::updateWL() WL_RESULT_CHECK(result); result = this->flash_drv->write(this->addr_state2, &this->state, sizeof(wl_state_t)); WL_RESULT_CHECK(result); - ESP_LOGD(TAG, "%s - move_count=%08x", __func__, this->state.move_count); + ESP_LOGD(TAG, "%s - move_count=%08x, pos=%08x, ", __func__, this->state.move_count, this->state.pos); } // Save structures to the flash... and check result if (result == ESP_OK) { @@ -369,7 +503,7 @@ size_t WL_Flash::calcAddr(size_t addr) } else { result += this->cfg.page_size; } - ESP_LOGV(TAG, "%s - addr=0x%08x -> result=0x%08x", __func__, (uint32_t) addr, (uint32_t) result); + ESP_LOGV(TAG, "%s - addr=0x%08x -> result=0x%08x, dummy_addr=0x%08x", __func__, (uint32_t) addr, (uint32_t) result, (uint32_t)dummy_addr); return result; } @@ -396,7 +530,7 @@ esp_err_t WL_Flash::erase_sector(size_t sector) if (!this->initialized) { return ESP_ERR_INVALID_STATE; } - ESP_LOGV(TAG, "%s - sector=0x%08x", __func__, (uint32_t) sector); + ESP_LOGD(TAG, "%s - sector=0x%08x", __func__, (uint32_t) sector); result = this->updateWL(); WL_RESULT_CHECK(result); size_t virt_addr = this->calcAddr(sector * this->cfg.sector_size); @@ -410,7 +544,7 @@ esp_err_t WL_Flash::erase_range(size_t start_address, size_t size) if (!this->initialized) { return ESP_ERR_INVALID_STATE; } - ESP_LOGV(TAG, "%s - start_address=0x%08x, size=0x%08x", __func__, (uint32_t) start_address, (uint32_t) size); + ESP_LOGD(TAG, "%s - start_address=0x%08x, size=0x%08x", __func__, (uint32_t) start_address, (uint32_t) size); size_t erase_count = (size + this->cfg.sector_size - 1) / this->cfg.sector_size; size_t start_sector = start_address / this->cfg.sector_size; for (size_t i = 0; i < erase_count; i++) { @@ -427,7 +561,7 @@ esp_err_t WL_Flash::write(size_t dest_addr, const void *src, size_t size) if (!this->initialized) { return ESP_ERR_INVALID_STATE; } - ESP_LOGV(TAG, "%s - dest_addr=0x%08x, size=0x%08x", __func__, (uint32_t) dest_addr, (uint32_t) size); + ESP_LOGD(TAG, "%s - dest_addr=0x%08x, size=0x%08x", __func__, (uint32_t) dest_addr, (uint32_t) size); uint32_t count = (size - 1) / this->cfg.page_size; for (size_t i = 0; i < count; i++) { size_t virt_addr = this->calcAddr(dest_addr + i * this->cfg.page_size); @@ -446,10 +580,11 @@ esp_err_t WL_Flash::read(size_t src_addr, void *dest, size_t size) if (!this->initialized) { return ESP_ERR_INVALID_STATE; } - ESP_LOGV(TAG, "%s - src_addr=0x%08x, size=0x%08x", __func__, (uint32_t) src_addr, (uint32_t) size); + ESP_LOGD(TAG, "%s - src_addr=0x%08x, size=0x%08x", __func__, (uint32_t) src_addr, (uint32_t) size); uint32_t count = (size - 1) / this->cfg.page_size; for (size_t i = 0; i < count; i++) { size_t virt_addr = this->calcAddr(src_addr + i * this->cfg.page_size); + ESP_LOGV(TAG, "%s - real_addr=0x%08x, size=0x%08x", __func__, (uint32_t) this->cfg.start_addr + virt_addr, (uint32_t) size); result = this->flash_drv->read(this->cfg.start_addr + virt_addr, &((uint8_t *)dest)[i * this->cfg.page_size], this->cfg.page_size); WL_RESULT_CHECK(result); } @@ -473,6 +608,6 @@ esp_err_t WL_Flash::flush() esp_err_t result = ESP_OK; this->state.access_count = this->state.max_count - 1; result = this->updateWL(); - ESP_LOGV(TAG, "%s - result=%08x", __func__, result); + ESP_LOGD(TAG, "%s - result=%08x, move_count=%08x", __func__, result, this->state.move_count); return result; } diff --git a/components/wear_levelling/private_include/WL_Flash.h b/components/wear_levelling/private_include/WL_Flash.h index 182320cafd..fca72de24b 100644 --- a/components/wear_levelling/private_include/WL_Flash.h +++ b/components/wear_levelling/private_include/WL_Flash.h @@ -66,11 +66,17 @@ protected: uint8_t *temp_buff = NULL; size_t dummy_addr; uint8_t used_bits; + uint32_t pos_data[4]; esp_err_t initSections(); esp_err_t updateWL(); esp_err_t recoverPos(); size_t calcAddr(size_t addr); + + esp_err_t updateVersion(); + esp_err_t updateV1_V2(); + void fillOkBuff(int n); + bool OkBuffSet(int n); }; #endif // _WL_Flash_H_ diff --git a/components/wear_levelling/private_include/WL_State.h b/components/wear_levelling/private_include/WL_State.h index 39a76ba5ea..7d232d51ef 100644 --- a/components/wear_levelling/private_include/WL_State.h +++ b/components/wear_levelling/private_include/WL_State.h @@ -19,7 +19,15 @@ * @brief This structure is used to store current state of flash access * */ -typedef struct WL_State_s { +#if defined(_MSC_VER) +#define ALIGNED_(x) __declspec(align(x)) +#else +#if defined(__GNUC__) +#define ALIGNED_(x) __attribute__ ((aligned(x))) +#endif +#endif + +typedef struct ALIGNED_(32) WL_State_s { public: uint32_t pos; /*!< current dummy block position*/ uint32_t max_pos; /*!< maximum amount of positions*/ @@ -28,6 +36,7 @@ public: uint32_t max_count; /*!< max access count when block will be moved*/ uint32_t block_size; /*!< size of move block*/ uint32_t version; /*!< state id used to identify the version of current libary implementaion*/ + uint32_t device_id; /*!< ID of current WL instance*/ uint32_t crc; /*!< CRC of structure*/ } wl_state_t; diff --git a/components/wear_levelling/test/test_wl.c b/components/wear_levelling/test/test_wl.c index 8aa3e6f439..b875262c09 100644 --- a/components/wear_levelling/test/test_wl.c +++ b/components/wear_levelling/test/test_wl.c @@ -6,6 +6,8 @@ #include "freertos/portable.h" #include "freertos/task.h" #include "freertos/semphr.h" +#include "esp_clk.h" +#include "soc/cpu.h" TEST_CASE("wl_unmount doesn't leak memory", "[wear_levelling]") { @@ -27,19 +29,26 @@ TEST_CASE("wl_mount check partition parameters", "[wear_levelling][ignore]") memcpy(&fake_partition, test_partition, sizeof(fake_partition)); wl_handle_t handle; size_t size_before, size_after; + wl_unmount(WL_INVALID_HANDLE); - // test small partition - fake_partition.size = SPI_FLASH_SEC_SIZE; - size_before = xPortGetFreeHeapSize(); - TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle)); - size_after = xPortGetFreeHeapSize(); - TEST_ASSERT_EQUAL_HEX32(size_before, size_after); - // currently this test leaks memory + esp_partition_erase_range(test_partition, test_partition->address, test_partition->size); + // test small partition: result should be error + for (int i=0 ; i< 5 ; i++) + { + fake_partition.size = SPI_FLASH_SEC_SIZE*(i); + size_before = xPortGetFreeHeapSize(); + TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle)); + size_after = xPortGetFreeHeapSize(); + TEST_ASSERT_EQUAL_HEX32(size_before, size_after); + printf("Test for size 0x%08x passed\n", fake_partition.size); + // currently this test leaks memory + } - // test slightly bigger partition - fake_partition.size = SPI_FLASH_SEC_SIZE * 3; + // test minimum size partition: result should be OK + fake_partition.size = SPI_FLASH_SEC_SIZE * 5; size_before = xPortGetFreeHeapSize(); - TEST_ESP_ERR(ESP_ERR_INVALID_ARG, wl_mount(&fake_partition, &handle)); + TEST_ESP_OK(wl_mount(&fake_partition, &handle)); + wl_unmount(handle); size_after = xPortGetFreeHeapSize(); TEST_ASSERT_EQUAL_HEX32(size_before, size_after); // currently this test hangs @@ -151,3 +160,79 @@ TEST_CASE("multiple tasks can access wl handle simultaneously", "[wear_levelling vSemaphoreDelete(args4.done); wl_unmount(handle); } + +#define TEST_SECTORS_COUNT 8 + +static void check_mem_data(wl_handle_t handle, uint32_t init_val, uint32_t* buff) +{ + size_t sector_size = wl_sector_size(handle); + + for (int m=0 ; m < TEST_SECTORS_COUNT ; m++) { + TEST_ESP_OK(wl_read(handle, sector_size * m, buff, sector_size)); + for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) { + uint32_t compare_val = init_val + i + m*sector_size; + TEST_ASSERT_EQUAL( buff[i], compare_val); + } + } +} + + +// We write complete memory with defined data +// And then write one sector many times. +// A data in other secors should be the same. +// We do this also with unmount +TEST_CASE("multiple write is correct", "[wear_levelling]") +{ + const esp_partition_t *partition = get_test_data_partition(); + esp_partition_t fake_partition; + memcpy(&fake_partition, partition, sizeof(fake_partition)); + + fake_partition.size = SPI_FLASH_SEC_SIZE*(4 + TEST_SECTORS_COUNT); + + wl_handle_t handle; + TEST_ESP_OK(wl_mount(&fake_partition, &handle)); + + size_t sector_size = wl_sector_size(handle); + // Erase 8 sectors + TEST_ESP_OK(wl_erase_range(handle, 0, sector_size * TEST_SECTORS_COUNT)); + // Write data to all sectors + printf("Check 1 sector_size=0x%08x\n", sector_size); + // Set initial random value + uint32_t init_val = rand(); + + uint32_t* buff = (uint32_t*)malloc(sector_size); + for (int m=0 ; m < TEST_SECTORS_COUNT ; m++) { + for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) { + buff[i] = init_val + i + m*sector_size; + } + TEST_ESP_OK(wl_erase_range(handle, sector_size*m, sector_size)); + TEST_ESP_OK(wl_write(handle, sector_size*m, buff, sector_size)); + } + + check_mem_data(handle, init_val, buff); + + uint32_t start; + RSR(CCOUNT, start); + + + for (int m=0 ; m< 100000 ; m++) { + uint32_t sector = m % TEST_SECTORS_COUNT; + for (int i=0 ; i< sector_size/sizeof(uint32_t) ; i++) { + buff[i] = init_val + i + sector*sector_size; + } + TEST_ESP_OK(wl_erase_range(handle, sector_size*sector, sector_size)); + TEST_ESP_OK(wl_write(handle, sector_size*sector, buff, sector_size)); + check_mem_data(handle, init_val, buff); + + uint32_t end; + RSR(CCOUNT, end); + uint32_t ms = (end - start) / (esp_clk_cpu_freq() / 1000); + printf("loop %4i pass, time= %ims\n", m, ms); + if (ms > 10000) { + break; + } + } + + free(buff); + wl_unmount(handle); +} diff --git a/components/wear_levelling/wear_levelling.cpp b/components/wear_levelling/wear_levelling.cpp index 798fb629da..b878ff9190 100644 --- a/components/wear_levelling/wear_levelling.cpp +++ b/components/wear_levelling/wear_levelling.cpp @@ -45,7 +45,7 @@ #endif //WL_DEFAULT_START_ADDR #ifndef WL_CURRENT_VERSION -#define WL_CURRENT_VERSION 1 +#define WL_CURRENT_VERSION 2 #endif //WL_CURRENT_VERSION typedef struct {