spi_flash: Enable flash emulation down to ROM function calls

This commit is contained in:
Renz Bagaporo 2018-05-26 14:58:01 +08:00 committed by bot
parent c409666d4e
commit 8caab13faa
43 changed files with 742 additions and 556 deletions

View File

@ -1,18 +1,24 @@
TEST_PROGRAM=test_fatfs COMPONENT=fatfs
# Use wear levelling TEST_PROGRAM=test_$(COMPONENT)
TEST_WL_COMPONENT=$(IDF_PATH)/components/wear_levelling
TEST_WL_DIR=$(TEST_WL_COMPONENT)/test_wl_host
TEST_WL_LIB=libtest_wl.a
TEST_PARTITION_SIM_DIR=$(IDF_PATH)/components/spi_flash/sim #Expose as a library
TEST_PARTITION_SIM_LIB=libpartition_sim.a COMPONENT_LIB=lib$(COMPONENT).a
#Use wear levelling and flash simulation
WEAR_LEVELLING=wear_levelling
WEAR_LEVELLING_DIR=../../$(WEAR_LEVELLING)
WEAR_LEVELLING_HOST_DIR=$(WEAR_LEVELLING_DIR)/test_wl_host
WEAR_LEVELLING_LIB=lib$(WEAR_LEVELLING).a
SPI_FLASH=spi_flash
SPI_FLASH_DIR=../../$(SPI_FLASH)
SPI_FLASH_SIM_DIR=$(SPI_FLASH_DIR)/sim
SPI_FLASH_LIB=lib$(SPI_FLASH).a
all: $(TEST_PROGRAM) all: $(TEST_PROGRAM)
SOURCE_FILES = \ SOURCE_FILES = \
main.cpp \
test_fatfs.cpp \
$(addprefix ../src/, \ $(addprefix ../src/, \
diskio.c \ diskio.c \
ff.c \ ff.c \
@ -22,6 +28,11 @@ SOURCE_FILES = \
) \ ) \
$(addprefix ./stubs/, log/log.c) $(addprefix ./stubs/, log/log.c)
TEST_SOURCE_FILES = \
test_fatfs.cpp \
main.cpp \
test_utils.c
INCLUDE_FLAGS = $(addprefix -I,\ INCLUDE_FLAGS = $(addprefix -I,\
../src \ ../src \
. \ . \
@ -31,38 +42,47 @@ INCLUDE_FLAGS = $(addprefix -I,\
sdmmc/include \ sdmmc/include \
log/include \ log/include \
) \ ) \
$(SPI_FLASH_DIR)/include \
$(WEAR_LEVELLING_DIR)/include \
../../esp32/include \ ../../esp32/include \
$(TEST_PARTITION_SIM_DIR)/include \
$(TEST_WL_COMPONENT)/include \
../../../tools/catch \ ../../../tools/catch \
) )
GCOV ?= gcov GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o)) OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o))
$(TEST_WL_DIR)/$(TEST_WL_LIB): force $(WEAR_LEVELLING_HOST_DIR)/$(WEAR_LEVELLING_LIB): force
$(MAKE) -C $(TEST_WL_DIR) lib $(MAKE) -C $(WEAR_LEVELLING_HOST_DIR) lib
$(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB): force $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB): force
$(MAKE) -C $(TEST_PARTITION_SIM_DIR) lib $(MAKE) -C $(SPI_FLASH_SIM_DIR) lib
force: force:
$(TEST_PROGRAM): $(OBJ_FILES) $(TEST_WL_DIR)/$(TEST_WL_LIB) $(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB) $(COMPONENT_LIB): $(OBJ_FILES)
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) -L$(TEST_PARTITION_SIM_DIR) -l:$(TEST_PARTITION_SIM_LIB) -L$(TEST_WL_DIR) -l:$(TEST_WL_LIB) $(AR) rcs $@ $^
lib: $(COMPONENT_LIB)
partition_table.bin: partition_table.csv
python ../../partition_table/gen_esp32part.py --verify $< $@
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB) $(WEAR_LEVELLING_HOST_DIR)/$(WEAR_LEVELLING_LIB) partition_table.bin
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(TEST_OBJ_FILES) -L$(abspath .) -l:$(COMPONENT_LIB) -L$(SPI_FLASH_SIM_DIR) -l:$(SPI_FLASH_LIB) -L$(WEAR_LEVELLING_HOST_DIR) -l:$(WEAR_LEVELLING_LIB) -g -m32
test: $(TEST_PROGRAM) test: $(TEST_PROGRAM)
./$(TEST_PROGRAM) ./$(TEST_PROGRAM)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES:.o=.gc*) COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): $(TEST_PROGRAM) lib $(COVERAGE_FILES): test
coverage.info: $(COVERAGE_FILES) coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} + find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
@ -73,11 +93,11 @@ coverage_report: coverage.info
@echo "Coverage report is in coverage_report/index.html" @echo "Coverage report is in coverage_report/index.html"
clean: clean:
rm -f $(OBJ_FILES) $(TEST_PROGRAM) rm -f $(OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(COMPONENT_LIB) partition_table.bin
$(MAKE) -C $(TEST_WL_DIR) clean $(MAKE) -C $(WEAR_LEVELLING_HOST_DIR) clean
$(MAKE) -C $(TEST_PARTITION_SIM_DIR) clean $(MAKE) -C $(SPI_FLASH_SIM_DIR) clean
rm -f $(COVERAGE_FILES) *.gcov rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/ rm -rf coverage_report/
rm -f coverage.info rm -f coverage.info
.PHONY: clean all test .PHONY: clean all test lib

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M,

View File

@ -9,8 +9,12 @@
#include "catch.hpp" #include "catch.hpp"
extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
TEST_CASE("create volume, open file, write and read back data", "[fatfs]") TEST_CASE("create volume, open file, write and read back data", "[fatfs]")
{ {
init_spi_flash(0x00400000, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
FRESULT fr_result; FRESULT fr_result;
BYTE pdrv; BYTE pdrv;
FATFS fs; FATFS fs;
@ -19,14 +23,11 @@ TEST_CASE("create volume, open file, write and read back data", "[fatfs]")
esp_err_t esp_result; esp_err_t esp_result;
// Create a 4MB partition const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, "storage");
uint32_t size = 0x00400000;
int flash_handle = esp_flash_create(size, 4096, 1);
esp_partition_t partition = esp_partition_create(size, 0, flash_handle);
// Mount wear-levelled partition // Mount wear-levelled partition
wl_handle_t wl_handle; wl_handle_t wl_handle;
esp_result = wl_mount(&partition, &wl_handle); esp_result = wl_mount(partition, &wl_handle);
REQUIRE(esp_result == ESP_OK); REQUIRE(esp_result == ESP_OK);
// Get a physical drive // Get a physical drive
@ -52,22 +53,32 @@ TEST_CASE("create volume, open file, write and read back data", "[fatfs]")
fr_result = f_open(&file, "test.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE); fr_result = f_open(&file, "test.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE);
REQUIRE(fr_result == FR_OK); REQUIRE(fr_result == FR_OK);
const char data[] = "Hello, World!"; // Generate data
char *read = (char*) malloc(sizeof(data)); uint32_t data_size = 100000;
fr_result = f_write(&file, data, sizeof(data), &bw); char *data = (char*) malloc(data_size);
char *read = (char*) malloc(data_size);
for(uint32_t i = 0; i < data_size; i += sizeof(i))
{
*((uint32_t*)(data + i)) = i;
}
// Write generated data
fr_result = f_write(&file, data, data_size, &bw);
REQUIRE(fr_result == FR_OK); REQUIRE(fr_result == FR_OK);
REQUIRE(bw == sizeof(data)); REQUIRE(bw == data_size);
// Move to beginning of file // Move to beginning of file
fr_result = f_lseek(&file, 0); fr_result = f_lseek(&file, 0);
REQUIRE(fr_result == FR_OK); REQUIRE(fr_result == FR_OK);
fr_result = f_read(&file, read, sizeof(data), &bw); // Read written data
fr_result = f_read(&file, read, data_size, &bw);
REQUIRE(fr_result == FR_OK); REQUIRE(fr_result == FR_OK);
REQUIRE(bw == sizeof(data)); REQUIRE(bw == data_size);
REQUIRE(strcmp(data, read) == 0); REQUIRE(memcmp(data, read, data_size) == 0);
// Close file // Close file
fr_result = f_close(&file); fr_result = f_close(&file);
@ -77,7 +88,6 @@ TEST_CASE("create volume, open file, write and read back data", "[fatfs]")
fr_result = f_mount(0, "", 0); fr_result = f_mount(0, "", 0);
REQUIRE(fr_result == FR_OK); REQUIRE(fr_result == FR_OK);
esp_flash_delete(flash_handle);
free(read); free(read);
free(data);
} }

View File

@ -0,0 +1,7 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}

View File

@ -1,130 +0,0 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "Flash_Emulator.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Flash_Emulator::Flash_Emulator(size_t size, size_t sector_sise, size_t min_size)
{
this->reset_count = 0x7fffffff;
this->size = size;
this->sector_sise = sector_sise;
this->min_size = min_size;
this->buff = (uint8_t *)malloc(this->size);
this->access_count = new uint32_t[this->size / this->sector_sise];
memset(this->access_count, 0, this->size / this->sector_sise * sizeof(uint32_t));
memset(this->buff, 1, this->size);
}
size_t Flash_Emulator::chip_size()
{
return this->size;
}
size_t Flash_Emulator::sector_size()
{
return this->sector_sise;
}
esp_err_t Flash_Emulator::erase_sector(size_t sector)
{
esp_err_t result = ESP_OK;
if ((this->reset_count != 0x7fffffff) && (this->reset_count != 0)) {
this->reset_count--;
}
if (this->reset_count <= 0) {
result = ESP_FAIL;
return result;
}
memset(&this->buff[sector * this->sector_sise], -1, this->sector_sise);
this->access_count[sector]++;
return result;
}
uint32_t Flash_Emulator::get_access_minmax()
{
uint32_t min = INT32_MAX;
uint32_t max = 0;
for (size_t i = 0; i < (this->size / this->sector_sise) - 2; i++) {
if (this->access_count[i] < min) {
min = this->access_count[i];
}
if (this->access_count[i] > max) {
max = this->access_count[i];
}
}
return max - min;
}
esp_err_t Flash_Emulator::erase_range(size_t start_address, size_t size)
{
esp_err_t result = ESP_OK;
uint32_t start_sector = start_address / this->sector_sise;
uint32_t count = (size + this->sector_sise - 1) / this->sector_sise;
for (size_t i = 0; i < count; i++) {
result |= this->erase_sector(start_sector + i);
}
return result;
}
esp_err_t Flash_Emulator::write(size_t dest_addr, const void *src, size_t size)
{
esp_err_t result = ESP_OK;
if ((size % this->min_size) != 0) {
result = ESP_ERR_INVALID_SIZE;
return result;
}
if ((dest_addr % this->min_size) != 0) {
result = ESP_ERR_INVALID_SIZE;
return result;
}
if ((this->reset_count != 0x7fffffff) && (this->reset_count != 0)) {
this->reset_count--;
}
if (this->reset_count <= 0) {
result = ESP_FAIL;
return result;
}
memcpy(&this->buff[dest_addr], src, size);
return result;
}
esp_err_t Flash_Emulator::read(size_t src_addr, void *dest, size_t size)
{
esp_err_t result = ESP_OK;
if (this->reset_count <= 0) {
result = ESP_FAIL;
return result;
}
memcpy(dest, &this->buff[src_addr], size);
return result;
}
Flash_Emulator::~Flash_Emulator()
{
free(this->buff);
delete this->access_count;
}
void Flash_Emulator::SetResetCount(uint32_t count)
{
this->reset_count = count;
}
void Flash_Emulator::SetResetSector(size_t sector)
{
this->reset_sector = sector;
}

View File

@ -1,59 +0,0 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _Flash_Emulator_H_
#define _Flash_Emulator_H_
#include "esp_err.h"
/**
* @brief This class is used to emulate flash devices. Class implements Flash_Access interface
*
*/
class Flash_Emulator
{
public:
Flash_Emulator(size_t size, size_t sector_sise, size_t min_size);
virtual size_t chip_size();
virtual esp_err_t erase_sector(size_t sector);
virtual esp_err_t erase_range(size_t start_address, size_t size);
virtual esp_err_t write(size_t dest_addr, const void *src, size_t size);
virtual esp_err_t read(size_t src_addr, void *dest, size_t size);
virtual size_t sector_size();
virtual ~Flash_Emulator();
uint32_t get_access_minmax();
public:
size_t size;
size_t sector_sise;
size_t min_size;
uint8_t *buff;
uint32_t *access_count;
public:
uint32_t reset_count;
size_t reset_sector;
void SetResetCount(uint32_t count);
void SetResetSector(size_t sector);
};
#endif // _Flash_Emulator_H_

View File

@ -1,34 +1,54 @@
PARTITION_SIM=partition_sim COMPONENT=spi_flash
PARTITION_SIM_LIB=lib$(PARTITION_SIM).a COMPONENT_LIB=lib$(COMPONENT).a
lib: $(PARTITION_SIM_LIB) all: lib
SOURCE_FILES = \ SOURCE_FILES = \
Flash_Emulator.cpp \ ../partition.c \
partition.c ../flash_ops.c \
SpiFlash.cpp \
flash_mock_util.c \
flash_mock.cpp \
$(addprefix stubs/, \
newlib/lock.c \
app_update/esp_ota_eps.c \
)
INCLUDE_FLAGS = $(addprefix -I,\ INCLUDE_FLAGS = $(addprefix -I,\
. \ . \
./include \ ../include \
../../esp32/include/ \ ../../esp32/include/ \
) $(addprefix stubs/, \
newlib/include \
log/include \
freertos/include \
) \
$(addprefix ../../../components/, \
soc/esp32/include \
esp32/include \
bootloader_support/include \
app_update/include \
) \
../../../tools/catch \
)
GCOV ?= gcov GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o)) OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
$(COMPONENT_LIB): $(OBJ_FILES)
$(PARTITION_SIM_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^ $(AR) rcs $@ $^
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES:.o=.gc*) lib: $(COMPONENT_LIB)
$(COVERAGE_FILES): $(TEST_PROGRAM) lib COVERAGE_FILES = $(OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): lib
coverage.info: $(COVERAGE_FILES) coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} + find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
@ -39,9 +59,9 @@ coverage_report: coverage.info
@echo "Coverage report is in coverage_report/index.html" @echo "Coverage report is in coverage_report/index.html"
clean: clean:
rm -f $(OBJ_FILES) $(PARTITION_SIM_LIB) rm -f $(OBJ_FILES) $(COMPONENT_LIB)
rm -f $(COVERAGE_FILES) *.gcov rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/ rm -rf coverage_report/
rm -f coverage.info rm -f coverage.info
.PHONY: clean lib .PHONY: clean lib all

