Merge branch 'feature/spiffs' into experiments/spi_flash_reimplement
This commit is contained in:
		
						commit
						fb187eae08
					
				
					 62 changed files with 2653 additions and 371 deletions
				
			
		
							
								
								
									
										153
									
								
								extras/spiffs/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								extras/spiffs/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,153 @@ | |||
| # SPIFFS ESP8266 File system | ||||
| 
 | ||||
| This component adds file system support for ESP8266. File system of choice | ||||
| for ESP8266 is [SPIFFS](https://github.com/pellepl/spiffs).  | ||||
| It was specifically designed to use with SPI NOR flash on embedded systems. | ||||
| The main advantage of SPIFFS is wear leveling, which prolongs life time  | ||||
| of a flash memory. | ||||
| 
 | ||||
| ## Features | ||||
| 
 | ||||
|  * SPIFFS - embedded file system for NOR flash memory. | ||||
|  * POSIX file operations. | ||||
|  * Static files upload to ESP8266 file system within build process. | ||||
|  * SPIFFS singleton configuration. Only one instance of FS on a device. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| In order to use file system in a project the following steps should be made: | ||||
|  * Add SPIFFS component in a project Makefile `EXTRA_COMPONENTS = extras/spiffs` | ||||
|  * Specify your flash size in the Makefile `FLASH_SIZE = 32` | ||||
|  * Specify the start address of file system region on the flash memory | ||||
| `SPIFFS_BASE_ADDR = 0x200000` | ||||
|  * If you want to upload files to a file system during flash process specify | ||||
| the directory with files `$(eval $(call make_spiffs_image,files))` | ||||
| 
 | ||||
| In the end the Makefile should look like: | ||||
| 
 | ||||
| ``` | ||||
| PROGRAM=spiffs_example | ||||
| EXTRA_COMPONENTS = extras/spiffs | ||||
| FLASH_SIZE = 32 | ||||
| 
 | ||||
| SPIFFS_BASE_ADDR = 0x200000 | ||||
| SPIFFS_SIZE = 0x100000 | ||||
| 
 | ||||
| include ../../common.mk | ||||
| 
 | ||||
| $(eval $(call make_spiffs_image,files)) | ||||
| ``` | ||||
| 
 | ||||
| Note: Macro call to prepare SPIFFS image for flashing should go after | ||||
| `include common.mk` | ||||
| 
 | ||||
| ### Files upload | ||||
| 
 | ||||
| To upload files to a file system during flash process the following macro is | ||||
| used: | ||||
| 
 | ||||
| ``` | ||||
| $(eval $(call make_spiffs_image,files)) | ||||
| ``` | ||||
| 
 | ||||
| It enables the build of a helper utility **mkspiffs**. This utility creates | ||||
| an SPIFFS image with files in the specified directory. | ||||
| 
 | ||||
| The SPIFFS image is created during build stage, after `make` is run. | ||||
| The image is flashed into the device along with firmware during flash stage, | ||||
| after `make flash` is run. | ||||
| 
 | ||||
| **mkspiffs** utility uses the same SPIFFS source code and the same | ||||
| configuration as ESP8266. So the created image should always be compatible | ||||
| with SPIFFS on a device. | ||||
| 
 | ||||
| The build process will catch any changes in files directory and rebuild the | ||||
| image each time `make` is run. | ||||
| The build process will handle SPIFFS_SIZE change and rebuild **mkspiffs** | ||||
| utility and the image. | ||||
| 
 | ||||
| ## Example | ||||
| 
 | ||||
| ### Mount | ||||
| 
 | ||||
| ``` | ||||
| esp_spiffs_init();   // allocate memory buffers | ||||
| if (esp_spiffs_mount() != SPIFFS_OK) { | ||||
|     printf("Error mounting SPIFFS\n"); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Format | ||||
| 
 | ||||
| Formatting SPIFFS is a little bit awkward. Before formatting SPIFFS must be | ||||
| mounted and unmounted. | ||||
| ``` | ||||
| esp_spiffs_init(); | ||||
| if (esp_spiffs_mount() != SPIFFS_OK) { | ||||
|     printf("Error mount SPIFFS\n"); | ||||
| } | ||||
| SPIFFS_unmount(&fs);  // FS must be unmounted before formating | ||||
| if (SPIFFS_format(&fs) == SPIFFS_OK) { | ||||
|     printf("Format complete\n"); | ||||
| } else { | ||||
|     printf("Format failed\n"); | ||||
| } | ||||
| esp_spiffs_mount(); | ||||
| ``` | ||||
| 
 | ||||
| ### POSIX read | ||||
| 
 | ||||
| Nothing special here. | ||||
| 
 | ||||
| ``` | ||||
| const int buf_size = 0xFF; | ||||
| uint8_t buf[buf_size]; | ||||
| 
 | ||||
| int fd = open("test.txt", O_RDONLY); | ||||
| if (fd < 0) { | ||||
|     printf("Error opening file\n"); | ||||
| } | ||||
| 
 | ||||
| read(fd, buf, buf_size); | ||||
| printf("Data: %s\n", buf); | ||||
| 
 | ||||
| close(fd); | ||||
| ``` | ||||
| 
 | ||||
| ### SPIFFS read | ||||
| 
 | ||||
| SPIFFS interface is intended to be as close to POSIX as possible. | ||||
| 
 | ||||
| ``` | ||||
| const int buf_size = 0xFF; | ||||
| uint8_t buf[buf_size]; | ||||
| 
 | ||||
| spiffs_file fd = SPIFFS_open(&fs, "other.txt", SPIFFS_RDONLY, 0); | ||||
| if (fd < 0) { | ||||
|     printf("Error opening file\n"); | ||||
| } | ||||
| 
 | ||||
| SPIFFS_read(&fs, fd, buf, buf_size); | ||||
| printf("Data: %s\n", buf); | ||||
| 
 | ||||
| SPIFFS_close(&fs, fd); | ||||
| ``` | ||||
| 
 | ||||
| ### POSIX write | ||||
| 
 | ||||
| ``` | ||||
| uint8_t buf[] = "Example data, written by ESP8266"; | ||||
| 
 | ||||
| int fd = open("other.txt", O_WRONLY|O_CREAT, 0); | ||||
| if (fd < 0) { | ||||
|     printf("Error opening file\n"); | ||||
| } | ||||
| 
 | ||||
| write(fd, buf, sizeof(buf)); | ||||
| 
 | ||||
| close(fd); | ||||
| ``` | ||||
| 
 | ||||
| ## Resources | ||||
| 
 | ||||
| [SPIFFS](https://github.com/pellepl/spiffs) | ||||
|  | @ -14,4 +14,44 @@ spiffs_CFLAGS = $(CFLAGS) | |||
| spiffs_CFLAGS += -DSPIFFS_BASE_ADDR=$(SPIFFS_BASE_ADDR) | ||||
| spiffs_CFLAGS += -DSPIFFS_SIZE=$(SPIFFS_SIZE) | ||||
| 
 | ||||
| 
 | ||||
| # Create an SPIFFS image of specified directory and flash it with
 | ||||
| # the rest of the firmware.
 | ||||
| #
 | ||||
| # Argumens:
 | ||||
| #   $(1) - directory with files which go into spiffs image
 | ||||
| #
 | ||||
| # Example:
 | ||||
| #  $(eval $(call make_spiffs_image,files))
 | ||||
| define make_spiffs_image | ||||
| SPIFFS_IMAGE = $(addprefix $(FIRMWARE_DIR),spiffs.bin) | ||||
| MKSPIFFS_DIR = $(ROOT)/extras/spiffs/mkspiffs | ||||
| MKSPIFFS = $$(MKSPIFFS_DIR)/mkspiffs | ||||
| SPIFFS_FILE_LIST = $(shell find $(1)) | ||||
| 
 | ||||
| all: $$(SPIFFS_IMAGE) | ||||
| 
 | ||||
| clean: clean_spiffs_img clean_mkspiffs | ||||
| 
 | ||||
| $$(SPIFFS_IMAGE): $$(MKSPIFFS) $$(SPIFFS_FILE_LIST) | ||||
| 	$$< $(1) $$@ | ||||
| 
 | ||||
| # Rebuild SPIFFS if Makefile is changed, where SPIFF_SIZE is defined
 | ||||
| $$(spiffs_ROOT)spiffs_config.h: Makefile | ||||
| 	$$(Q) touch $$@ | ||||
| 
 | ||||
| # if SPIFFS_SIZE in Makefile is changed rebuild mkspiffs
 | ||||
| $$(MKSPIFFS): Makefile | ||||
| 	$$(MAKE) -C $$(MKSPIFFS_DIR) clean | ||||
| 	$$(MAKE) -C $$(MKSPIFFS_DIR) SPIFFS_SIZE=$(SPIFFS_SIZE) | ||||
| 
 | ||||
| clean_spiffs_img: | ||||
| 	$$(Q) rm -f $$(SPIFFS_IMAGE) | ||||
| 
 | ||||
| clean_mkspiffs: | ||||
| 	$$(Q) $$(MAKE) -C $$(MKSPIFFS_DIR) clean | ||||
| 
 | ||||
| SPIFFS_ESPTOOL_ARGS = $(SPIFFS_BASE_ADDR) $$(SPIFFS_IMAGE) | ||||
| endef | ||||
| 
 | ||||
| $(eval $(call component_compile_rules,spiffs)) | ||||
|  |  | |||
|  | @ -12,12 +12,26 @@ | |||
| #include "common_macros.h" | ||||
| #include "FreeRTOS.h" | ||||
| #include "esp/rom.h" | ||||
| #include <esp/uart.h> | ||||
| #include <fcntl.h> | ||||
| 
 | ||||
| spiffs fs; | ||||
| 
 | ||||
| static void *work_buf = 0; | ||||
| static void *fds_buf = 0; | ||||
| static void *cache_buf = 0; | ||||
| typedef struct { | ||||
|     void *buf; | ||||
|     uint32_t size; | ||||
| } fs_buf_t; | ||||
| 
 | ||||
| static fs_buf_t work_buf = {0}; | ||||
| static fs_buf_t fds_buf = {0}; | ||||
| static fs_buf_t cache_buf = {0}; | ||||
| 
 | ||||
| /**
 | ||||
|  * Number of file descriptors opened at the same time | ||||
|  */ | ||||
| #define ESP_SPIFFS_FD_NUMBER       5 | ||||
| 
 | ||||
| #define ESP_SPIFFS_CACHE_PAGES     5 | ||||
| 
 | ||||
| 
 | ||||
| // ROM functions
 | ||||
|  | @ -286,6 +300,29 @@ static s32_t esp_spiffs_erase(u32_t addr, u32_t size) | |||
|     return SPIFFS_OK; | ||||
| } | ||||
| 
 | ||||
| void esp_spiffs_init() | ||||
| { | ||||
|     work_buf.size = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); | ||||
|     fds_buf.size = SPIFFS_buffer_bytes_for_filedescs(&fs, ESP_SPIFFS_FD_NUMBER); | ||||
|     cache_buf.size= SPIFFS_buffer_bytes_for_cache(&fs, ESP_SPIFFS_CACHE_PAGES); | ||||
| 
 | ||||
|     work_buf.buf = malloc(work_buf.size); | ||||
|     fds_buf.buf = malloc(fds_buf.size); | ||||
|     cache_buf.buf = malloc(cache_buf.size); | ||||
| } | ||||
| 
 | ||||
| void esp_spiffs_deinit() | ||||
| { | ||||
|     free(work_buf.buf); | ||||
|     work_buf.buf = 0; | ||||
| 
 | ||||
|     free(fds_buf.buf); | ||||
|     fds_buf.buf = 0; | ||||
| 
 | ||||
|     free(cache_buf.buf); | ||||
|     cache_buf.buf = 0; | ||||
| } | ||||
| 
 | ||||
| int32_t esp_spiffs_mount() | ||||
| { | ||||
|     spiffs_config config = {0}; | ||||
|  | @ -294,18 +331,13 @@ int32_t esp_spiffs_mount() | |||
|     config.hal_write_f = esp_spiffs_write; | ||||
|     config.hal_erase_f = esp_spiffs_erase; | ||||
| 
 | ||||
|     size_t workBufSize = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); | ||||
|     size_t fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&fs, 5); | ||||
|     size_t cacheBufSize = SPIFFS_buffer_bytes_for_cache(&fs, 5); | ||||
|     printf("SPIFFS size: %d\n", SPIFFS_SIZE); | ||||
|     printf("SPIFFS memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", | ||||
|             work_buf.size, fds_buf.size, cache_buf.size); | ||||
| 
 | ||||
|     work_buf = malloc(workBufSize); | ||||
|     fds_buf = malloc(fdsBufSize); | ||||
|     cache_buf = malloc(cacheBufSize); | ||||
|     printf("spiffs memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", | ||||
|             workBufSize, fdsBufSize, cacheBufSize); | ||||
| 
 | ||||
|     int32_t err = SPIFFS_mount(&fs, &config, work_buf, fds_buf, fdsBufSize, | ||||
|             cache_buf, cacheBufSize, 0); | ||||
|     int32_t err = SPIFFS_mount(&fs, &config, (uint8_t*)work_buf.buf,  | ||||
|             (uint8_t*)fds_buf.buf, fds_buf.size,  | ||||
|             cache_buf.buf, cache_buf.size, 0); | ||||
| 
 | ||||
|     if (err != SPIFFS_OK) { | ||||
|         printf("Error spiffs mount: %d\n", err); | ||||
|  | @ -314,15 +346,95 @@ int32_t esp_spiffs_mount() | |||
|     return err; | ||||
| } | ||||
| 
 | ||||
| void esp_spiffs_unmount() | ||||
| #define FD_OFFSET 3 | ||||
| 
 | ||||
| // This implementation replaces implementation in core/newlib_syscals.c
 | ||||
| long _write_r(struct _reent *r, int fd, const char *ptr, int len ) | ||||
| { | ||||
|     SPIFFS_unmount(&fs); | ||||
| 
 | ||||
|     free(work_buf); | ||||
|     free(fds_buf); | ||||
|     free(cache_buf); | ||||
| 
 | ||||
|     work_buf = 0; | ||||
|     fds_buf = 0; | ||||
|     cache_buf = 0; | ||||
|     if(fd != r->_stdout->_file) { | ||||
|         long ret = SPIFFS_write(&fs, (spiffs_file)(fd - FD_OFFSET),  | ||||
|                 (char*)ptr, len); | ||||
|         return ret; | ||||
|     } | ||||
|     for(int i = 0; i < len; i++) { | ||||
|         /* Auto convert CR to CRLF, ignore other LFs (compatible with Espressif SDK behaviour) */ | ||||
|         if(ptr[i] == '\r') | ||||
|             continue; | ||||
|         if(ptr[i] == '\n') | ||||
|             uart_putc(0, '\r'); | ||||
|         uart_putc(0, ptr[i]); | ||||
|     } | ||||
|     return len; | ||||
| } | ||||
| 
 | ||||
| // This implementation replaces implementation in core/newlib_syscals.c
 | ||||
| long _read_r( struct _reent *r, int fd, char *ptr, int len ) | ||||
| { | ||||
|     int ch, i; | ||||
| 
 | ||||
|     if(fd != r->_stdin->_file) { | ||||
|         long ret = SPIFFS_read(&fs, (spiffs_file)(fd - FD_OFFSET), ptr, len); | ||||
|         return ret; | ||||
|     } | ||||
|     uart_rxfifo_wait(0, 1); | ||||
|     for(i = 0; i < len; i++) { | ||||
|         ch = uart_getc_nowait(0); | ||||
|         if (ch < 0) break; | ||||
|         ptr[i] = ch; | ||||
|     } | ||||
|     return i; | ||||
| } | ||||
| 
 | ||||
| int _open_r(struct _reent *r, const char *pathname, int flags, int mode) | ||||
| { | ||||
|     uint32_t spiffs_flags = SPIFFS_RDONLY; | ||||
| 
 | ||||
|     if (flags & O_CREAT)    spiffs_flags |= SPIFFS_CREAT; | ||||
|     if (flags & O_APPEND)   spiffs_flags |= SPIFFS_APPEND; | ||||
|     if (flags & O_TRUNC)    spiffs_flags |= SPIFFS_TRUNC; | ||||
|     if (flags & O_RDONLY)   spiffs_flags |= SPIFFS_RDONLY; | ||||
|     if (flags & O_WRONLY)   spiffs_flags |= SPIFFS_WRONLY; | ||||
| 
 | ||||
|     int ret = SPIFFS_open(&fs, pathname, spiffs_flags, mode); | ||||
|     if (ret > 0) { | ||||
|         return ret + FD_OFFSET; | ||||
|     } | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| int _close_r(struct _reent *r, int fd) | ||||
| { | ||||
|     return SPIFFS_close(&fs, (spiffs_file)(fd - FD_OFFSET)); | ||||
| } | ||||
| 
 | ||||
| int _unlink_r(struct _reent *r, const char *path) | ||||
| { | ||||
|     return SPIFFS_remove(&fs, path); | ||||
| } | ||||
| 
 | ||||
| int _fstat_r(struct _reent *r, int fd, void *buf) | ||||
| { | ||||
|     spiffs_stat s; | ||||
|     struct stat *sb = (struct stat*)buf; | ||||
| 
 | ||||
|     int result = SPIFFS_fstat(&fs, (spiffs_file)(fd - FD_OFFSET), &s); | ||||
|     sb->st_size = s.size; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| int _stat_r(struct _reent *r, const char *pathname, void *buf) | ||||
| { | ||||
|     spiffs_stat s; | ||||
|     struct stat *sb = (struct stat*)buf; | ||||
| 
 | ||||
|     int result = SPIFFS_stat(&fs, pathname, &s); | ||||
|     sb->st_size = s.size; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| off_t _lseek_r(struct _reent *r, int fd, off_t offset, int whence) | ||||
| {    | ||||
|     return SPIFFS_lseek(&fs, (spiffs_file)(fd - FD_OFFSET), offset, whence); | ||||
| } | ||||
|  |  | |||
|  | @ -13,16 +13,27 @@ | |||
| extern spiffs fs; | ||||
| 
 | ||||
| /**
 | ||||
|  * Provide SPIFFS with all necessary configuration, allocate memory buffers | ||||
|  * and mount SPIFFS. | ||||
|  * Prepare for SPIFFS mount. | ||||
|  *  | ||||
|  * The function allocates all the necessary buffers. | ||||
|  */ | ||||
| void esp_spiffs_init(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Free all memory buffers that were used by SPIFFS. | ||||
|  * | ||||
|  * The function should be called after SPIFFS unmount if the file system is not | ||||
|  * going to need any more. | ||||
|  */ | ||||
| void esp_spiffs_deinit(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Mount SPIFFS. | ||||
|  * | ||||
|  * esp_spiffs_init must be called first. | ||||
|  * | ||||
|  * Return SPIFFS return code. | ||||
|  */ | ||||
| int32_t esp_spiffs_mount(); | ||||
| 
 | ||||
| /**
 | ||||
|  * Unmount SPIFFS and free all allocated buffers. | ||||
|  */ | ||||
| void esp_spiffs_unmount(); | ||||
| 
 | ||||
| #endif  // __ESP_SPIFFS_H__
 | ||||
|  |  | |||
							
								
								
									
										37
									
								
								extras/spiffs/mkspiffs/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								extras/spiffs/mkspiffs/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| # Check if SPIFFS_SIZE defined only if not cleaning
 | ||||
| ifneq ($(MAKECMDGOALS),clean) | ||||
| ifndef SPIFFS_SIZE | ||||
| define ERROR_MSG | ||||
| Variable SPIFFS_SIZE is not defined. | ||||
| Cannot build mkspiffs without SPIFFS_SIZE. | ||||
| Please specify it in your application Makefile. | ||||
| 
 | ||||
| endef | ||||
| $(error $(ERROR_MSG))	 | ||||
| endif | ||||
| endif | ||||
| 
 | ||||
| SOURCES := spiffs_hydrogen.c | ||||
| SOURCES += spiffs_cache.c | ||||
| SOURCES += spiffs_gc.c | ||||
| SOURCES += spiffs_check.c | ||||
| SOURCES += spiffs_nucleus.c | ||||
| SOURCES += mkspiffs.c | ||||
| 
 | ||||
| OBJECTS := $(SOURCES:.c=.o) | ||||
| 
 | ||||
| VPATH = ../spiffs/src | ||||
| 
 | ||||
| CFLAGS += -I.. | ||||
| CFLAGS += -DSPIFFS_BASE_ADDR=0   # for image base addr is start of the image | ||||
| CFLAGS += -DSPIFFS_SIZE=$(SPIFFS_SIZE) | ||||
| 
 | ||||
| all: mkspiffs | ||||
| 
 | ||||
| mkspiffs: $(OBJECTS) | ||||
| 
 | ||||
| clean: | ||||
| 	@rm -f mkspiffs | ||||
| 	@rm -f *.o | ||||
| 
 | ||||
| .PHONY: all clean | ||||
							
								
								
									
										34
									
								
								extras/spiffs/mkspiffs/README.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								extras/spiffs/mkspiffs/README.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| # mkspiffs Create spiffs image | ||||
| 
 | ||||
| mkspiffs is a command line utility to create an image of SPIFFS in order | ||||
| to write to flash. | ||||
| 
 | ||||
| ## Usage | ||||
| 
 | ||||
| mkspiffs will be built automatically if you include the following line in your | ||||
| makefile: | ||||
| 
 | ||||
| ``` | ||||
| $(eval $(call make_spiffs_image,files)) | ||||
| ``` | ||||
| 
 | ||||
| where *files* is the directory with files that should go into SPIFFS image. | ||||
| 
 | ||||
| Or you can build mkspiffs manually with: | ||||
| 
 | ||||
| ``` | ||||
| make SPIFFS_SIZE=0x100000 | ||||
| ``` | ||||
| 
 | ||||
| mkspiffs cannot be built without specifying SPIFFS size because it uses the | ||||
| same SPIFFS sources as the firmware. And for the firmware SPIFFS size is | ||||
| compile time defined. | ||||
| 
 | ||||
| Please note that if you change SPIFFS_SIZE you need to rebuild mkspiffs. | ||||
| The easiest way is to run `make clean` for you project. | ||||
| 
 | ||||
| To manually generate SPIFFS image from directory, run: | ||||
| 
 | ||||
| ``` | ||||
| mkspiffs DIRECTORY IMAGE_NAME | ||||
| ``` | ||||
							
								
								
									
										243
									
								
								extras/spiffs/mkspiffs/mkspiffs.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								extras/spiffs/mkspiffs/mkspiffs.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,243 @@ | |||
| /**
 | ||||
|  * The MIT License (MIT) | ||||
|  * | ||||
|  * Copyright (c) 2016 sheinz (https://github.com/sheinz)
 | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
| #include <fcntl.h> | ||||
| #include <unistd.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/dir.h> | ||||
| #include <sys/dirent.h> | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "spiffs_config.h" | ||||
| #include "../spiffs/src/spiffs.h" | ||||
| 
 | ||||
| static spiffs fs; | ||||
| static void *image = 0; | ||||
| static void *work_buf = 0; | ||||
| static void *fds_buf = 0; | ||||
| static void *cache_buf = 0; | ||||
| 
 | ||||
| static void print_usage(const char *prog_name, const char *error_msg) | ||||
| { | ||||
|     if (error_msg) { | ||||
|         printf("Error: %s\n", error_msg); | ||||
|     } | ||||
|     printf("Usage: "); | ||||
|     printf("\t%s DIRECTORY IMAGE_NAME\n\n", prog_name); | ||||
|     printf("Example:\n"); | ||||
|     printf("\t%s ./my_files spiffs.img\n\n", prog_name); | ||||
| } | ||||
| 
 | ||||
| static s32_t _read_data(u32_t addr, u32_t size, u8_t *dst) | ||||
| { | ||||
|     memcpy(dst, (uint8_t*)image + addr, size); | ||||
|     return SPIFFS_OK; | ||||
| } | ||||
| 
 | ||||
| static s32_t _write_data(u32_t addr, u32_t size, u8_t *src) | ||||
| { | ||||
|     memcpy((uint8_t*)image + addr, src, size); | ||||
|     return  SPIFFS_OK; | ||||
| } | ||||
| 
 | ||||
| static s32_t _erase_data(u32_t addr, u32_t size) | ||||
| { | ||||
|     memset((uint8_t*)image + addr, 0xFF, size); | ||||
|     return SPIFFS_OK; | ||||
| } | ||||
| 
 | ||||
| static bool init_spiffs(bool allocate_mem) | ||||
| { | ||||
|     spiffs_config config = {0}; | ||||
|     printf("Initializing SPIFFS, size=%d\n", SPIFFS_SIZE); | ||||
| 
 | ||||
|     config.hal_read_f = _read_data; | ||||
|     config.hal_write_f = _write_data; | ||||
|     config.hal_erase_f = _erase_data; | ||||
| 
 | ||||
|     int workBufSize = 2 * SPIFFS_CFG_LOG_PAGE_SZ(); | ||||
|     int fdsBufSize = SPIFFS_buffer_bytes_for_filedescs(&fs, 5); | ||||
|     int cacheBufSize = SPIFFS_buffer_bytes_for_cache(&fs, 5); | ||||
| 
 | ||||
|     if (allocate_mem) { | ||||
|         image = malloc(SPIFFS_SIZE); | ||||
|         work_buf = malloc(workBufSize); | ||||
|         fds_buf = malloc(fdsBufSize); | ||||
|         cache_buf = malloc(cacheBufSize); | ||||
|         printf("spiffs memory, work_buf_size=%d, fds_buf_size=%d, cache_buf_size=%d\n", | ||||
|                 workBufSize, fdsBufSize, cacheBufSize); | ||||
|     } | ||||
| 
 | ||||
|     int32_t err = SPIFFS_mount(&fs, &config, work_buf, fds_buf, fdsBufSize, | ||||
|             cache_buf, cacheBufSize, 0); | ||||
| 
 | ||||
|     if (err != SPIFFS_OK) { | ||||
|         printf("Error spiffs mount: %d\n", err); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool format_spiffs() | ||||
| { | ||||
|     SPIFFS_unmount(&fs); | ||||
| 
 | ||||
|     if (SPIFFS_format(&fs) == SPIFFS_OK) { | ||||
|         printf("Format complete\n");  | ||||
|     } else { | ||||
|         printf("Failed to format SPIFFS\n"); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (!init_spiffs(false)) { | ||||
|         printf("Failed to mount SPIFFS\n"); | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static void spiffs_free() | ||||
| { | ||||
|     free(image);  | ||||
|     image = NULL; | ||||
| 
 | ||||
|     free(work_buf); | ||||
|     work_buf = NULL; | ||||
| 
 | ||||
|     free(fds_buf); | ||||
|     fds_buf = NULL; | ||||
| 
 | ||||
|     free(cache_buf); | ||||
|     cache_buf = NULL; | ||||
| } | ||||
| 
 | ||||
| static bool process_file(const char *src_file, const char *dst_file) | ||||
| { | ||||
|     int fd; | ||||
|     const int buf_size = 256; | ||||
|     uint8_t buf[buf_size]; | ||||
|     int data_len; | ||||
|      | ||||
|     fd = open(src_file, O_RDONLY); | ||||
|     if (fd < 0) { | ||||
|         printf("Error openning file: %s\n", src_file); | ||||
|     } | ||||
|      | ||||
|     spiffs_file out_fd = SPIFFS_open(&fs, dst_file,  | ||||
|             SPIFFS_O_CREAT | SPIFFS_O_WRONLY, 0); | ||||
|     while ((data_len = read(fd, buf, buf_size)) != 0) { | ||||
|         if (SPIFFS_write(&fs, out_fd, buf, data_len) != data_len) { | ||||
|             printf("Error writing to SPIFFS file\n"); | ||||
|             break; | ||||
|         }        | ||||
|     } | ||||
|     SPIFFS_close(&fs, out_fd); | ||||
|     close(fd); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool process_directory(const char *direcotry) | ||||
| { | ||||
|     DIR *dp; | ||||
|     struct dirent *ep; | ||||
|     char path[256]; | ||||
| 
 | ||||
|     dp = opendir(direcotry); | ||||
|     if (dp != NULL) { | ||||
|         while ((ep = readdir(dp)) != 0) { | ||||
|             if (!strcmp(ep->d_name, ".") ||  | ||||
|                 !strcmp(ep->d_name, "..")) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (ep->d_type != DT_REG) { | ||||
|                 continue;  // not a regular file
 | ||||
|             } | ||||
|             sprintf(path, "%s/%s", direcotry, ep->d_name); | ||||
|             printf("Processing file %s\n", path); | ||||
|             if (!process_file(path, ep->d_name)) { | ||||
|                 printf("Error processing file\n");    | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         closedir(dp); | ||||
|     } else { | ||||
|         printf("Error reading direcotry: %s\n", direcotry); | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static bool write_image(const char *out_file) | ||||
| { | ||||
|     int fd; | ||||
|     int size = SPIFFS_SIZE; | ||||
|     uint8_t *p = (uint8_t*)image; | ||||
|     fd = open(out_file, O_WRONLY | O_CREAT | O_TRUNC, 0666); | ||||
|     if (fd < 0) { | ||||
|         printf("Error creating file %s\n", out_file); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     printf("Writing image to file: %s\n", out_file); | ||||
| 
 | ||||
|     while (size != 0) { | ||||
|         write(fd, p, SPIFFS_CFG_LOG_PAGE_SZ()); | ||||
|         p += SPIFFS_CFG_LOG_PAGE_SZ(); | ||||
|         size -= SPIFFS_CFG_LOG_PAGE_SZ(); | ||||
|     } | ||||
| 
 | ||||
|     close(fd); | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|     int result = 0; | ||||
|      | ||||
|     if (argc != 3) { | ||||
|         print_usage(argv[0], NULL); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     if (init_spiffs(/*allocate_mem=*/true)) { | ||||
|         if (format_spiffs()) { | ||||
|             if (process_directory(argv[1])) { | ||||
|                 if (!write_image(argv[2])) { | ||||
|                     printf("Error writing image\n"); | ||||
|                 }        | ||||
|             } else { | ||||
|                 printf("Error processing direcotry\n"); | ||||
|             } | ||||
|         } else { | ||||
|             printf("Error formating spiffs\n"); | ||||
|         } | ||||
|     } else { | ||||
|         printf("Error initialising SPIFFS\n"); | ||||
|     } | ||||
|        | ||||
|     spiffs_free(); | ||||
|     return result; | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue