diff --git a/.gitignore b/.gitignore index ac4dec2e6..f5001c1dd 100644 --- a/.gitignore +++ b/.gitignore @@ -41,4 +41,5 @@ docs/doxygen_sqlite3.db .settings # MacOS directory files -.DS_Store \ No newline at end of file +.DS_Store +examples/wifi/getting_started/station/.vs/ diff --git a/components/esp8266/driver/spi.c b/components/esp8266/driver/spi.c index a5a3ed4b9..4edc0969a 100644 --- a/components/esp8266/driver/spi.c +++ b/components/esp8266/driver/spi.c @@ -489,9 +489,8 @@ static esp_err_t SPI_HIGH_THROUGHPUT_ATTR spi_master_trans(spi_host_t host, spi_ SPI[host]->data_buf[y] = trans->mosi[y]; } } else { - ESP_LOGW(TAG,"Using unaligned data may reduce transmission efficiency"); - memset(spi_object[host]->buf, 0, sizeof(uint32_t) * 16); - memcpy(spi_object[host]->buf, trans->mosi, trans->bits.mosi / 8 + (trans->bits.mosi % 8) ? 1 : 0); + memcpy(spi_object[host]->buf, trans->mosi, trans->bits.mosi / 8 + ((trans->bits.mosi % 8) ? 1 : 0)); + for (x = 0; x < trans->bits.mosi; x += 32) { y = x / 32; SPI[host]->data_buf[y] = spi_object[host]->buf[y]; @@ -522,19 +521,17 @@ static esp_err_t SPI_HIGH_THROUGHPUT_ATTR spi_master_trans(spi_host_t host, spi_ if (trans->bits.miso && trans->miso) { while (SPI[host]->cmd.usr); - if ((uint32_t)(trans->miso) % 4 == 0) { + if ((uint32_t)(trans->miso) % 4 == 0 && trans->bits.miso % 32 == 0) { for (x = 0; x < trans->bits.miso; x += 32) { y = x / 32; trans->miso[y] = SPI[host]->data_buf[y]; } } else { - ESP_LOGW(TAG,"Using unaligned data may reduce transmission efficiency"); - memset(spi_object[host]->buf, 0, sizeof(uint32_t) * 16); for (x = 0; x < trans->bits.miso; x += 32) { y = x / 32; spi_object[host]->buf[y] = SPI[host]->data_buf[y]; } - memcpy(trans->miso, spi_object[host]->buf, trans->bits.miso / 8 + (trans->bits.miso % 8) ? 1 : 0); + memcpy(trans->miso, spi_object[host]->buf, trans->bits.miso / 8 + ((trans->bits.miso % 8) ? 1 : 0)); } } @@ -577,7 +574,7 @@ static esp_err_t SPI_HIGH_THROUGHPUT_ATTR spi_slave_trans(spi_host_t host, spi_t } else { ESP_LOGW(TAG,"Using unaligned data may reduce transmission efficiency"); memset(spi_object[host]->buf, 0, sizeof(uint32_t) * 16); - memcpy(spi_object[host]->buf, trans->miso, trans->bits.miso / 8 + (trans->bits.miso % 8) ? 1 : 0); + memcpy(spi_object[host]->buf, trans->miso, trans->bits.miso / 8 + ((trans->bits.miso % 8) ? 1 : 0)); for (x = 0; x < trans->bits.miso; x += 32) { y = x / 32; SPI[host]->data_buf[y] = spi_object[host]->buf[y]; @@ -599,7 +596,7 @@ static esp_err_t SPI_HIGH_THROUGHPUT_ATTR spi_slave_trans(spi_host_t host, spi_t y = x / 32; spi_object[host]->buf[y] = SPI[host]->data_buf[y]; } - memcpy(trans->mosi, spi_object[host]->buf, trans->bits.mosi / 8 + (trans->bits.mosi % 8) ? 1 : 0); + memcpy(trans->mosi, spi_object[host]->buf, trans->bits.mosi / 8 + ((trans->bits.mosi % 8) ? 1 : 0)); } } diff --git a/components/spi_flash/CMakeLists.txt b/components/spi_flash/CMakeLists.txt index b2a0f715c..7b7d4ab28 100644 --- a/components/spi_flash/CMakeLists.txt +++ b/components/spi_flash/CMakeLists.txt @@ -1,4 +1,4 @@ -set(srcs "src/partition" +set(srcs "src/partition.c" "src/spi_flash_raw.c" "src/spi_flash.c") if(BOOTLOADER_BUILD) diff --git a/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c b/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c index 0378fef24..845552de5 100644 --- a/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c +++ b/examples/protocols/https_mbedtls/main/https_mbedtls_example_main.c @@ -47,9 +47,11 @@ #include "mbedtls/certs.h" /* Constants that aren't configurable in menuconfig */ -#define WEB_SERVER "www.howsmyssl.com" +//#define WEB_SERVER "www.howsmyssl.com" +#define WEB_SERVER "home.z52.hu" #define WEB_PORT "443" -#define WEB_URL "https://www.howsmyssl.com/a/check" +//#define WEB_URL "https://www.howsmyssl.com/a/check" +#define WEB_URL "https://home.z52.hu" static const char *TAG = "example"; diff --git a/examples/storage/spiffs/CMakeLists.txt b/examples/storage/spiffs/CMakeLists.txt index 1894b31ca..be8af338e 100644 --- a/examples/storage/spiffs/CMakeLists.txt +++ b/examples/storage/spiffs/CMakeLists.txt @@ -4,3 +4,4 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(spiffs) +spiffs_create_partition_image(spiffs data) \ No newline at end of file diff --git a/examples/storage/spiffs/_spiffs.bin b/examples/storage/spiffs/_spiffs.bin new file mode 100644 index 000000000..b9280faf3 Binary files /dev/null and b/examples/storage/spiffs/_spiffs.bin differ diff --git a/examples/storage/spiffs/_spiffs_r.bin b/examples/storage/spiffs/_spiffs_r.bin new file mode 100644 index 000000000..828673cb0 Binary files /dev/null and b/examples/storage/spiffs/_spiffs_r.bin differ diff --git a/examples/storage/spiffs/data/ademo.txt b/examples/storage/spiffs/data/ademo.txt new file mode 100644 index 000000000..6ca5b39cf --- /dev/null +++ b/examples/storage/spiffs/data/ademo.txt @@ -0,0 +1,5 @@ +ademo szoveg + + + + diff --git a/examples/storage/spiffs/data/demo.txt b/examples/storage/spiffs/data/demo.txt new file mode 100644 index 000000000..1fcd2f725 --- /dev/null +++ b/examples/storage/spiffs/data/demo.txt @@ -0,0 +1,5 @@ +masik demo szoveg + + + + diff --git a/examples/storage/spiffs/flashspiffs.bat b/examples/storage/spiffs/flashspiffs.bat new file mode 100644 index 000000000..4612e1111 --- /dev/null +++ b/examples/storage/spiffs/flashspiffs.bat @@ -0,0 +1,3 @@ +rem mkspiffs -c data -b 4096 -p 256 -s 458752 spiffs.bin +python spiffsgen.py 0x70000 data spiffs.bin +python %IDF_PATH%/components/esptool_py/esptool/esptool.py --chip esp8266 --port COM5 --baud 115200 --before default_reset --after hard_reset write_flash -z 0x90000 spiffs.bin \ No newline at end of file diff --git a/examples/storage/spiffs/main/spiffs_example_main.c b/examples/storage/spiffs/main/spiffs_example_main.c index 2148139a3..83b667a95 100644 --- a/examples/storage/spiffs/main/spiffs_example_main.c +++ b/examples/storage/spiffs/main/spiffs_example_main.c @@ -13,6 +13,8 @@ #include "esp_err.h" #include "esp_log.h" #include "esp_spiffs.h" +#include +#include static const char *TAG = "example"; @@ -21,7 +23,7 @@ void app_main(void) ESP_LOGI(TAG, "Initializing SPIFFS"); esp_vfs_spiffs_conf_t conf = { - .base_path = "/spiffs", + .base_path = "", .partition_label = NULL, .max_files = 5, .format_if_mount_failed = true @@ -49,36 +51,58 @@ void app_main(void) } else { ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); } + + + DIR *dp; + struct dirent *ep; + dp = opendir ("/"); - // Use POSIX and C standard library functions to work with files. - // First create a file. - ESP_LOGI(TAG, "Opening file"); - FILE* f = fopen("/spiffs/hello.txt", "w"); - if (f == NULL) { - ESP_LOGE(TAG, "Failed to open file for writing"); - return; - } - fprintf(f, "Hello World!\n"); - fclose(f); - ESP_LOGI(TAG, "File written"); + if (dp != NULL) + { + while ((ep = readdir (dp))) + puts (ep->d_name); - // Check if destination file exists before renaming - struct stat st; - if (stat("/spiffs/foo.txt", &st) == 0) { - // Delete it if it exists - unlink("/spiffs/foo.txt"); - } + (void) closedir (dp); + } + else + ESP_LOGE(TAG, "Couldn't open the directory"); + + FILE* f = NULL; + + // // // Use POSIX and C standard library functions to work with files. + // // // First create a file. + // ESP_LOGI(TAG, "Opening file"); + // f = fopen("/ademo.txt", "w"); + // if (f == NULL) { + // ESP_LOGE(TAG, "Failed to open file for writing"); + // return; + // } + // fprintf(f, "ademo szoveg"); + // fclose(f); + // ESP_LOGI(TAG, "File written"); - // Rename original file - ESP_LOGI(TAG, "Renaming file"); - if (rename("/spiffs/hello.txt", "/spiffs/foo.txt") != 0) { - ESP_LOGE(TAG, "Rename failed"); - return; - } + // // Check if destination file exists before renaming + // struct stat st; + // if (stat("/spiffs/foo.txt", &st) == 0) { + // // Delete it if it exists + // unlink("/spiffs/foo.txt"); + // } + + // // Rename original file + // ESP_LOGI(TAG, "Renaming file"); + // if (rename("/spiffs/hello.txt", "/spiffs/foo.txt") != 0) { + // ESP_LOGE(TAG, "Rename failed"); + // return; + // } + +struct stat st; +stat("/demo.txt", &st); +int size = st.st_size; // Open renamed file for reading - ESP_LOGI(TAG, "Reading file"); - f = fopen("/spiffs/foo.txt", "r"); + ESP_LOGI(TAG, "Reading file (size %u)",size); + f = fopen("/ademo.txt", "r"); + //f = fopen("/spiffs/foo.txt", "r"); if (f == NULL) { ESP_LOGE(TAG, "Failed to open file for reading"); return; @@ -91,6 +115,22 @@ void app_main(void) if (pos) { *pos = '\0'; } + ESP_LOGI(TAG, "Read from file: '%s'", line); + + // Open file for reading + ESP_LOGI(TAG, "Reading file"); + f = fopen("/demo.txt", "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return; + } + fgets(line, sizeof(line), f); + fclose(f); + // strip newline + pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } ESP_LOGI(TAG, "Read from file: '%s'", line); // All done, unmount partition and disable SPIFFS diff --git a/examples/storage/spiffs/mkspiffs.exe b/examples/storage/spiffs/mkspiffs.exe new file mode 100644 index 000000000..c1d8e28e6 Binary files /dev/null and b/examples/storage/spiffs/mkspiffs.exe differ diff --git a/examples/storage/spiffs/spiffsgen.py b/examples/storage/spiffs/spiffsgen.py new file mode 100644 index 000000000..96d48bf01 --- /dev/null +++ b/examples/storage/spiffs/spiffsgen.py @@ -0,0 +1,604 @@ +#!/usr/bin/env python +# +# spiffsgen is a tool used to generate a spiffs image from a directory +# +# Copyright 2019 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. + +from __future__ import division, print_function + +import argparse +import io +import math +import os +import struct + +try: + import typing + + TSP = typing.TypeVar('TSP', bound='SpiffsObjPageWithIdx') + ObjIdsItem = typing.Tuple[int, typing.Type[TSP]] +except ImportError: + pass + + +SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xF8 +SPIFFS_PH_FLAG_USED_FINAL = 0xFC + +SPIFFS_PH_FLAG_LEN = 1 +SPIFFS_PH_IX_SIZE_LEN = 4 +SPIFFS_PH_IX_OBJ_TYPE_LEN = 1 +SPIFFS_TYPE_FILE = 1 + +# Based on typedefs under spiffs_config.h +SPIFFS_OBJ_ID_LEN = 2 # spiffs_obj_id +SPIFFS_SPAN_IX_LEN = 2 # spiffs_span_ix +SPIFFS_PAGE_IX_LEN = 2 # spiffs_page_ix +SPIFFS_BLOCK_IX_LEN = 2 # spiffs_block_ix + + +class SpiffsBuildConfig(object): + def __init__(self, + page_size, # type: int + page_ix_len, # type: int + block_size, # type: int + block_ix_len, # type: int + meta_len, # type: int + obj_name_len, # type: int + obj_id_len, # type: int + span_ix_len, # type: int + packed, # type: bool + aligned, # type: bool + endianness, # type: str + use_magic, # type: bool + use_magic_len, # type: bool + aligned_obj_ix_tables # type: bool + ): + if block_size % page_size != 0: + raise RuntimeError('block size should be a multiple of page size') + + self.page_size = page_size + self.block_size = block_size + self.obj_id_len = obj_id_len + self.span_ix_len = span_ix_len + self.packed = packed + self.aligned = aligned + self.obj_name_len = obj_name_len + self.meta_len = meta_len + self.page_ix_len = page_ix_len + self.block_ix_len = block_ix_len + self.endianness = endianness + self.use_magic = use_magic + self.use_magic_len = use_magic_len + self.aligned_obj_ix_tables = aligned_obj_ix_tables + + self.PAGES_PER_BLOCK = self.block_size // self.page_size + self.OBJ_LU_PAGES_PER_BLOCK = int(math.ceil(self.block_size / self.page_size * self.obj_id_len / self.page_size)) + self.OBJ_USABLE_PAGES_PER_BLOCK = self.PAGES_PER_BLOCK - self.OBJ_LU_PAGES_PER_BLOCK + + self.OBJ_LU_PAGES_OBJ_IDS_LIM = self.page_size // self.obj_id_len + + self.OBJ_DATA_PAGE_HEADER_LEN = self.obj_id_len + self.span_ix_len + SPIFFS_PH_FLAG_LEN + + pad = 4 - (4 if self.OBJ_DATA_PAGE_HEADER_LEN % 4 == 0 else self.OBJ_DATA_PAGE_HEADER_LEN % 4) + + self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED = self.OBJ_DATA_PAGE_HEADER_LEN + pad + self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD = pad + self.OBJ_DATA_PAGE_CONTENT_LEN = self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN + + self.OBJ_INDEX_PAGES_HEADER_LEN = (self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED + SPIFFS_PH_IX_SIZE_LEN + + SPIFFS_PH_IX_OBJ_TYPE_LEN + self.obj_name_len + self.meta_len) + if aligned_obj_ix_tables: + self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = (self.OBJ_INDEX_PAGES_HEADER_LEN + SPIFFS_PAGE_IX_LEN - 1) & ~(SPIFFS_PAGE_IX_LEN - 1) + self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED - self.OBJ_INDEX_PAGES_HEADER_LEN + else: + self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = self.OBJ_INDEX_PAGES_HEADER_LEN + self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = 0 + + self.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM = (self.page_size - self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED) // self.block_ix_len + self.OBJ_INDEX_PAGES_OBJ_IDS_LIM = (self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED) // self.block_ix_len + + +class SpiffsFullError(RuntimeError): + pass + + +class SpiffsPage(object): + _endianness_dict = { + 'little': '<', + 'big': '>' + } + + _len_dict = { + 1: 'B', + 2: 'H', + 4: 'I', + 8: 'Q' + } + + def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None + self.build_config = build_config + self.bix = bix + + def to_binary(self): # type: () -> bytes + raise NotImplementedError() + + +class SpiffsObjPageWithIdx(SpiffsPage): + def __init__(self, obj_id, build_config): # type: (int, SpiffsBuildConfig) -> None + super(SpiffsObjPageWithIdx, self).__init__(0, build_config) + self.obj_id = obj_id + + def to_binary(self): # type: () -> bytes + raise NotImplementedError() + + +class SpiffsObjLuPage(SpiffsPage): + def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None + SpiffsPage.__init__(self, bix, build_config) + + self.obj_ids_limit = self.build_config.OBJ_LU_PAGES_OBJ_IDS_LIM + self.obj_ids = list() # type: typing.List[ObjIdsItem] + + def _calc_magic(self, blocks_lim): # type: (int) -> int + # Calculate the magic value mirroring computation done by the macro SPIFFS_MAGIC defined in + # spiffs_nucleus.h + magic = 0x20140529 ^ self.build_config.page_size + if self.build_config.use_magic_len: + magic = magic ^ (blocks_lim - self.bix) + # narrow the result to build_config.obj_id_len bytes + mask = (2 << (8 * self.build_config.obj_id_len)) - 1 + return magic & mask + + def register_page(self, page): # type: (TSP) -> None + if not self.obj_ids_limit > 0: + raise SpiffsFullError() + + obj_id = (page.obj_id, page.__class__) + self.obj_ids.append(obj_id) + self.obj_ids_limit -= 1 + + def to_binary(self): # type: () -> bytes + img = b'' + + for (obj_id, page_type) in self.obj_ids: + if page_type == SpiffsObjIndexPage: + obj_id ^= (1 << ((self.build_config.obj_id_len * 8) - 1)) + img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + + SpiffsPage._len_dict[self.build_config.obj_id_len], obj_id) + + assert(len(img) <= self.build_config.page_size) + + img += b'\xFF' * (self.build_config.page_size - len(img)) + + return img + + def magicfy(self, blocks_lim): # type: (int) -> None + # Only use magic value if no valid obj id has been written to the spot, which is the + # spot taken up by the last obj id on last lookup page. The parent is responsible + # for determining which is the last lookup page and calling this function. + remaining = self.obj_ids_limit + empty_obj_id_dict = { + 1: 0xFF, + 2: 0xFFFF, + 4: 0xFFFFFFFF, + 8: 0xFFFFFFFFFFFFFFFF + } + if remaining >= 2: + for i in range(remaining): + if i == remaining - 2: + self.obj_ids.append((self._calc_magic(blocks_lim), SpiffsObjDataPage)) + break + else: + self.obj_ids.append((empty_obj_id_dict[self.build_config.obj_id_len], SpiffsObjDataPage)) + self.obj_ids_limit -= 1 + + +class SpiffsObjIndexPage(SpiffsObjPageWithIdx): + def __init__(self, obj_id, span_ix, size, name, build_config + ): # type: (int, int, int, str, SpiffsBuildConfig) -> None + super(SpiffsObjIndexPage, self).__init__(obj_id, build_config) + self.span_ix = span_ix + self.name = name + self.size = size + + if self.span_ix == 0: + self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM + else: + self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_LIM + + self.pages = list() # type: typing.List[int] + + def register_page(self, page): # type: (SpiffsObjDataPage) -> None + if not self.pages_lim > 0: + raise SpiffsFullError + + self.pages.append(page.offset) + self.pages_lim -= 1 + + def to_binary(self): # type: () -> bytes + obj_id = self.obj_id ^ (1 << ((self.build_config.obj_id_len * 8) - 1)) + img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + + SpiffsPage._len_dict[self.build_config.obj_id_len] + + SpiffsPage._len_dict[self.build_config.span_ix_len] + + SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN], + obj_id, + self.span_ix, + SPIFFS_PH_FLAG_USED_FINAL_INDEX) + + # Add padding before the object index page specific information + img += b'\xFF' * self.build_config.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD + + # If this is the first object index page for the object, add filname, type + # and size information + if self.span_ix == 0: + img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + + SpiffsPage._len_dict[SPIFFS_PH_IX_SIZE_LEN] + + SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN], + self.size, + SPIFFS_TYPE_FILE) + + img += self.name.encode() + (b'\x00' * ( + (self.build_config.obj_name_len - len(self.name)) + + self.build_config.meta_len + + self.build_config.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD)) + + # Finally, add the page index of daa pages + for page in self.pages: + page = page >> int(math.log(self.build_config.page_size, 2)) + img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + + SpiffsPage._len_dict[self.build_config.page_ix_len], page) + + assert(len(img) <= self.build_config.page_size) + + img += b'\xFF' * (self.build_config.page_size - len(img)) + + return img + + +class SpiffsObjDataPage(SpiffsObjPageWithIdx): + def __init__(self, offset, obj_id, span_ix, contents, build_config + ): # type: (int, int, int, bytes, SpiffsBuildConfig) -> None + super(SpiffsObjDataPage, self).__init__(obj_id, build_config) + self.span_ix = span_ix + self.contents = contents + self.offset = offset + + def to_binary(self): # type: () -> bytes + img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + + SpiffsPage._len_dict[self.build_config.obj_id_len] + + SpiffsPage._len_dict[self.build_config.span_ix_len] + + SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN], + self.obj_id, + self.span_ix, + SPIFFS_PH_FLAG_USED_FINAL) + + img += self.contents + + assert(len(img) <= self.build_config.page_size) + + img += b'\xFF' * (self.build_config.page_size - len(img)) + + return img + + +class SpiffsBlock(object): + def _reset(self): # type: () -> None + self.cur_obj_index_span_ix = 0 + self.cur_obj_data_span_ix = 0 + self.cur_obj_id = 0 + self.cur_obj_idx_page = None # type: typing.Optional[SpiffsObjIndexPage] + + def __init__(self, bix, build_config): # type: (int, SpiffsBuildConfig) -> None + self.build_config = build_config + self.offset = bix * self.build_config.block_size + self.remaining_pages = self.build_config.OBJ_USABLE_PAGES_PER_BLOCK + self.pages = list() # type: typing.List[SpiffsPage] + self.bix = bix + + lu_pages = list() + for i in range(self.build_config.OBJ_LU_PAGES_PER_BLOCK): + page = SpiffsObjLuPage(self.bix, self.build_config) + lu_pages.append(page) + + self.pages.extend(lu_pages) + + self.lu_page_iter = iter(lu_pages) + self.lu_page = next(self.lu_page_iter) + + self._reset() + + def _register_page(self, page): # type: (TSP) -> None + if isinstance(page, SpiffsObjDataPage): + assert self.cur_obj_idx_page is not None + self.cur_obj_idx_page.register_page(page) # can raise SpiffsFullError + + try: + self.lu_page.register_page(page) + except SpiffsFullError: + self.lu_page = next(self.lu_page_iter) + try: + self.lu_page.register_page(page) + except AttributeError: # no next lookup page + # Since the amount of lookup pages is pre-computed at every block instance, + # this should never occur + raise RuntimeError('invalid attempt to add page to a block when there is no more space in lookup') + + self.pages.append(page) + + def begin_obj(self, obj_id, size, name, obj_index_span_ix=0, obj_data_span_ix=0 + ): # type: (int, int, str, int, int) -> None + if not self.remaining_pages > 0: + raise SpiffsFullError() + self._reset() + + self.cur_obj_id = obj_id + self.cur_obj_index_span_ix = obj_index_span_ix + self.cur_obj_data_span_ix = obj_data_span_ix + + page = SpiffsObjIndexPage(obj_id, self.cur_obj_index_span_ix, size, name, self.build_config) + self._register_page(page) + + self.cur_obj_idx_page = page + + self.remaining_pages -= 1 + self.cur_obj_index_span_ix += 1 + + def update_obj(self, contents): # type: (bytes) -> None + if not self.remaining_pages > 0: + raise SpiffsFullError() + page = SpiffsObjDataPage(self.offset + (len(self.pages) * self.build_config.page_size), + self.cur_obj_id, self.cur_obj_data_span_ix, contents, self.build_config) + + self._register_page(page) + + self.cur_obj_data_span_ix += 1 + self.remaining_pages -= 1 + + def end_obj(self): # type: () -> None + self._reset() + + def is_full(self): # type: () -> bool + return self.remaining_pages <= 0 + + def to_binary(self, blocks_lim): # type: (int) -> bytes + img = b'' + + if self.build_config.use_magic: + for (idx, page) in enumerate(self.pages): + if idx == self.build_config.OBJ_LU_PAGES_PER_BLOCK - 1: + assert isinstance(page, SpiffsObjLuPage) + page.magicfy(blocks_lim) + img += page.to_binary() + else: + for page in self.pages: + img += page.to_binary() + + assert(len(img) <= self.build_config.block_size) + + img += b'\xFF' * (self.build_config.block_size - len(img)) + return img + + +class SpiffsFS(object): + def __init__(self, img_size, build_config): # type: (int, SpiffsBuildConfig) -> None + if img_size % build_config.block_size != 0: + raise RuntimeError('image size should be a multiple of block size') + + self.img_size = img_size + self.build_config = build_config + + self.blocks = list() # type: typing.List[SpiffsBlock] + self.blocks_lim = self.img_size // self.build_config.block_size + self.remaining_blocks = self.blocks_lim + self.cur_obj_id = 1 # starting object id + + def _create_block(self): # type: () -> SpiffsBlock + if self.is_full(): + raise SpiffsFullError('the image size has been exceeded') + + block = SpiffsBlock(len(self.blocks), self.build_config) + self.blocks.append(block) + self.remaining_blocks -= 1 + return block + + def is_full(self): # type: () -> bool + return self.remaining_blocks <= 0 + + def create_file(self, img_path, file_path): # type: (str, str) -> None + if len(img_path) > self.build_config.obj_name_len: + raise RuntimeError("object name '%s' too long" % img_path) + + name = img_path + + with open(file_path, 'rb') as obj: + contents = obj.read() + + stream = io.BytesIO(contents) + + try: + block = self.blocks[-1] + block.begin_obj(self.cur_obj_id, len(contents), name) + except (IndexError, SpiffsFullError): + block = self._create_block() + block.begin_obj(self.cur_obj_id, len(contents), name) + + contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN) + + while contents_chunk: + try: + block = self.blocks[-1] + try: + # This can fail because either (1) all the pages in block have been + # used or (2) object index has been exhausted. + block.update_obj(contents_chunk) + except SpiffsFullError: + # If its (1), use the outer exception handler + if block.is_full(): + raise SpiffsFullError + # If its (2), write another object index page + block.begin_obj(self.cur_obj_id, len(contents), name, + obj_index_span_ix=block.cur_obj_index_span_ix, + obj_data_span_ix=block.cur_obj_data_span_ix) + continue + except (IndexError, SpiffsFullError): + # All pages in the block have been exhausted. Create a new block, copying + # the previous state of the block to a new one for the continuation of the + # current object + prev_block = block + block = self._create_block() + block.cur_obj_id = prev_block.cur_obj_id + block.cur_obj_idx_page = prev_block.cur_obj_idx_page + block.cur_obj_data_span_ix = prev_block.cur_obj_data_span_ix + block.cur_obj_index_span_ix = prev_block.cur_obj_index_span_ix + continue + + contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN) + + block.end_obj() + + self.cur_obj_id += 1 + + def to_binary(self): # type: () -> bytes + img = b'' + all_blocks = [] + for block in self.blocks: + all_blocks.append(block.to_binary(self.blocks_lim)) + bix = len(self.blocks) + if self.build_config.use_magic: + # Create empty blocks with magic numbers + while self.remaining_blocks > 0: + block = SpiffsBlock(bix, self.build_config) + all_blocks.append(block.to_binary(self.blocks_lim)) + self.remaining_blocks -= 1 + bix += 1 + else: + # Just fill remaining spaces FF's + all_blocks.append(b'\xFF' * (self.img_size - len(all_blocks) * self.build_config.block_size)) + img += b''.join([blk for blk in all_blocks]) + return img + + +class CustomHelpFormatter(argparse.HelpFormatter): + """ + Similar to argparse.ArgumentDefaultsHelpFormatter, except it + doesn't add the default value if "(default:" is already present. + This helps in the case of options with action="store_false", like + --no-magic or --no-magic-len. + """ + def _get_help_string(self, action): # type: (argparse.Action) -> str + if action.help is None: + return '' + if '%(default)' not in action.help and '(default:' not in action.help: + if action.default is not argparse.SUPPRESS: + defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE] + if action.option_strings or action.nargs in defaulting_nargs: + return action.help + ' (default: %(default)s)' + return action.help + + +def main(): # type: () -> None + parser = argparse.ArgumentParser(description='SPIFFS Image Generator', + formatter_class=CustomHelpFormatter) + + parser.add_argument('image_size', + help='Size of the created image') + + parser.add_argument('base_dir', + help='Path to directory from which the image will be created') + + parser.add_argument('output_file', + help='Created image output file path') + + parser.add_argument('--page-size', + help='Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE.', + type=int, + default=256) + + parser.add_argument('--block-size', + help="Logical block size. Set to the same value as the flash chip's sector size (g_rom_flashchip.sector_size).", + type=int, + default=4096) + + parser.add_argument('--obj-name-len', + help='File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN.', + type=int, + default=32) + + parser.add_argument('--meta-len', + help='File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH.', + type=int, + default=4) + + parser.add_argument('--use-magic', + dest='use_magic', + help='Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.', + action='store_true') + + parser.add_argument('--no-magic', + dest='use_magic', + help='Inverse of --use-magic (default: --use-magic is enabled)', + action='store_false') + + parser.add_argument('--use-magic-len', + dest='use_magic_len', + help='Use position in memory to create different magic numbers for each block. Specify if CONFIG_SPIFFS_USE_MAGIC_LENGTH.', + action='store_true') + + parser.add_argument('--no-magic-len', + dest='use_magic_len', + help='Inverse of --use-magic-len (default: --use-magic-len is enabled)', + action='store_false') + + parser.add_argument('--follow-symlinks', + help='Take into account symbolic links during partition image creation.', + action='store_true') + + parser.add_argument('--big-endian', + help='Specify if the target architecture is big-endian. If not specified, little-endian is assumed.', + action='store_true') + + parser.add_argument('--aligned-obj-ix-tables', + action='store_true', + help='Use aligned object index tables. Specify if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES is set.') + + parser.set_defaults(use_magic=True, use_magic_len=True) + + args = parser.parse_args() + + if not os.path.exists(args.base_dir): + raise RuntimeError('given base directory %s does not exist' % args.base_dir) + + with open(args.output_file, 'wb') as image_file: + image_size = int(args.image_size, 0) + spiffs_build_default = SpiffsBuildConfig(args.page_size, SPIFFS_PAGE_IX_LEN, + args.block_size, SPIFFS_BLOCK_IX_LEN, args.meta_len, + args.obj_name_len, SPIFFS_OBJ_ID_LEN, SPIFFS_SPAN_IX_LEN, + True, True, 'big' if args.big_endian else 'little', + args.use_magic, args.use_magic_len, args.aligned_obj_ix_tables) + + spiffs = SpiffsFS(image_size, spiffs_build_default) + + for root, dirs, files in os.walk(args.base_dir, followlinks=args.follow_symlinks): + for f in files: + full_path = os.path.join(root, f) + spiffs.create_file('/' + os.path.relpath(full_path, args.base_dir).replace('\\', '/'), full_path) + + image = spiffs.to_binary() + + image_file.write(image) + + +if __name__ == '__main__': + main() diff --git a/examples/wifi/getting_started/station/CMakeSettings.json b/examples/wifi/getting_started/station/CMakeSettings.json new file mode 100644 index 000000000..b6dba59cd --- /dev/null +++ b/examples/wifi/getting_started/station/CMakeSettings.json @@ -0,0 +1,23 @@ +{ + // See https://go.microsoft.com/fwlink/?linkid=834763 for more information about this file. + "configurations": [ + { + "name": "ESP", + "generator": "Ninja", + "configurationType": "Release", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "", + "inheritEnvironments": [ "linux_arm" ], + "environments": [ + { + "XTENSA": "${env.IDF_TOOLS_PATH}\\tools\\xtensa-lx106-elf\\esp-2020r3-49-gd5524c1-8.4.0\\xtensa-lx106-elf", + "INCLUDE": "${env.XTENSA}\\xtensa-lx106-elf\\include;${env.XTENSA}\\lib\\gcc\\xtensa-lx106-elf\\8.4.0\\include;${env.XTENSA}\\lib\\gcc\\xtensa-lx106-elf\\8.4.0\\include-fixed;${env.XTENSA}\\xtensa-lx106-elf\\include\\c++\\8.4.0;" + } + ], + "intelliSenseMode": "linux-gcc-x64" + } + ] +} \ No newline at end of file