View File

@ -0,0 +1,126 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "SpiFlash.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
#include "esp_flash_data_types.h"
using namespace std;
SpiFlash::SpiFlash()
{
return;
}
SpiFlash::~SpiFlash()
{
deinit();
}
void SpiFlash::init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin)
{
// De-initialize first
deinit();
this->chip_size = chip_size;
this->block_size = block_size;
this->sector_size = sector_size;
this->page_size = page_size;
this->memory = (uint8_t *) malloc(this->chip_size);
memset(this->memory, 0xFF, this->chip_size);
ifstream ifd(partitions_bin, ios::binary | ios::ate);
int size = ifd.tellg();
ifd.seekg(0, ios::beg);
vector<char> buffer;
buffer.resize(size);
ifd.read(buffer.data(), size);
memcpy(&this->memory[ESP_PARTITION_TABLE_ADDR], buffer.data(), buffer.size());
}
void SpiFlash::deinit()
{
if(inited)
{
free(this->memory);
}
}
size_t SpiFlash::get_chip_size()
{
return this->chip_size;
}
size_t SpiFlash::get_sector_size()
{
return this->sector_size;
}
esp_rom_spiflash_result_t SpiFlash::erase_block(uint32_t block)
{
memset(&this->memory[block * this->block_size], 0xFF, this->block_size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::erase_sector(size_t sector)
{
memset(&this->memory[sector * this->sector_size], 0xFF, this->sector_size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::erase_page(uint32_t page)
{
memset(&this->memory[page * this->page_size], 0xFF, this->page_size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::write(size_t dest_addr, const void *src, size_t size)
{
// Emulate inability to set programmed bits without erasing
for(uint32_t ctr = 0; ctr < size; ctr++)
{
uint8_t data = ((uint8_t*)src)[ctr];
uint8_t written = this->memory[dest_addr + ctr];
data &= written;
this->memory[dest_addr + ctr] = data;
}
return ESP_ROM_SPIFLASH_RESULT_OK;
}
esp_rom_spiflash_result_t SpiFlash::read(size_t src_addr, void *dest, size_t size)
{
memcpy(dest, &this->memory[src_addr], size);
return ESP_ROM_SPIFLASH_RESULT_OK;
}
uint8_t* SpiFlash::get_memory_ptr(uint32_t src_address)
{
return &this->memory[src_address];
}

View File

@ -0,0 +1,62 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _SpiFlash_H_
#define _SpiFlash_H_
#include "esp_err.h"
#include "rom/spi_flash.h"
/**
* @brief This class is used to emulate flash devices.
*
*/
class SpiFlash
{
public:
SpiFlash();
~SpiFlash();
void init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin);
esp_rom_spiflash_result_t erase_block(uint32_t block);
esp_rom_spiflash_result_t erase_sector(uint32_t sector);
esp_rom_spiflash_result_t erase_page(uint32_t page);
esp_rom_spiflash_result_t write(size_t dest_addr, const void *src, size_t size);
esp_rom_spiflash_result_t read(size_t src_addr, void *dest, size_t size);
size_t get_chip_size();
size_t get_sector_size();
uint8_t* get_memory_ptr(uint32_t src_address);
private:
bool inited = false;
size_t chip_size;
size_t block_size;
size_t sector_size;
size_t page_size;
uint8_t* memory;
void* partitions;
uint8_t partitions_num;
void deinit();
};
#endif // _SpiFlash_H_

View File

@ -0,0 +1,65 @@
#include "SpiFlash.h"
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "esp_err.h"
#include "rom/spi_flash.h"
static SpiFlash spiflash = SpiFlash();
esp_rom_spiflash_chip_t g_rom_flashchip;
extern "C" void _spi_flash_init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partitions_bin)
{
spiflash.init(chip_size, block_size, sector_size, page_size, partitions_bin);
g_rom_flashchip.chip_size = chip_size;
g_rom_flashchip.block_size = block_size;
g_rom_flashchip.sector_size = sector_size;
g_rom_flashchip.page_size = page_size;
}
esp_err_t spi_flash_mmap(size_t src_addr, size_t size, spi_flash_mmap_memory_t memory,
const void** out_ptr, spi_flash_mmap_handle_t* out_handle)
{
*out_handle = 0;
*out_ptr = (void*)spiflash.get_memory_ptr(src_addr);
return ESP_OK;
}
void spi_flash_munmap(spi_flash_mmap_handle_t handle)
{
return;
}
esp_rom_spiflash_result_t esp_rom_spiflash_read(uint32_t target, uint32_t *dest, int32_t len)
{
return spiflash.read(target, dest, len);
}
esp_rom_spiflash_result_t esp_rom_spiflash_erase_block(uint32_t block)
{
return spiflash.erase_block(block);
}
esp_rom_spiflash_result_t esp_rom_spiflash_erase_sector(uint32_t sector)
{
return spiflash.erase_sector(sector);
}
esp_rom_spiflash_result_t esp_rom_spiflash_erase_page(uint32_t page)
{
return spiflash.erase_page(page);
}
esp_rom_spiflash_result_t esp_rom_spiflash_write(uint32_t target, const uint32_t *src, int32_t len)
{
return spiflash.write(target, src, len);
}
esp_rom_spiflash_result_t esp_rom_spiflash_write_encrypted(uint32_t flash_addr, uint32_t *data, uint32_t len)
{
return spiflash.write(flash_addr, data, len);
}

View File

@ -0,0 +1,57 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "esp_err.h"
#include "rom/spi_flash.h"
extern void _spi_flash_init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
void spi_flash_init(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
_spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}
void spi_flash_mark_modified_region(size_t start_addr, size_t length)
{
return;
}
esp_rom_spiflash_result_t esp_rom_spiflash_unlock()
{
return ESP_ROM_SPIFLASH_RESULT_OK;
}
void spi_flash_init_lock()
{
return;
}
void spi_flash_op_lock()
{
return;
}
void spi_flash_op_unlock()
{
return;
}
void spi_flash_disable_interrupts_caches_and_other_cpu()
{
return;
}
void spi_flash_enable_interrupts_caches_and_other_cpu()
{
return;
}
void spi_flash_disable_interrupts_caches_and_other_cpu_no_os()
{
return;
}
void spi_flash_enable_interrupts_caches_no_os()
{
return;
}

View File

@ -1,96 +0,0 @@
#pragma once
#include <stdbool.h>
#include "sdkconfig.h"
#include "esp_err.h"
#include "esp_spi_flash.h"
#if defined(__cplusplus)
extern "C" { // Make sure we have C-declarations in C++ programs
#endif
/**
* @brief Partition type
* @note Keep this enum in sync with PartitionDefinition class gen_esp32part.py
*/
typedef enum {
ESP_PARTITION_TYPE_APP = 0x00, //!< Application partition type
ESP_PARTITION_TYPE_DATA = 0x01, //!< Data partition type
} esp_partition_type_t;
/**
* @brief Partition subtype
* @note Keep this enum in sync with PartitionDefinition class gen_esp32part.py
*/
typedef enum {
ESP_PARTITION_SUBTYPE_APP_FACTORY = 0x00, //!< Factory application partition
ESP_PARTITION_SUBTYPE_APP_OTA_MIN = 0x10, //!< Base for OTA partition subtypes
ESP_PARTITION_SUBTYPE_APP_OTA_0 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 0, //!< OTA partition 0
ESP_PARTITION_SUBTYPE_APP_OTA_1 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 1, //!< OTA partition 1
ESP_PARTITION_SUBTYPE_APP_OTA_2 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 2, //!< OTA partition 2
ESP_PARTITION_SUBTYPE_APP_OTA_3 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 3, //!< OTA partition 3
ESP_PARTITION_SUBTYPE_APP_OTA_4 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 4, //!< OTA partition 4
ESP_PARTITION_SUBTYPE_APP_OTA_5 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 5, //!< OTA partition 5
ESP_PARTITION_SUBTYPE_APP_OTA_6 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 6, //!< OTA partition 6
ESP_PARTITION_SUBTYPE_APP_OTA_7 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 7, //!< OTA partition 7
ESP_PARTITION_SUBTYPE_APP_OTA_8 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 8, //!< OTA partition 8
ESP_PARTITION_SUBTYPE_APP_OTA_9 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 9, //!< OTA partition 9
ESP_PARTITION_SUBTYPE_APP_OTA_10 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 10,//!< OTA partition 10
ESP_PARTITION_SUBTYPE_APP_OTA_11 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 11,//!< OTA partition 11
ESP_PARTITION_SUBTYPE_APP_OTA_12 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 12,//!< OTA partition 12
ESP_PARTITION_SUBTYPE_APP_OTA_13 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 13,//!< OTA partition 13
ESP_PARTITION_SUBTYPE_APP_OTA_14 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 14,//!< OTA partition 14
ESP_PARTITION_SUBTYPE_APP_OTA_15 = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 15,//!< OTA partition 15
ESP_PARTITION_SUBTYPE_APP_OTA_MAX = ESP_PARTITION_SUBTYPE_APP_OTA_MIN + 16,//!< Max subtype of OTA partition
ESP_PARTITION_SUBTYPE_APP_TEST = 0x20, //!< Test application partition
ESP_PARTITION_SUBTYPE_DATA_OTA = 0x00, //!< OTA selection partition
ESP_PARTITION_SUBTYPE_DATA_PHY = 0x01, //!< PHY init data partition
ESP_PARTITION_SUBTYPE_DATA_NVS = 0x02, //!< NVS partition
ESP_PARTITION_SUBTYPE_DATA_COREDUMP = 0x03, //!< COREDUMP partition
ESP_PARTITION_SUBTYPE_DATA_ESPHTTPD = 0x80, //!< ESPHTTPD partition
ESP_PARTITION_SUBTYPE_DATA_FAT = 0x81, //!< FAT partition
ESP_PARTITION_SUBTYPE_DATA_SPIFFS = 0x82, //!< SPIFFS partition
ESP_PARTITION_SUBTYPE_ANY = 0xff, //!< Used to search for partitions with any subtype
} esp_partition_subtype_t;
/**
* @brief partition information structure
*
* This is not the format in flash, that format is esp_partition_info_t.
*
* However, this is the format used by this API.
*/
typedef struct {
esp_partition_type_t type; /*!< partition type (app/data) */
esp_partition_subtype_t subtype; /*!< partition subtype */
uint32_t address; /*!< starting address of the partition in flash */
uint32_t size; /*!< size of the partition, in bytes */
char label[17]; /*!< partition label, zero-terminated ASCII string */
bool encrypted; /*!< flag is set to true if partition is encrypted */
int handle; /*!< simulator handle */
} esp_partition_t;
esp_err_t esp_partition_write(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size);
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
uint32_t start_addr, uint32_t size);
esp_err_t esp_partition_read(const esp_partition_t* partition,
size_t src_offset, void* dst, size_t size);
esp_partition_t esp_partition_create(uint32_t size, uint32_t start, int handle);
int esp_flash_create(uint32_t size, uint32_t sector_size, uint32_t write_size);
void esp_flash_delete(int handle);
#if defined(__cplusplus)
}
#endif

View File

@ -1,7 +0,0 @@
#pragma once
#define CONFIG_WL_SECTOR_SIZE 4096
#define SPI_FLASH_SEC_SIZE CONFIG_WL_SECTOR_SIZE
#define SPI_FLASH_WRITE_SIZE 16

View File

@ -1,68 +0,0 @@
#include <assert.h>
#include "esp_partition.h"
#include "esp_spi_flash.h"
#include "Flash_Emulator.h"
#define EMULATORS_MAX 8
static Flash_Emulator* emulators[EMULATORS_MAX];
int esp_flash_create(uint32_t size, uint32_t sector_size, uint32_t write_size)
{
int handle = -1;
for (int i = 0; i < EMULATORS_MAX; i++) {
if (emulators[i] == NULL) {
emulators[i] = new Flash_Emulator(size, sector_size, write_size);
handle = i;
break;
}
}
assert(handle != -1);
return handle;
}
esp_partition_t esp_partition_create(uint32_t size, uint32_t start, int flash)
{
esp_partition_t partition;
// Fills partition with default values, and attaches the flash_emulator reference
// to the struct
partition.type = ESP_PARTITION_TYPE_DATA;
partition.subtype = ESP_PARTITION_SUBTYPE_ANY;
partition.address = start;
partition.size = size;
partition.handle = flash;
return partition;
}
void esp_flash_delete(int handle)
{
delete emulators[handle];
emulators[handle] = NULL;
}
esp_err_t esp_partition_write(const esp_partition_t* partition,
size_t dst_offset, const void* src, size_t size)
{
emulators[partition->handle]->write(dst_offset, src, size);
return ESP_OK;
}
esp_err_t esp_partition_erase_range(const esp_partition_t* partition,
uint32_t start_addr, uint32_t size)
{
emulators[partition->handle]->erase_range(start_addr, size);
return ESP_OK;
}
esp_err_t esp_partition_read(const esp_partition_t* partition,
size_t src_offset, void* dst, size_t size)
{
emulators[partition->handle]->read(src_offset, dst, size);
return ESP_OK;
}

View File

@ -1 +1,2 @@
#pragma once #pragma once

View File

@ -0,0 +1,13 @@
#include "esp_ota_ops.h"
#include "esp_partition.h"
const esp_partition_t* esp_ota_get_running_partition(void)
{
// Return first instance of an app partition
const esp_partition_t* partition = esp_partition_find_first(ESP_PARTITION_TYPE_APP,
ESP_PARTITION_SUBTYPE_ANY,
NULL);
assert(partition != NULL);
return partition;
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "projdefs.h"
#include "semphr.h"
// Avoid redefinition compile error. Put here since this is included
// in flash_ops.c.
#define spi_flash_init() overriden_spi_flash_init()

View File

@ -0,0 +1,11 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define pdTRUE 1
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1,16 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
#define vSemaphoreDelete( xSemaphore )
#define xSemaphoreCreateMutex() ((void*)(1))
#define xSemaphoreGive( xSemaphore )
#define xSemaphoreTake( xSemaphore, xBlockTime ) pdTRUE
typedef void* SemaphoreHandle_t;
#if defined(__cplusplus)
}
#endif

View File

@ -0,0 +1 @@
#pragma once

View File

@ -0,0 +1,48 @@
#pragma once
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
typedef enum {
ESP_LOG_NONE, /*!< No log output */
ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */
ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */
ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */
ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */
ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */
} esp_log_level_t;
#define LOG_COLOR_E
#define LOG_COLOR_W
#define LOG_COLOR_I
#define LOG_COLOR_D
#define LOG_COLOR_V
#define LOG_RESET_COLOR
uint32_t esp_log_timestamp(void);
void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4)));
#define LOG_FORMAT(letter, format) LOG_COLOR_ ## letter #letter " (%d) %s: " format LOG_RESET_COLOR "\n"
#define ESP_LOGE( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_ERROR) { esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGV( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_VERBOSE) { esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGD( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_DEBUG) { esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
#define ESP_LOGW( tag, format, ... ) if (LOG_LOCAL_LEVEL >= ESP_LOG_WARN) { esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
// Assume that flash encryption is not enabled. Put here since in partition.c
// esp_log.h is included later than esp_flash_encrypt.h.
#define esp_flash_encryption_enabled() false
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,22 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include "esp_log.h"
void esp_log_write(esp_log_level_t level,
const char *tag,
const char *format, ...)
{
va_list arg;
va_start(arg, format);
vprintf(format, arg);
va_end(arg);
}
uint32_t esp_log_timestamp()
{
return 0;
}

