浏览代码

Merge branch 'feature/wl_host_test_cmake' into 'master'

Storage: Migrate WL host test to CMake

See merge request espressif/esp-idf!23015
Radek Tandler 2 年之前
父节点
当前提交
d8b8ab5d43

+ 0 - 10
.gitlab/ci/host-test.yml

@@ -40,16 +40,6 @@ test_partition_table_on_host:
     - cd components/partition_table/test_gen_esp32part_host
     - ./gen_esp32part_tests.py
 
-test_wl_on_host:
-  extends: .host_test_template
-  artifacts:
-    paths:
-      - components/wear_levelling/test_wl_host/coverage_report.zip
-    expire_in: 1 week
-  script:
-    - cd components/wear_levelling/test_wl_host
-    - make test
-
 test_fatfs_on_host:
   extends: .host_test_template
   script:

+ 2 - 0
components/spi_flash/CMakeLists.txt

@@ -1,5 +1,7 @@
 idf_build_get_property(target IDF_TARGET)
 if(${target} STREQUAL "linux")
+    idf_component_register(INCLUDE_DIRS include
+                           PRIV_INCLUDE_DIRS include/spi_flash)
     return()
 endif()
 

+ 4 - 0
components/wear_levelling/.build-test-rules.yml

@@ -1,5 +1,9 @@
 # Documentation: .gitlab/ci/README.md#manifest-file-to-control-the-buildtest-apps
 
+components/wear_levelling/host_test:
+  enable:
+    - if: IDF_TARGET == "linux"
+      reason: only test on linux
 components/wear_levelling/test_apps:
   enable:
     - if: IDF_TARGET in ["esp32", "esp32c3"]

+ 3 - 3
components/wear_levelling/WL_Flash.cpp

@@ -153,7 +153,7 @@ esp_err_t WL_Flash::init()
                 WL_RESULT_CHECK(result);
                 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++) {
+                for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)); i++) {
                     bool pos_bits;
                     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);
@@ -187,7 +187,7 @@ esp_err_t WL_Flash::init()
             WL_RESULT_CHECK(result);
             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++) {
+            for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)); i++) {
                 bool pos_bits;
                 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);
