example: Add SPIFFS image generation from build system example

This commit is contained in:
Renz Christian Bagaporo 2019-01-31 19:54:45 +08:00
parent 4d9c3a262d
commit 09d7383180
11 changed files with 4006 additions and 0 deletions

View file

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(spiffsgen)

View file

@ -0,0 +1,15 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := spiffsgen
include $(IDF_PATH)/make/project.mk
# Create a SPIFFS image from the contents of the 'spiffs_image' directory
# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that
# the generated image should be flashed when the entire project is flashed to
# the target with 'make flash'.
$(eval $(call spiffs_create_partition_image,storage,spiffs_image,FLASH_IN_PROJECT))

View file

@ -0,0 +1,59 @@
# SPIFFS Image Generation on Build Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This example demonstrates how to use the SPIFFS image generation tool [spiffsgen.py](../../../components/spiffs/spiffsgen.py) to automatically create a SPIFFS
filesystem image from the contents of a host folder during build, with an option of
automatically flashing the created image on invocation of `idf.py flash` or `make flash`.
For more information, see description of `spiffsgen.py` on the ESP-IDF Programming Guide under API Reference > Storage > SPIFFS Filesystem.
The following gives an overview of the example:
1. There is a directory `spiffs_image` from which the SPIFFS filesystem image will be created.
2. The function `spiffs_create_partition_image` is used to specify that a SPIFFS image
should be created during build for the `storage` partition. For CMake, it is called from [the main component's CMakeLists.txt](./main/CMakeLists.txt);
for Make, from the [project Makefile](./Makefile). `FLASH_IN_PROJECT` specifies that the created image
should be flashed on invocation of `idf.py flash` or `make flash` together with app, bootloader, partition table, etc.
For both build systems, the image is created on the example's build directory with the output filename `storage.bin`.
3. Upon invocation of `idf.py flash monitor` or `make flash monitor`, application loads and
finds there is already a valid SPIFFS filesystem in the `storage` partition with files same as those in `spiffs_image` directory. The application is then
able to read those files.
## How to use example
### Build and flash
To run the example, type the following command:
```Makefile
# Make
make flash monitor
```
or
```CMake
# CMake
idf.py flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
Here is the example's console output:
```
...
I (10) example: Initializing SPIFFS
I (110) example: Partition size: total: 896321, used: 171935
I (110) example: Reading hello.txt
I (110) example: Read from hello.txt: Hello World!
I (110) example: Computing alice.txt MD5 hash
I (330) example: Computed MD5 hash of alice.txt: deeb71f585cbb3ae5f7976d5127faf2a
I (330) example: SPIFFS unmounted
```
The logic of the example is contained in a [single source file](./main/spiffsgen_example_main.c), and it should be relatively simple to match points in its execution with the log outputs above.

View file

@ -0,0 +1,34 @@
from __future__ import print_function
import os
import sys
import hashlib
try:
import IDF
except ImportError:
test_fw_path = os.getenv('TEST_FW_PATH')
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
@IDF.idf_example_test(env_tag='Example_WIFI')
def test_examples_spiffsgen(env, extra_data):
# Test with default build configurations
dut = env.get_dut('spiffsgen', 'examples/build_system/spiffsgen')
dut.start_app()
base_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'spiffs_image')
# Expect hello.txt is read successfully
with open(os.path.join(base_dir, 'hello.txt'), 'r') as hello_txt:
dut.expect('Read from hello.txt: ' + hello_txt.read())
# Expect alice.txt MD5 hash is computed accurately
with open(os.path.join(base_dir, 'sub', 'alice.txt'), 'rb') as alice_txt:
alice_md5 = hashlib.md5(alice_txt.read()).hexdigest()
dut.expect('Computed MD5 hash of alice.txt: ' + alice_md5)
if __name__ == '__main__':
test_examples_spiffsgen()

View file

@ -0,0 +1,10 @@
set(COMPONENT_SRCS "spiffsgen_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
# Create a SPIFFS image from the contents of the 'spiffs_image' directory
# that fits the partition named 'storage'. FLASH_IN_PROJECT indicates that
# the generated image should be flashed when the entire project is flashed to
# the target with 'idf.py flash'.
spiffs_create_partition_image(storage ../spiffs_image FLASH_IN_PROJECT)

View file

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,130 @@
/* SPIFFS Image Generation on Build Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "esp32/rom/md5_hash.h"
static const char *TAG = "example";
static void read_hello_txt()
{
ESP_LOGI(TAG, "Reading hello.txt");
// Open for reading hello.txt
FILE* f = fopen("/spiffs/hello.txt", "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open hello.txt");
return;
}
char buf[64];
memset(buf, 0, sizeof(buf));
fread(buf, 1, sizeof(buf), f);
fclose(f);
// Display the read contents from the file
ESP_LOGI(TAG, "Read from hello.txt: %s", buf);
}
static void compute_alice_txt_md5()
{
ESP_LOGI(TAG, "Computing alice.txt MD5 hash");
// The file alice.txt lives under a subdirectory, though SPIFFS itself is flat
FILE* f = fopen("/spiffs/sub/alice.txt", "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open alice.txt");
return;
}
// Read file and compute the digest chunk by chunk
#define MD5_MAX_LEN 16
char buf[64];
struct MD5Context ctx;
unsigned char digest[MD5_MAX_LEN];
MD5Init(&ctx);
size_t read;
do {
read = fread((void*) buf, 1, sizeof(buf), f);
MD5Update(&ctx, (unsigned const char*) buf, read);
} while(read == sizeof(buf));
MD5Final(digest, &ctx);
// Create a string of the digest
char digest_str[MD5_MAX_LEN * 2];
for (int i = 0; i < MD5_MAX_LEN; i++) {
sprintf(&digest_str[i * 2], "%02x", (unsigned int)digest[i]);
}
// For reference, MD5 should be deeb71f585cbb3ae5f7976d5127faf2a
ESP_LOGI(TAG, "Computed MD5 hash of alice.txt: %s", digest_str);
fclose(f);
}
void app_main(void)
{
ESP_LOGI(TAG, "Initializing SPIFFS");
esp_vfs_spiffs_conf_t conf = {
.base_path = "/spiffs",
.partition_label = NULL,
.max_files = 5,
.format_if_mount_failed = false
};
// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return;
}
size_t total = 0, used = 0;
ret = esp_spiffs_info(NULL, &total, &used);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
} else {
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
}
/* The following calls demonstrate reading files from the generated SPIFFS
* image. The images should contain the same files and contents as the spiffs_image directory.
*/
// Read and display the contents of a small text file (hello.txt)
read_hello_txt();
// Compute and display the MD5 hash of a large text file (alice.txt)
compute_alice_txt_md5();
// All done, unmount partition and disable SPIFFS
esp_vfs_spiffs_unregister(NULL);
ESP_LOGI(TAG, "SPIFFS unmounted");
}

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, , 0xF0000,
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, , 0xF0000,

View file

@ -0,0 +1,5 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_APP_OFFSET=0x10000

View file

@ -0,0 +1 @@
Hello World!

File diff suppressed because it is too large Load diff