View File

@ -0,0 +1,17 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef int _lock_t;
void _lock_acquire(_lock_t *lock);
void _lock_close(_lock_t *lock);
void _lock_init(_lock_t *lock);
void _lock_release(_lock_t *lock);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,21 @@
#include "sys/lock.h"
void _lock_acquire(_lock_t *lock)
{
return;
}
void _lock_close(_lock_t *lock)
{
return;
}
void _lock_init(_lock_t *lock)
{
return;
}
void _lock_release(_lock_t *lock)
{
return;
}

View File

@ -1,13 +1,18 @@
TEST_PROGRAM=test_spiffs COMPONENT=spiffs
TEST_PARTITION_SIM_DIR=$(IDF_PATH)/components/spi_flash/sim TEST_PROGRAM=test_$(COMPONENT)
TEST_PARTITION_SIM_LIB=libpartition_sim.a
#Expose as a library
COMPONENT_LIB=lib$(COMPONENT).a
SPI_FLASH=spi_flash
SPI_FLASH_DIR=../../$(SPI_FLASH)
SPI_FLASH_SIM_DIR=$(SPI_FLASH_DIR)/sim
SPI_FLASH_LIB=lib$(SPI_FLASH).a
all: $(TEST_PROGRAM) all: $(TEST_PROGRAM)
SOURCE_FILES = \ SOURCE_FILES = \
main.cpp \
test_spiffs.cpp \
../spiffs_api.c \ ../spiffs_api.c \
$(addprefix ../spiffs/src/, \ $(addprefix ../spiffs/src/, \
spiffs_cache.c \ spiffs_cache.c \
@ -20,46 +25,59 @@ SOURCE_FILES = \
log/log.c \ log/log.c \
) )
TEST_SOURCE_FILES = \
test_spiffs.cpp \
main.cpp \
test_utils.c
INCLUDE_FLAGS = $(addprefix -I,\ INCLUDE_FLAGS = $(addprefix -I,\
. \ . \
.. \ .. \
../spiffs/src \ ../spiffs/src \
../include \ ../include \
$(addprefix ./stubs/, \ $(addprefix ./stubs/, \
esp32/include \
log/include \ log/include \
freertos/include \ freertos/include \
newlib/include \ newlib/include \
vfs/include \ vfs/include \
) \ ) \
../../esp32/include \ ../../esp32/include \
$(TEST_PARTITION_SIM_DIR)/include \ $(SPI_FLASH_DIR)/include \
../../../tools/catch \ ../../../tools/catch \
) )
GCOV ?= gcov GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o)) OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o))
$(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB): force $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB): force
$(MAKE) -C $(TEST_PARTITION_SIM_DIR) lib $(MAKE) -C $(SPI_FLASH_SIM_DIR) lib
$(TEST_PROGRAM): $(OBJ_FILES) $(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB)
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(OBJ_FILES) -L$(TEST_PARTITION_SIM_DIR) -l:$(TEST_PARTITION_SIM_LIB) -L$(TEST_WL_DIR) -l:$(TEST_WL_LIB)
force: force:
$(COMPONENT_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^
lib: $(COMPONENT_LIB)
partitions_table.bin: partitions_table.csv
python ../../partition_table/gen_esp32part.py --verify $< $@
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB) partitions_table.bin
g++ $(LDFLAGS) -o $(TEST_PROGRAM) $(TEST_OBJ_FILES) -L$(abspath .) -l:$(COMPONENT_LIB) -L$(SPI_FLASH_SIM_DIR) -l:$(SPI_FLASH_LIB) -g -m32
test: $(TEST_PROGRAM) test: $(TEST_PROGRAM)
./$(TEST_PROGRAM) ./$(TEST_PROGRAM)
COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(OBJ_FILES:.o=.gc*) COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): $(TEST_PROGRAM) lib $(COVERAGE_FILES): test
coverage.info: $(COVERAGE_FILES) coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} + find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
@ -70,10 +88,10 @@ coverage_report: coverage.info
@echo "Coverage report is in coverage_report/index.html" @echo "Coverage report is in coverage_report/index.html"
clean: clean:
rm -f $(OBJ_FILES) $(TEST_PROGRAM) $(TEST_WL_LIB) rm -f $(OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(COMPONENT_LIB) partitions_table.bin
$(MAKE) -C $(TEST_PARTITION_SIM_DIR) clean $(MAKE) -C $(SPI_FLASH_SIM_DIR) clean
rm -f $(COVERAGE_FILES) *.gcov rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/ rm -rf coverage_report/
rm -f coverage.info rm -f coverage.info
.PHONY: clean all test .PHONY: clean all test lib

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, spiffs, , 2M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, spiffs, , 2M,

View File

@ -11,4 +11,4 @@
#define CONFIG_SPIFFS_USE_MAGIC 1 #define CONFIG_SPIFFS_USE_MAGIC 1
#define CONFIG_SPIFFS_PAGE_CHECK 1 #define CONFIG_SPIFFS_PAGE_CHECK 1
#define CONFIG_SPIFFS_USE_MTIME 1 #define CONFIG_SPIFFS_USE_MTIME 1
#define CONFIG_WL_SECTOR_SIZE 4096 #define CONFIG_WL_SECTOR_SIZE 4096

View File

@ -1,23 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct {
uint32_t device_id;
uint32_t chip_size; // chip size in bytes
uint32_t block_size;
uint32_t sector_size;
uint32_t page_size;
uint32_t status_mask;
} esp_rom_spiflash_chip_t;
extern esp_rom_spiflash_chip_t g_rom_flashchip;
#if defined(__cplusplus)
}
#endif