@@ -204,7 +204,7 @@ esp_err_t WL_Flash::init()
             WL_RESULT_CHECK(result);
             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++) {
+            for (size_t i = 0; i < ((this->cfg.full_mem_size / this->cfg.sector_size)); i++) {
                 bool pos_bits;
                 result = this->flash_drv->read(this->addr_state2 + sizeof(wl_state_t) + i * this->cfg.wr_size, this->temp_buff, this->cfg.wr_size);
 

+ 2 - 2
components/wear_levelling/crc32.cpp

@@ -4,9 +4,9 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 #include "crc32.h"
-#include "esp32/rom/crc.h"
+#include "esp_rom_crc.h"
 
 unsigned int crc32::crc32_le(unsigned int crc, unsigned char const *buf, unsigned int len)
 {
-    return ::crc32_le(crc, buf, len);
+    return ::esp_rom_crc32_le(crc, buf, len);
 }

+ 10 - 0
components/wear_levelling/host_test/CMakeLists.txt

@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.16)
+
+include($ENV{IDF_PATH}/tools/cmake/project.cmake)
+set(COMPONENTS main)
+# Freertos is included via common components. However, CATCH isn't compatible with the FreeRTOS component yet, hence
+# using the FreeRTOS mock component.
+# target.
+list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
+
+project(wear_levelling_host_test)

+ 2 - 0
components/wear_levelling/host_test/README.md

@@ -0,0 +1,2 @@
+| Supported Targets | Linux |
+| ----------------- | ----- |

+ 8 - 0
components/wear_levelling/host_test/main/CMakeLists.txt

@@ -0,0 +1,8 @@
+idf_component_register(SRCS "main.cpp"
+                            "test_wl.cpp"
+                       INCLUDE_DIRS "$ENV{IDF_PATH}/tools/catch"
+                       PRIV_INCLUDE_DIRS "../../private_include"
+                            "../.."
+                       REQUIRES wear_levelling
+                       WHOLE_ARCHIVE
+                       )

+ 0 - 0
components/wear_levelling/test_wl_host/esp_error_check_stub.cpp → components/wear_levelling/host_test/main/esp_error_check_stub.cpp


+ 0 - 0
components/wear_levelling/test_wl_host/main.cpp → components/wear_levelling/host_test/main/main.cpp


+ 428 - 0
components/wear_levelling/host_test/main/test_wl.cpp

@@ -0,0 +1,428 @@
+/*
+ * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "esp_partition.h"
+#include "esp_private/partition_linux.h"
+
+#include "wear_levelling.h"
+#include "WL_Flash.h"
+#include "crc32.h"
+
+
+#include "catch.hpp"
+
+#include "sdkconfig.h"
+
+#include "esp_log.h"
+static const char *TAG = "test_wl";
+
+// Number of test cycles. Prime number close to 100
+#define TEST_COUNT_MAX 101
+
+// Number of erase operations until emulated power off error is raised
+// Prime number close to 100
+#define ERASE_CYCLES_TILL_POWER_OFF 97
+
+TEST_CASE("write and read back data", "[wear_levelling]")
+{
+    esp_err_t result;
+    wl_handle_t wl_handle;
+
+    int flash_handle;
+    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
+
+    // Mount wear-levelled partition
+    result = wl_mount(partition, &wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    // Get the sector size
+    uint32_t sector_size = wl_sector_size(wl_handle);
+    REQUIRE(sector_size == CONFIG_WL_SECTOR_SIZE);
+
+    uint8_t* data = (uint8_t*) malloc(partition->size);
+    uint8_t* read = (uint8_t*) malloc(partition->size);
+
+    uint32_t sectors = partition->size / sector_size;
+
+    // Generate data
+    for(uint32_t sector = 0; sector < sectors; sector++)
+    {
+        uint32_t sector_address = sector * sector_size;
+
+        for(uint32_t i = 0; i < sector_size / sizeof(i); i++)
+        {
+            ((uint32_t*) data)[i] = sector_address + i;
+        }
+    }
+
+    // Write data
+    result = wl_write(wl_handle, 0, data, partition->size);
+    REQUIRE(result == ESP_OK);
+
+    // Read data
+    result = wl_read(wl_handle, 0, read, partition->size);
+    REQUIRE(result == ESP_OK);
+
+    // Verify that written and read data match
+    REQUIRE(memcmp(data, read, partition->size));
+
+    // Erase some ranges
+    result = wl_erase_range(wl_handle, 0, sector_size);
+    REQUIRE(result == ESP_OK);
+    result = wl_erase_range(wl_handle, 12288, sector_size * 2);
+    REQUIRE(result == ESP_OK);
+    result = wl_erase_range(wl_handle, 28672, sector_size * 3);
+    REQUIRE(result == ESP_OK);
+
+    // Expected data after erasure
+    memset(data + 0, 0xFF, sector_size);
+    memset(data + 12288, 0xFF, sector_size * 2);
+    memset(data + 28672, 0xFF, sector_size * 3);
+
+    // Read again, with erased ranges
+    result = wl_read(wl_handle, 0, read, partition->size);
+    REQUIRE(result == ESP_OK);
+
+    // Verify that written and read data match
+    REQUIRE(memcmp(data, read, partition->size));
+
+    // Unmount
+    result = wl_unmount(wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    free(data);
+    free(read);
+}
+
+TEST_CASE("power down test", "[wear_levelling]")
+{
+    esp_err_t result;
+    wl_handle_t wl_handle;
+
+    int flash_handle;
+    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
+
+    // Disable power down failure counting
+    esp_partition_fail_after(SIZE_MAX, 0);
+
+    // Mount wear-levelled partition
+    result = wl_mount(partition, &wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    // Get wl partition information
+    size_t sector_size = wl_sector_size(wl_handle);
+    int32_t sectors_count = wl_size(wl_handle) / sector_size;
+
+    uint32_t add_const = 0;
+    uint32_t *sector_data = new uint32_t[sector_size / sizeof(uint32_t)];
+
+    // Fill partition with check data
+    for (int32_t i = 0; i < sectors_count; i++) {
+        ESP_LOGV(TAG, "%s(%d): wl_erase_range (*, %lu, %zu)", __FUNCTION__, __LINE__, i * sector_size, sector_size);
+        REQUIRE(wl_erase_range(wl_handle, i * sector_size, sector_size) == ESP_OK);
+        for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
+            uint32_t temp_data = i * sector_size + add_const + m;
+            sector_data[m] = temp_data;
+        }
+        ESP_LOGV(TAG, "%s(%d): wl_write (*, %lu, *, %zu)", __FUNCTION__, __LINE__, i * sector_size, sector_size);
+        REQUIRE(wl_write(wl_handle, i * sector_size, sector_data, sector_size) == ESP_OK);
+    }
+
+    for (int32_t i = 0; i < sectors_count; i++) {
+        ESP_LOGV(TAG, "%s(%d): wl_read (*, %lu, *, %zu)", __FUNCTION__, __LINE__, i * sector_size, sector_size);
+        result |= wl_read(wl_handle, i * sector_size, sector_data, sector_size);
+        for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
+            uint32_t temp_data = i * sector_size + add_const + m;
+            REQUIRE(temp_data == sector_data[m]);
+            if (temp_data != sector_data[m]) {
+                printf("Error - read: %08x, expected %08x\n", sector_data[m], temp_data);
+            }
+        }
+    }
+
+    // Perform test
+    int32_t max_count = ERASE_CYCLES_TILL_POWER_OFF;
+    int32_t max_check_count = TEST_COUNT_MAX;
+
+    ESP_LOGI(TAG, "%s(%d): max_check_count = %d)", __FUNCTION__, __LINE__, max_check_count);
+
+    for (int32_t k = 0; k < max_check_count; k++) {
+
+        // Enable power down failure after max_count cycles
+        esp_partition_fail_after(max_count, ESP_PARTITION_FAIL_AFTER_MODE_BOTH);
+
+        int32_t err_sector = -1;
+        for (int32_t i = 0; i < sectors_count; i++) {
+            result = ESP_OK;
+            ESP_LOGV(TAG, "%s(%d): wl_erase_range (*, %lu, %zu)", __FUNCTION__, __LINE__, i * sector_size, sector_size);
+            result = wl_erase_range(wl_handle, i * sector_size, sector_size);
+            if (result != ESP_OK) {
+                err_sector = i;
+                break;
+            }
+
+            for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
+                uint32_t temp_data = i * sector_size + add_const + m;
+                sector_data[m] = temp_data;
+            }
+            ESP_LOGV(TAG, "%s(%d): wl_write (*, %lu, *, %zu)", __FUNCTION__, __LINE__, i * sector_size, sector_size);
+            result = wl_write(wl_handle, i * sector_size, sector_data, sector_size);
+            if (result != ESP_OK) {
+                err_sector = i;
+                break;
+            }
+        }
+
+        if (err_sector >= 0) {
+            max_count++;
+        } else {
+            max_count = 0;
+        }
+
+        // Call unmount, but don't care about the result as the power down failure may be persisting or even arise during the unmount.
+        // In real power down scenario, this function won't be called, here in the test, we need it to free wl handles in driver.
+        ESP_LOGV(TAG, "%s(%d): wl_unmount", __FUNCTION__, __LINE__);
+        wl_unmount(wl_handle);
+
+        // Disable power down failure counting
+        esp_partition_fail_after(SIZE_MAX, 0);
+
+        ESP_LOGV(TAG, "%s(%d): wl_mount", __FUNCTION__, __LINE__);
+        result = wl_mount(partition, &wl_handle);
+        REQUIRE(result == ESP_OK);
+
+        for (int32_t i = 0; i < sectors_count; i++) {
+            if (i != err_sector) {
+                ESP_LOGV(TAG, "%s(%d): wl_read (*, %lu, *, %zu)", __FUNCTION__, __LINE__, i * sector_size, sector_size);
+                result |= wl_read(wl_handle, i * sector_size, sector_data, sector_size);
+                for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
+                    uint32_t temp_data = i * sector_size + add_const + m;
+                    REQUIRE(temp_data == sector_data[m]);
+                    if (temp_data != sector_data[m]) {
+                        printf("Error - read: %08x, expected %08x, m=%i, sector=%i\n", sector_data[m], temp_data, m, i);
+                    }
+                }
+            }
+        }
+
+        if (err_sector != -1) {
+            ESP_LOGV(TAG, "%s(%d): wl_erase_range (*, %lu, %zu)", __FUNCTION__, __LINE__, err_sector * sector_size, sector_size);
+            result |= wl_erase_range(wl_handle, err_sector * sector_size, sector_size);
+            for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
+                uint32_t temp_data = err_sector * sector_size + add_const + m;
+                sector_data[m] = temp_data;
+            }
+            ESP_LOGV(TAG, "%s(%d): wl_write (*, %lu, *, %zu)", __FUNCTION__, __LINE__, err_sector * sector_size, sector_size);
+            result |= wl_write(wl_handle, err_sector * sector_size, sector_data, sector_size);
+        }
+    }
+
+    delete[] sector_data;
+
+    // Unmount
+    ESP_LOGV(TAG, "%s(%d): wl_unmount", __FUNCTION__, __LINE__);
+    result = wl_unmount(wl_handle);
+    REQUIRE(result == ESP_OK);
+}
+
+// Calculates wl status blocks offsets and status block size
+void calculate_wl_state_address_info(const esp_partition_t *partition, size_t *offset_state_1, size_t *offset_state_2, size_t *state_size)
+{
+    // This code follows ::init of WL_Flash.cpp
+    // and define directives from wear_levelling.cpp
+
+    // get sector size
+    esp_err_t result;
+    wl_handle_t wl_handle;
+
+    // Try to mount wear-levelled partition
+    ESP_LOGD(TAG, "wl_mount");
+    result = wl_mount(partition, &wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    size_t sector_size = wl_sector_size(wl_handle); //SPI_FLASH_SEC_SIZE 4096;
+    REQUIRE(sector_size == CONFIG_WL_SECTOR_SIZE);
+
+    // Unmount
+    ESP_LOGD(TAG, "wl_unmount");
+    result = wl_unmount(wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    // rest of parameters
+    size_t full_mem_size = partition->size;
+    size_t start_addr = 0; // WL_DEFAULT_START_ADDR   0
+    size_t wr_size = 16; // WL_DEFAULT_WRITE_SIZE   16
+    size_t cfg_size = 0;
+
+
+    *state_size = sector_size;
+    if (*state_size < (sizeof(wl_state_t) + (full_mem_size / sector_size) * wr_size)) {
+        *state_size = ((sizeof(wl_state_t) + (full_mem_size / sector_size) * wr_size) + sector_size - 1) / sector_size;
+        *state_size = *state_size * sector_size;
+    }
+    cfg_size = (sizeof(wl_config_t) + sector_size - 1) / sector_size;
+    cfg_size = cfg_size * sector_size;
+
+    *offset_state_1 = start_addr + full_mem_size - *state_size * 2 - cfg_size;
+    *offset_state_2 = start_addr + full_mem_size - *state_size * 1 - cfg_size;
+}
+
+#ifndef WL_CFG_CRC_CONST
+#define WL_CFG_CRC_CONST UINT32_MAX
+#endif // WL_CFG_CRC_CONST
+
+// calculates crc of wear levelling state block
+void calculate_wl_state_crc(WL_State_s *state_ptr)
+{
+    int check_size = WL_STATE_CRC_LEN_V2;
+    // Chech CRC and recover state
+    state_ptr->crc = crc32::crc32_le(WL_CFG_CRC_CONST, (uint8_t *)state_ptr, check_size);
+ }
+
+TEST_CASE("power down during WL status 1 update", "[wear_levelling]")
+{
+    // Manipulates wl status block 1 as if it wasn't written correctly due to power down event
+    // Tries to let such a damaged flash wl_mount (and recover)
+
+    ESP_LOGI(TAG, "power down during WL status 1 update");
+
+    esp_err_t result;
+    wl_handle_t wl_handle;
+
+    int flash_handle;
+    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
+
+    size_t offset_state_1, offset_state_2, size_state = 0;
+
+    // get offsets of respective status blocks in flash
+    calculate_wl_state_address_info(partition, &offset_state_1, &offset_state_2, &size_state);
+
+    // allocate temporary buffer for status manipulation
+    uint8_t* tmp_state = (uint8_t*) malloc(size_state);
+
+    // damage 1st status block
+    memset(tmp_state, 0xff, size_state);
+
+    ESP_LOGD(TAG, "esp_partition_erase_range offset: %zu size: %zu", offset_state_1, size_state);
+    result = esp_partition_erase_range(partition, offset_state_1, size_state);
+    REQUIRE(result == ESP_OK);
+    ESP_LOGD(TAG, "esp_partition_write offset: %zu size: %zu", offset_state_1, size_state);
+    result = esp_partition_write(partition, offset_state_1, tmp_state, size_state);
+    REQUIRE(result == ESP_OK);
+
+    // Try to mount wear-levelled partition
+    ESP_LOGD(TAG, "wl_mount");
+    result = wl_mount(partition, &wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    // Unmount
+    ESP_LOGD(TAG, "wl_unmount");
+    result = wl_unmount(wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    free(tmp_state);
+}
+
+TEST_CASE("power down during WL status 2 update", "[wear_levelling]")
+{
+    // Manipulates wl status block 2 as if it wasn't written correctly due to power down event
+    // Tries to let such a damaged flash wl_mount (and recover)
+
+    ESP_LOGI(TAG, "power down during WL status 2 update");
+
+    esp_err_t result;
+    wl_handle_t wl_handle;
+
+    int flash_handle;
+    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
+
+    size_t offset_state_1, offset_state_2, size_state = 0;
+
+    // get offsets of respective status blocks in flash
+    calculate_wl_state_address_info(partition, &offset_state_1, &offset_state_2, &size_state);
+
+    // allocate temporary buffer for status manipulation
+    uint8_t* tmp_state = (uint8_t*) malloc(size_state);
+
+    // damage 2nd status block
+    memset(tmp_state, 0xff, size_state);
+
+    ESP_LOGD(TAG, "esp_partition_erase_range offset: %zu size: %zu", offset_state_2, size_state);
+    result = esp_partition_erase_range(partition, offset_state_2, size_state);
+    REQUIRE(result == ESP_OK);
+    ESP_LOGD(TAG, "esp_partition_write offset: %zu size: %zu", offset_state_2, size_state);
+    result = esp_partition_write(partition, offset_state_2, tmp_state, size_state);
+    REQUIRE(result == ESP_OK);
+
+    // Try to mount wear-levelled partition
+    ESP_LOGD(TAG, "wl_mount");
+    result = wl_mount(partition, &wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    // Unmount
+    ESP_LOGD(TAG, "wl_unmount");
+    result = wl_unmount(wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    free(tmp_state);
+}
+
+TEST_CASE("power down between WL status 1 and WL status 2 update", "[wear_levelling]")
+{
+    // Manipulates wl status block 2 and reclaculates its crc just to have two different ones as if it wasn't updates due to power down event
+    // Tries to let such a damaged flash wl_mount (and recover)
+
+    ESP_LOGI(TAG, "power down between WL status 1 and WL status 2 update");
+
+    esp_err_t result;
+    wl_handle_t wl_handle;
+
+    int flash_handle;
+    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
+
+    size_t offset_state_1, offset_state_2, size_state = 0;
+
+    // get offsets of respective status blocks in flash
+    calculate_wl_state_address_info(partition, &offset_state_1, &offset_state_2, &size_state);
+
+    // allocate temporary buffer for status manipulation
+    uint8_t* tmp_state = (uint8_t*) malloc(size_state);
+
+    // unsync 1st and 2nd block state - change move count in 2nd block and recalculate its crc
+
+    // read actual status2
+    ESP_LOGD(TAG, "esp_partition_read offset: %zu size: %zu", offset_state_2, size_state);
+    result = esp_partition_read(partition, offset_state_2, tmp_state, size_state);
+    REQUIRE(result == ESP_OK);
+
+    // change move count and recalc crc
+    WL_State_s *state_ptr = (WL_State_s *) tmp_state;
+    state_ptr->move_count++;
+    calculate_wl_state_crc(state_ptr);
+
+    // write back modified status2
+    ESP_LOGD(TAG, "esp_partition_erase_range offset: %zu size: %zu", offset_state_2, size_state);
+    result = esp_partition_erase_range(partition, offset_state_2, size_state);
+    REQUIRE(result == ESP_OK);
+    ESP_LOGD(TAG, "esp_partition_write offset: %zu size: %zu", offset_state_2, size_state);
+    result = esp_partition_write(partition, offset_state_2, tmp_state, size_state);
+    REQUIRE(result == ESP_OK);
+
+    // Try to mount wear-levelled partition
+    ESP_LOGD(TAG, "wl_mount");
+    result = wl_mount(partition, &wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    // Unmount
+    ESP_LOGD(TAG, "wl_unmount");
+    result = wl_unmount(wl_handle);
+    REQUIRE(result == ESP_OK);
+
+    free(tmp_state);
+}

+ 0 - 0
components/wear_levelling/test_wl_host/partition_table.csv → components/wear_levelling/host_test/partition_table.csv


+ 10 - 0
components/wear_levelling/host_test/pytest_wear_levelling_linux.py

@@ -0,0 +1,10 @@
+# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
+# SPDX-License-Identifier: Unlicense OR CC0-1.0
+import pytest
+from pytest_embedded import Dut
+
+
+@pytest.mark.linux
+@pytest.mark.host_test
+def test_wear_levelling_linux(dut: Dut) -> None:
+    dut.expect_exact('All tests passed', timeout=120)

+ 12 - 0
components/wear_levelling/host_test/sdkconfig.defaults

@@ -0,0 +1,12 @@
+CONFIG_IDF_TARGET="linux"
+CONFIG_COMPILER_CXX_EXCEPTIONS=y
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=n
+CONFIG_WL_SECTOR_SIZE=4096
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_CUSTOM=y
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partition_table.csv"
+CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
+CONFIG_SPI_FLASH_USE_LEGACY_IMPL=1
+CONFIG_MMU_PAGE_SIZE=0X10000
+CONFIG_ESP_PARTITION_ENABLE_STATS=y

+ 1 - 0
components/wear_levelling/test_wl_host/Makefile.files

@@ -2,6 +2,7 @@ SOURCE_FILES := \
 	$(addprefix ../, \
 	wear_levelling.cpp \
 	crc32.cpp \
+	../esp_rom/linux/esp_rom_crc.c \
 	WL_Flash.cpp \
 	Partition.cpp \
 	)

+ 0 - 215
components/wear_levelling/test_wl_host/test_wl.cpp

@@ -1,215 +0,0 @@
-/*
- * SPDX-FileCopyrightText: 2016-2022 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "spi_flash_mmap.h"
-#include "esp_partition.h"
-#include "wear_levelling.h"
-#include "WL_Flash.h"
-#include "SpiFlash.h"
-
-#include "catch.hpp"
-
-#include "sdkconfig.h"
-
-extern "C" void _spi_flash_init(const char* chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
-extern SpiFlash spiflash;
-
-#define TEST_COUNT_MAX 100
-
-TEST_CASE("write and read back data", "[wear_levelling]")
-{
-    _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
-
-    esp_err_t result;
-    wl_handle_t wl_handle;
-
-    int flash_handle;
-    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
-
-    // Mount wear-levelled partition
-    result = wl_mount(partition, &wl_handle);
-    REQUIRE(result == ESP_OK);
-
-    // Get the sector size
-    uint32_t sector_size = wl_sector_size(wl_handle);
-    REQUIRE(sector_size == CONFIG_WL_SECTOR_SIZE);
-
-    uint8_t* data = (uint8_t*) malloc(partition->size);
-    uint8_t* read = (uint8_t*) malloc(partition->size);
-
-    uint32_t sectors = partition->size / sector_size;
-
-    // Generate data
-    for(uint32_t sector = 0; sector < sectors; sector++)
-    {
-        uint32_t sector_address = sector * sector_size;
-
-        for(uint32_t i = 0; i < sector_size / sizeof(i); i++)
-        {
-            ((uint32_t*) data)[i] = sector_address + i;
-        }
-    }
-
-    // Write data
-    result = wl_write(wl_handle, 0, data, partition->size);
-    REQUIRE(result == ESP_OK);
-
-    // Read data
-    result = wl_read(wl_handle, 0, read, partition->size);
-    REQUIRE(result == ESP_OK);
-
-    // Verify that written and read data match
-    REQUIRE(memcmp(data, read, partition->size));
-
-    // Erase some ranges
-    result = wl_erase_range(wl_handle, 0, sector_size);
-    REQUIRE(result == ESP_OK);
-    result = wl_erase_range(wl_handle, 12288, sector_size * 2);
-    REQUIRE(result == ESP_OK);
-    result = wl_erase_range(wl_handle, 28672, sector_size * 3);
-    REQUIRE(result == ESP_OK);
-
-    // Expected data after erasure
-    memset(data + 0, 0xFF, sector_size);
-    memset(data + 12288, 0xFF, sector_size * 2);
-    memset(data + 28672, 0xFF, sector_size * 3);
-
-    // Read again, with erased ranges
-    result = wl_read(wl_handle, 0, read, partition->size);
-    REQUIRE(result == ESP_OK);
-
-    // Verify that written and read data match
-    REQUIRE(memcmp(data, read, partition->size));
-
-    // Unmount
-    result = wl_unmount(wl_handle);
-    REQUIRE(result == ESP_OK);
-
-    free(data);
-    free(read);
-}
-
-TEST_CASE("power down test", "[wear_levelling]")
-{
-    _spi_flash_init(CONFIG_ESPTOOLPY_FLASHSIZE, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
-
-    esp_err_t result;
-    wl_handle_t wl_handle;
-
-    int flash_handle;
-    const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
-
-    // Mount wear-levelled partition
-    result = wl_mount(partition, &wl_handle);
-    REQUIRE(result == ESP_OK);
-
-    // Get wl partition information
-    size_t sector_size = wl_sector_size(wl_handle);
-    int32_t sectors_count = wl_size(wl_handle) / sector_size;
-
-    uint32_t add_const = 0;
-    uint32_t *sector_data = new uint32_t[sector_size / sizeof(uint32_t)];
-
-    // Fill partition with check data
-    for (int32_t i = 0; i < sectors_count; i++) {
-        REQUIRE(wl_erase_range(wl_handle, i * sector_size, sector_size) == ESP_OK);
-        for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
-            uint32_t temp_data = i * sector_size + add_const + m;
-            sector_data[m] = temp_data;
-        }
-        REQUIRE(wl_write(wl_handle, i * sector_size, sector_data, sector_size) == ESP_OK);
-    }
-
-    for (int32_t i = 0; i < sectors_count; i++) {
-        result |= wl_read(wl_handle, i * sector_size, sector_data, sector_size);
-        for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
-            uint32_t temp_data = i * sector_size + add_const + m;
-            REQUIRE(temp_data == sector_data[m]);
-            if (temp_data != sector_data[m]) {
-                printf("Error - read: %08x, expected %08x\n", sector_data[m], temp_data);
-            }
-        }
-    }
-
-    // Perform test
-    int32_t max_count = 100;
-    int32_t max_check_count = TEST_COUNT_MAX;
-
-    printf("used_sectors_count=%d\n", max_check_count);
-
-    for (int32_t k = 0; k < max_check_count; k++) {
-
-        spiflash.set_total_erase_cycles_limit(max_count);
-
-        int32_t err_sector = -1;
-        for (int32_t i = 0; i < sectors_count; i++) {
-            result = ESP_OK;
-            result = wl_erase_range(wl_handle, i * sector_size, sector_size);
-            if (result != ESP_OK) {
-                err_sector = i;
-                break;
-            }
-            for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
-                uint32_t temp_data = i * sector_size + add_const + m;
-                sector_data[m] = temp_data;
-            }
-            result = wl_write(wl_handle, i * sector_size, sector_data, sector_size);
-            if (result != ESP_OK) {
-                err_sector = i;
-                break;
-            }
-        }
-
-        if (err_sector >= 0) {
-            max_count++;
-        } else {
-            max_count = 0;
-        }
-
-        spiflash.set_total_erase_cycles_limit(0);
-
-        result = wl_unmount(wl_handle);
-        REQUIRE(result == ESP_OK);
-
-        result = wl_mount(partition, &wl_handle);
-        REQUIRE(result == ESP_OK);
-
-        for (int32_t i = 0; i < sectors_count; i++) {
-            if (i != err_sector) {
-                result |= wl_read(wl_handle, i * sector_size, sector_data, sector_size);
-                for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
-                    uint32_t temp_data = i * sector_size + add_const + m;
-                    REQUIRE(temp_data == sector_data[m]);
-                    if (temp_data != sector_data[m]) {
-                        printf("Error - read: %08x, expected %08x, m=%i, sector=%i\n", sector_data[m], temp_data, m, i);
-                    }
-                }
-            }
-        }
-
-        if (err_sector != -1) {
-            result |= wl_erase_range(wl_handle, err_sector * sector_size, sector_size);
-            for (uint32_t m = 0; m < sector_size / sizeof(uint32_t); m++) {
-                uint32_t temp_data = err_sector * sector_size + add_const + m;
-                sector_data[m] = temp_data;
-            }
-            result |= wl_write(wl_handle, err_sector * sector_size, sector_data, sector_size);
-        }
-
-        spiflash.reset_total_erase_cycles();
-
-        printf("[%3.f%%] err_sector=%i\n", (float)k / ((float)max_check_count) * 100.0f, err_sector);
-    }
-
-    delete[] sector_data;
-
-    // Unmount
-    result = wl_unmount(wl_handle);
-    REQUIRE(result == ESP_OK);
-}