View File

@ -9,19 +9,20 @@
#include "catch.hpp" #include "catch.hpp"
extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
TEST_CASE("format disk, open file, write and read file", "[spiffs]") TEST_CASE("format disk, open file, write and read file", "[spiffs]")
{ {
uint32_t size = 0x00400000; init_spi_flash(0x00400000, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partitions_table.bin");
int flash_handle = esp_flash_create(size, CONFIG_WL_SECTOR_SIZE, 1);
esp_partition_t partition = esp_partition_create(size, 0, flash_handle);
spiffs fs; spiffs fs;
spiffs_config cfg; spiffs_config cfg;
const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, "storage");
// Configure objects needed by SPIFFS // Configure objects needed by SPIFFS
esp_spiffs_t esp_user_data; esp_spiffs_t esp_user_data;
esp_user_data.partition = &partition; esp_user_data.partition = partition;
fs.user_data = (void*)&esp_user_data; fs.user_data = (void*)&esp_user_data;
cfg.hal_erase_f = spiffs_api_erase; cfg.hal_erase_f = spiffs_api_erase;
@ -31,7 +32,7 @@ TEST_CASE("format disk, open file, write and read file", "[spiffs]")
cfg.log_page_size = CONFIG_SPIFFS_PAGE_SIZE; cfg.log_page_size = CONFIG_SPIFFS_PAGE_SIZE;
cfg.phys_addr = 0; cfg.phys_addr = 0;
cfg.phys_erase_block = CONFIG_WL_SECTOR_SIZE; cfg.phys_erase_block = CONFIG_WL_SECTOR_SIZE;
cfg.phys_size = partition.size; cfg.phys_size = partition->size;
uint32_t max_files = 5; uint32_t max_files = 5;
@ -63,34 +64,44 @@ TEST_CASE("format disk, open file, write and read file", "[spiffs]")
spiffs_res = SPIFFS_open(&fs, "test.txt", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0); spiffs_res = SPIFFS_open(&fs, "test.txt", SPIFFS_O_CREAT | SPIFFS_O_RDWR, 0);
REQUIRE(spiffs_res >= SPIFFS_OK); REQUIRE(spiffs_res >= SPIFFS_OK);
// Write to the test file // Generate data
spiffs_file file = spiffs_res; spiffs_file file = spiffs_res;
const char data[] = "Hello, World!"; uint32_t data_size = 100000;
char *read = (char*) malloc(sizeof(data));
char *data = (char*) malloc(data_size);
char *read = (char*) malloc(data_size);
for(uint32_t i = 0; i < data_size; i += sizeof(i))
{
*((uint32_t*)(data + i)) = i;
}
s32_t bw; s32_t bw;
spiffs_res = SPIFFS_write(&fs, file, (void*)data, sizeof(data)); // Write data to file
spiffs_res = SPIFFS_write(&fs, file, (void*)data, data_size);
REQUIRE(spiffs_res >= SPIFFS_OK); REQUIRE(spiffs_res >= SPIFFS_OK);
REQUIRE(spiffs_res == sizeof(data)); REQUIRE(spiffs_res == data_size);
// Set the file object pointer to the beginning // Set the file object pointer to the beginning
spiffs_res = SPIFFS_lseek(&fs, file, 0, SPIFFS_SEEK_SET); spiffs_res = SPIFFS_lseek(&fs, file, 0, SPIFFS_SEEK_SET);
REQUIRE(spiffs_res >= SPIFFS_OK); REQUIRE(spiffs_res >= SPIFFS_OK);
// Set the file object pointer to the beginning // Read the file
spiffs_res = SPIFFS_read(&fs, file, (void*)read, sizeof(data)); spiffs_res = SPIFFS_read(&fs, file, (void*)read, data_size);
REQUIRE(spiffs_res >= SPIFFS_OK); REQUIRE(spiffs_res >= SPIFFS_OK);
REQUIRE(spiffs_res == sizeof(data)); REQUIRE(spiffs_res == data_size);
// Close the test file // Close the test file
spiffs_res = SPIFFS_close(&fs, file); spiffs_res = SPIFFS_close(&fs, file);
REQUIRE(spiffs_res >= SPIFFS_OK); REQUIRE(spiffs_res >= SPIFFS_OK);
REQUIRE(memcmp(data, read, data_size) == 0);
// Unmount // Unmount
SPIFFS_unmount(&fs); SPIFFS_unmount(&fs);
esp_flash_delete(flash_handle);
free(read); free(read);
} free(data);
}

View File

@ -0,0 +1,7 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}

View File

@ -10,10 +10,9 @@ The WLC Files
^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^
The WLC consist of few components that are implemented in different files. The list and brief description of these components written below. The WLC consist of few components that are implemented in different files. The list and brief description of these components written below.
- Flash_Access - memory access interface. Used to access the memory. A classes WL_Flash, Partition, SPI_Flash, Flash_Emulator are implements this interface. - Flash_Access - memory access interface. Used to access the memory. A classes WL_Flash, Partition, SPI_Flash are implements this interface.
- SPI_Flash - class implements the Flash_Access interface to provide access to the flash memory. - SPI_Flash - class implements the Flash_Access interface to provide access to the flash memory.
- Partition - class implements the Flash_Access interface to provide access to the partition. - Partition - class implements the Flash_Access interface to provide access to the partition.
- Flash_Emulator - class implements the Flash_Access interface to provide test functionality for WLC testing.
- WL_Flash - the main class that implements wear levelling functionality. - WL_Flash - the main class that implements wear levelling functionality.
- WL_State - contains state structure of the WLC. - WL_State - contains state structure of the WLC.
- WL_Config - contains structure to configure the WLC component at startup. - WL_Config - contains structure to configure the WLC component at startup.

View File

@ -1,30 +1,35 @@
TEST_PROGRAM=test_wl COMPONENT=wear_levelling
TEST_PROGRAM=test_$(COMPONENT)
# Expose as a library for FS components that require wear_levelling # Expose as a library for FS components that require wear_levelling
TEST_LIB=lib$(TEST_PROGRAM).a COMPONENT_LIB=lib$(COMPONENT).a
# Use simulated block device # Use simulated block device
TEST_PARTITION_SIM_DIR=$(IDF_PATH)/components/spi_flash/sim SPI_FLASH=spi_flash
TEST_PARTITION_SIM_LIB=libpartition_sim.a SPI_FLASH_DIR=../../$(SPI_FLASH)
SPI_FLASH_SIM_DIR=$(SPI_FLASH_DIR)/sim
SPI_FLASH_LIB=lib$(SPI_FLASH).a
all: $(TEST_PROGRAM) all: $(TEST_PROGRAM)
LIB_SOURCE_FILES = \ SOURCE_FILES = \
$(addprefix stubs/, \
newlib/lock.c \
log/log.c \
esp32/crc.cpp \
) \
$(addprefix ../, \ $(addprefix ../, \
wear_levelling.cpp \ wear_levelling.cpp \
crc32.cpp \ crc32.cpp \
WL_Flash.cpp \ WL_Flash.cpp \
Partition.cpp \ Partition.cpp \
) \ ) \
$(addprefix stubs/, \
newlib/lock.c \
log/log.c \
esp32/crc.cpp \
)
TEST_SOURCE_FILES = \ TEST_SOURCE_FILES = \
test_wl.cpp \ test_wl.cpp \
main.cpp main.cpp \
test_utils.c
INCLUDE_FLAGS = $(addprefix -I,\ INCLUDE_FLAGS = $(addprefix -I,\
. \ . \
@ -32,47 +37,49 @@ INCLUDE_FLAGS = $(addprefix -I,\
../include \ ../include \
../private_include \ ../private_include \
$(addprefix stubs/, \ $(addprefix stubs/, \
esp32/include \
newlib/include \ newlib/include \
log/include \ log/include \
) \ ) \
$(SPI_FLASH_DIR)/include \
../../esp32/include \ ../../esp32/include \
../../spi_flash/sim/include \
../../../tools/catch \ ../../../tools/catch \
) )
GCOV ?= gcov GCOV ?= gcov
CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g CPPFLAGS += $(INCLUDE_FLAGS) -D CONFIG_LOG_DEFAULT_LEVEL -g -m32
CFLAGS += -fprofile-arcs -ftest-coverage CFLAGS += -fprofile-arcs -ftest-coverage
CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage CXXFLAGS += -std=c++11 -Wall -Werror -fprofile-arcs -ftest-coverage
LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage LDFLAGS += -lstdc++ -fprofile-arcs -ftest-coverage
LIB_OBJ_FILES = $(filter %.o, $(LIB_SOURCE_FILES:.cpp=.o) $(LIB_SOURCE_FILES:.c=.o)) OBJ_FILES = $(filter %.o, $(SOURCE_FILES:.cpp=.o) $(SOURCE_FILES:.c=.o))
TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o)) TEST_OBJ_FILES = $(filter %.o, $(TEST_SOURCE_FILES:.cpp=.o) $(TEST_SOURCE_FILES:.c=.o))
$(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB): force $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB): force
$(MAKE) -C $(TEST_PARTITION_SIM_DIR) lib $(MAKE) -C $(SPI_FLASH_SIM_DIR) lib
$(TEST_LIB): $(LIB_OBJ_FILES) $(COMPONENT_LIB): $(OBJ_FILES)
$(AR) rcs $@ $^ $(AR) rcs $@ $^
lib: $(TEST_LIB)
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(TEST_PARTITION_SIM_DIR)/$(TEST_PARTITION_SIM_LIB)
g++ $(LDFLAGS) -o $@ $(TEST_OBJ_FILES) -L$(abspath .) -l:$(TEST_LIB) -L$(TEST_PARTITION_SIM_DIR) -l:$(TEST_PARTITION_SIM_LIB)
force: force:
lib: $(COMPONENT_LIB)
partition_table.bin: partition_table.csv
python ../../../components/partition_table/gen_esp32part.py --verify $< $@
$(TEST_PROGRAM): lib $(TEST_OBJ_FILES) $(SPI_FLASH_SIM_DIR)/$(SPI_FLASH_LIB) partition_table.bin
g++ $(LDFLAGS) -o $@ $(TEST_OBJ_FILES) -L$(abspath .) -l:$(COMPONENT_LIB) -L$(SPI_FLASH_SIM_DIR) -l:$(SPI_FLASH_LIB) -g -m32
test: $(TEST_PROGRAM) test: $(TEST_PROGRAM)
./$(TEST_PROGRAM) ./$(TEST_PROGRAM)
$(OUTPUT_DIR): $(OUTPUT_DIR):
mkdir -p $(OUTPUT_DIR) mkdir -p $(OUTPUT_DIR)
COVERAGE_FILES = $(LIB_OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*) COVERAGE_FILES = $(OBJ_FILES:.o=.gc*) $(TEST_OBJ_FILES:.o=.gc*)
$(COVERAGE_FILES): $(TEST_PROGRAM) test $(COVERAGE_FILES): test
coverage.info: $(COVERAGE_FILES) coverage.info: $(COVERAGE_FILES)
find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} + find ../ -name "*.gcno" -exec $(GCOV) -r -pb {} +
@ -83,8 +90,8 @@ coverage_report: coverage.info
@echo "Coverage report is in coverage_report/index.html" @echo "Coverage report is in coverage_report/index.html"
clean: clean:
$(MAKE) -C $(TEST_PARTITION_SIM_DIR) clean $(MAKE) -C $(SPI_FLASH_SIM_DIR) clean
rm -f $(LIB_OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(TEST_LIB) rm -f $(OBJ_FILES) $(TEST_OBJ_FILES) $(TEST_PROGRAM) $(COMPONENT_LIB) partition_table.bin
rm -f $(COVERAGE_FILES) *.gcov rm -f $(COVERAGE_FILES) *.gcov
rm -rf coverage_report/ rm -rf coverage_report/
rm -f coverage.info rm -f coverage.info

View File

@ -1,2 +1,2 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include "catch.hpp" #include "catch.hpp"

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, fat, , 1M,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, fat, , 1M,

View File

@ -1,2 +1,3 @@
#pragma once #pragma once
#define CONFIG_WL_SECTOR_SIZE 4096

View File

@ -1,8 +1,19 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "rom/crc.h"
static const unsigned int crc32_le_table[256] = { static const unsigned int crc32_le_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L,
0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L,
@ -20,7 +31,7 @@ static const unsigned int crc32_le_table[256] = {
0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L,
0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL,
0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L,
0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L,
0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L,
@ -39,7 +50,9 @@ static const unsigned int crc32_le_table[256] = {
0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL
}; };
extern "C" unsigned int crc32_le(uint32_t crc, const uint8_t* buf, size_t len)
extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len)
{ {
unsigned int i; unsigned int i;
crc = ~crc; crc = ~crc;
@ -47,4 +60,5 @@ extern "C" unsigned int crc32_le(uint32_t crc, const uint8_t* buf, size_t len)
crc = crc32_le_table[(crc^buf[i])&0xff]^(crc>>8); crc = crc32_le_table[(crc^buf[i])&0xff]^(crc>>8);
} }
return ~crc; return ~crc;
} }

View File

@ -1,15 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
uint32_t crc32_le(uint32_t crc, const uint8_t* buf, size_t len);
#ifdef __cplusplus
}
#endif

View File

@ -1,13 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint32_t device_id;
uint32_t chip_size; // chip size in bytes
uint32_t block_size;
uint32_t sector_size;
uint32_t page_size;
uint32_t status_mask;
} esp_rom_spiflash_chip_t;

View File

@ -18,5 +18,4 @@ void esp_log_write(esp_log_level_t level,
uint32_t esp_log_timestamp() uint32_t esp_log_timestamp()
{ {
return 0; return 0;
} }

View File

@ -13,5 +13,4 @@ void _lock_release(_lock_t *lock);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -18,4 +18,4 @@ void _lock_init(_lock_t *lock)
void _lock_release(_lock_t *lock) void _lock_release(_lock_t *lock)
{ {
return; return;
} }

View File

@ -0,0 +1,7 @@
#include "esp_spi_flash.h"
#include "esp_partition.h"
void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin)
{
spi_flash_init(chip_size, block_size, sector_size, page_size, partition_bin);
}

View File

@ -1,35 +1,27 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "esp_spi_flash.h"
#include "esp_partition.h" #include "esp_partition.h"
#include "wear_levelling.h" #include "wear_levelling.h"
#include "WL_Flash.h" #include "WL_Flash.h"
#include "catch.hpp" #include "catch.hpp"
#include "sdkconfig.h"
extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin); extern "C" void init_spi_flash(size_t chip_size, size_t block_size, size_t sector_size, size_t page_size, const char* partition_bin);
TEST_CASE("write and read back data", "[wear_levelling]") TEST_CASE("write and read back data", "[wear_levelling]")
{ {
init_spi_flash(0x00400000, CONFIG_WL_SECTOR_SIZE * 16, CONFIG_WL_SECTOR_SIZE, CONFIG_WL_SECTOR_SIZE, "partition_table.bin");
esp_err_t result; esp_err_t result;
wl_handle_t wl_handle; wl_handle_t wl_handle;
int flash_handle = esp_flash_create(PARTITION_SIZE, 4096, 16); int flash_handle;
esp_partition_t partition = esp_partition_create(PARTITION_SIZE, PARTITION_START, flash_handle); const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, "storage");
// Mount wear-levelled partition // Mount wear-levelled partition
result = wl_mount(partition, &wl_handle); result = wl_mount(partition, &wl_handle);