From a476098fcc47893008e99952dcd92d4457d84a2f Mon Sep 17 00:00:00 2001 From: becseya Date: Wed, 21 Aug 2024 11:47:29 +0200 Subject: [PATCH] feat(fs): default drive letter + ESP FS docs (#6367) Co-authored-by: Gabor Kiss-Vamosi --- .devcontainer/__lv_conf.h__ | 3 + Kconfig | 22 ++-- docs/integration/chip/espressif.rst | 117 +++++++++++++++++- docs/integration/chip/renesas.rst | 2 +- docs/integration/ide/pc-simulator.rst | 2 +- ...-littlefs.rst => arduino_esp_littlefs.rst} | 5 +- docs/libs/{arduino-sd.rst => arduino_sd.rst} | 5 +- docs/libs/fs.rst | 19 ++- docs/libs/lfs.rst | 2 +- docs/overview/fs.rst | 4 + docs/porting/display.rst | 4 +- docs/porting/indev.rst | 2 +- docs/widgets/image.rst | 2 +- lv_conf_template.h | 3 + src/libs/fsdrv/lv_fs_arduino_esp_littlefs.cpp | 20 +++ src/libs/fsdrv/lv_fs_arduino_sd.cpp | 19 +++ src/libs/fsdrv/lv_fs_fatfs.c | 11 +- src/libs/fsdrv/lv_fs_littlefs.c | 13 ++ src/libs/fsdrv/lv_fs_memfs.c | 12 ++ src/libs/fsdrv/lv_fs_posix.c | 11 +- src/libs/fsdrv/lv_fs_stdio.c | 13 ++ src/libs/fsdrv/lv_fs_win32.c | 13 ++ src/lv_conf_internal.h | 9 ++ src/misc/lv_fs.c | 59 ++++++--- 24 files changed, 333 insertions(+), 39 deletions(-) rename docs/libs/{arduino-littlefs.rst => arduino_esp_littlefs.rst} (82%) rename docs/libs/{arduino-sd.rst => arduino_sd.rst} (81%) diff --git a/.devcontainer/__lv_conf.h__ b/.devcontainer/__lv_conf.h__ index a1424736d..990e7880d 100644 --- a/.devcontainer/__lv_conf.h__ +++ b/.devcontainer/__lv_conf.h__ @@ -597,6 +597,9 @@ /*File system interfaces for common APIs */ +/*Setting a default driver letter allows skipping the driver prefix in filepaths*/ +#define LV_FS_DEFAULT_DRIVE_LETTER '\0' + /*API for fopen, fread, etc*/ #define LV_USE_FS_STDIO 1 #if LV_USE_FS_STDIO diff --git a/Kconfig b/Kconfig index 2cf707a10..b79268fc6 100644 --- a/Kconfig +++ b/Kconfig @@ -1124,10 +1124,16 @@ menu "LVGL configuration" endmenu menu "3rd Party Libraries" + config LV_FS_DEFAULT_DRIVE_LETTER + int "Default drive letter (e.g. 65 for 'A')" + default 0 + help + Setting a default drive letter allows skipping the driver prefix in filepaths + config LV_USE_FS_STDIO bool "File system on top of stdio API" config LV_FS_STDIO_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65 )" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_STDIO config LV_FS_STDIO_PATH @@ -1141,7 +1147,7 @@ menu "LVGL configuration" config LV_USE_FS_POSIX bool "File system on top of posix API" config LV_FS_POSIX_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_POSIX config LV_FS_POSIX_PATH @@ -1155,7 +1161,7 @@ menu "LVGL configuration" config LV_USE_FS_WIN32 bool "File system on top of Win32 API" config LV_FS_WIN32_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_WIN32 config LV_FS_WIN32_PATH @@ -1169,7 +1175,7 @@ menu "LVGL configuration" config LV_USE_FS_FATFS bool "File system on top of FatFS" config LV_FS_FATFS_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_FATFS config LV_FS_FATFS_CACHE_SIZE @@ -1180,28 +1186,28 @@ menu "LVGL configuration" config LV_USE_FS_MEMFS bool "File system on top of memory-mapped API" config LV_FS_MEMFS_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_MEMFS config LV_USE_FS_LITTLEFS bool "File system on top of littlefs API" config LV_FS_LITTLEFS_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_LITTLEFS config LV_USE_FS_ARDUINO_ESP_LITTLEFS bool "File system on top of Arduino ESP littlefs API" config LV_FS_ARDUINO_ESP_LITTLEFS_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_ARDUINO_ESP_LITTLEFS config LV_USE_FS_ARDUINO_SD bool "File system on top of Arduino SD API" config LV_FS_ARDUINO_SD_LETTER - int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)" + int "Set an upper cased letter on which the drive will accessible (e.g. 65 for 'A')" default 0 depends on LV_USE_FS_ARDUINO_SD config LV_FS_ARDUINO_SD_CS_PIN diff --git a/docs/integration/chip/espressif.rst b/docs/integration/chip/espressif.rst index 1277d661a..f125db6cd 100644 --- a/docs/integration/chip/espressif.rst +++ b/docs/integration/chip/espressif.rst @@ -78,5 +78,120 @@ These components share a common public API, making it easy to migrate your proje To add a display or touch driver to your project, use a command like: .. code:: sh - idf.py add-dependency "espressif/esp_lcd_gc9a01^2.0.0" + +Using the File System under ESP-IDF +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ESP-IDF uses the standard C functions (``fopen``, ``fread``) in all storage related APIs. +This allows seamless interoperability with LVGL when enabling the :c:macro:`LV_USE_FS_STDIO` configuration. +The process is described in details below, using ``SPIFFS`` as demonstration. + +- **Decide what storage system you want to use** + + ESP-IDF has many, ready-to-use examples like + `SPIFFS `__ + , + `SD Card `__ + and + `LittleFS `__ + . + +- **Re-configure your own project** + + The example project should be examined for details, but in general the changes involve: + + - Enabling LVGL's STDIO file system in the configuration + + You can use ``menuconfig``: + + - ``Component config → LVGL configuration → 3rd Party Libraries``: enable ``File system on top of stdio API`` + - Then select ``Set an upper cased letter on which the drive will accessible`` and set it to ``65`` (ASCII **A**) + - You can also set ``Default driver letter`` to 65 to skip the prefix in file paths. + + - Modifying the partition table + + The exact configuration depends on your flash size and existing partitions, + but the new final result should look something like this: + + .. code:: csv + + nvs, data, nvs, 0x9000, 0x6000, + phy_init, data, phy, 0xf000, 0x1000, + factory, app, factory, 0x10000, 1400k, + storage, data, spiffs, , 400k, + + + .. note:: + + If you are not using a custom ``parition.csv`` yet, it can be added + via ``menuconfig`` (``Partition Table → Partition Table → Custom partition table CSV``). + + - Apply changes to the build system + + Some ESP file systems provide automatic generation from a host folder using CMake. The proper line(s) must be copied to ``main/CMakeLists.txt`` + + .. note:: + + ``LittleFS`` has extra dependencies that should be added to ``main/idf_component.yml`` + +- **Prepare the image files** + + LVGL's ``LVGLImage.py`` Python tool can be used to convert images to binary pixel map files. + It supports various formats and compression. + + Meanwhile 3rd party libraries + (like :ref:`LodePNG` and :ref:`Tiny JPEG`) + allow using image files without conversion. + + After preparing the files, they should be moved to the target device: + + - If properly activated a **SPIFFS** file system based on the ``spiffs_image`` folder should be automatically generated and later flashed to the target + - Similar mechanism for **LittleFS** uses the ``flash_data`` folder, but it's only available for Linux hosts + - For the **SD Card**, a traditional file browser can be used + +- **Invoke proper API calls in the application code** + + The core functionality requires only a few lines. The following example draws the image as well. + + .. code:: c + + #include "esp_spiffs.h" + + void lv_example_image_from_esp_fs(void) { + + esp_vfs_spiffs_conf_t conf = { + .base_path = "/spiffs", + .partition_label = NULL, + .max_files = 5, + .format_if_mount_failed = false + }; + + esp_err_t ret = esp_vfs_spiffs_register(&conf); + + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to register SPIFF filesystem"); + return; + } + + lv_obj_t * obj = lv_image_create(lv_screen_active()); + lv_image_set_src(obj, "A:/spiffs/logo.bin"); + lv_obj_center(obj); + } + +- **Build and flash** + + After calling ``idf.py build flash`` the picture should be displayed on the screen. + + +.. note:: + + Changes made by ``menuconfig`` are not being tracked in the repository if the ``sdkconfig`` file is added to ``.gitignore``, which is the default for many ESP-IDF projects. + To make your configuration permanent, add the following lines to ``sdkconfig.defaults``: + + .. code:: c + + CONFIG_PARTITION_TABLE_CUSTOM=y + CONFIG_LV_USE_FS_STDIO=y + CONFIG_LV_FS_STDIO_LETTER=65 + CONFIG_LV_LV_FS_DEFAULT_DRIVE_LETTER=65 diff --git a/docs/integration/chip/renesas.rst b/docs/integration/chip/renesas.rst index 6fc3212c1..d07929521 100644 --- a/docs/integration/chip/renesas.rst +++ b/docs/integration/chip/renesas.rst @@ -150,7 +150,7 @@ Get started with the Renesas ecosystem The compiler must be activated in e² studio: - Go to go to ``Help`` -> ``Add Renesas Toolchains`` - - Press the ``Add... `` button + - Press the ``Add...`` button - Browse the installation folder of the toolchain | diff --git a/docs/integration/ide/pc-simulator.rst b/docs/integration/ide/pc-simulator.rst index 743aae875..c133abfdf 100644 --- a/docs/integration/ide/pc-simulator.rst +++ b/docs/integration/ide/pc-simulator.rst @@ -16,7 +16,7 @@ Using the simulator on a PC has the following advantages: - Easy Validation: The simulator is also very useful to report bugs because it provides a common platform for every user. - Better developer experience: On PC Debuggers are usually faster and better, you can log to files, -add a lot of ``printf``s, do profiling, and so on. + add a lot of ``printf``-s, do profiling, and so on. Select an IDE diff --git a/docs/libs/arduino-littlefs.rst b/docs/libs/arduino_esp_littlefs.rst similarity index 82% rename from docs/libs/arduino-littlefs.rst rename to docs/libs/arduino_esp_littlefs.rst index d61ee2022..542dd6c05 100644 --- a/docs/libs/arduino-littlefs.rst +++ b/docs/libs/arduino_esp_littlefs.rst @@ -7,7 +7,8 @@ Arduino ESP littlefs LittleFS is a little fail-safe filesystem designed for microcontrollers and integrated in the Arduino framework when used with ESP32 and ESP8266. -Detailed introduction: +Detailed introduction: + - https://github.com/esp8266/Arduino - https://github.com/espressif/arduino-esp32 @@ -15,7 +16,7 @@ Detailed introduction: Usage ----- -Enable :c:macro:`LV_USE_FS_ARDUINO_ESP_LITTLEFS` and define a :c:macro`LV_FS_ARDUINO_ESP_LITTLEFS_LETTER` in ``lv_conf.h``. +Enable :c:macro:`LV_USE_FS_ARDUINO_ESP_LITTLEFS` and define a :c:macro:`LV_FS_ARDUINO_ESP_LITTLEFS_LETTER` in ``lv_conf.h``. API diff --git a/docs/libs/arduino-sd.rst b/docs/libs/arduino_sd.rst similarity index 81% rename from docs/libs/arduino-sd.rst rename to docs/libs/arduino_sd.rst index f337a7c63..97ae71319 100644 --- a/docs/libs/arduino-sd.rst +++ b/docs/libs/arduino_sd.rst @@ -8,14 +8,15 @@ Enables reading and writing on SD cards. Once an SD memory card is connected to the SPI interface of the Arduino or Genuino board you can create files and read/write on them. You can also move through directories on the SD card.. -Detailed introduction: +Detailed introduction: + - https://www.arduino.cc/reference/en/libraries/sd/ Usage ----- -Enable :c:macro:`LV_USE_FS_ARDUINO_SD` and define a :c:macro`LV_FS_ARDUINO_SD_LETTER` in ``lv_conf.h``. +Enable :c:macro:`LV_USE_FS_ARDUINO_SD` and define a :c:macro:`LV_FS_ARDUINO_SD_LETTER` in ``lv_conf.h``. You probably need to configure the :c:macro:`LV_FS_ARDUINO_SD_CS_PIN` and :c:macro:`LV_FS_ARDUINO_SD_FREQUENCY` that corresponds to the pin connected and the frequency used by the chip of the SD CARD. diff --git a/docs/libs/fs.rst b/docs/libs/fs.rst index 73937468c..589949ab7 100644 --- a/docs/libs/fs.rst +++ b/docs/libs/fs.rst @@ -30,9 +30,24 @@ In ``lv_conf.h`` enable ``LV_USE_FS_...`` and assign an upper cased letter to ``LV_FS_..._LETTER`` (e.g. ``'S'``). After that you can access files using that driver letter. E.g. ``"S:path/to/file.txt"``. -The work directory can be set with ``LV_FS_..._PATH``. E.g. +Working with common prefixes +"""""""""""""""""""""""""""" + +A **default driver letter** can be set by ``LV_FS_DEFAULT_DRIVE_LETTER``, +which allows skipping the drive prefix in file paths. + +For example if ``LV_FS_DEFAULT_DRIVE_LETTER`` is set the ``'S'`` *"path/to/file.txt"* will mean *"S:path/to/file.txt"*. + +This feature is useful if you have only a single driver and don't want to bother with LVGL's driver layer in the file paths. +It also helps to use a unified path with LVGL's file system and normal file systems. +The original mechanism is not affected, so a path starting with drive letter will still work. + +The **working directory** can be set with ``LV_FS_..._PATH``. E.g. ``"/home/joe/projects/"`` The actual file/directory paths will be -appended to it. +appended to it, allowing to skip the common part. + +Caching +""""""" :ref:`Cached reading ` is also supported if ``LV_FS_..._CACHE_SIZE`` is set to not ``0`` value. :cpp:func:`lv_fs_read` caches this size of data to lower the diff --git a/docs/libs/lfs.rst b/docs/libs/lfs.rst index 89234aaba..f7c9bef48 100644 --- a/docs/libs/lfs.rst +++ b/docs/libs/lfs.rst @@ -12,7 +12,7 @@ Detailed introduction: https://github.com/littlefs-project/littlefs Usage ----- -Enable :c:macro:`LV_USE_FS_LITTLEFS` and define a :c:macro`LV_FS_LITTLEFS_LETTER` in ``lv_conf.h``. +Enable :c:macro:`LV_USE_FS_LITTLEFS` and define a :c:macro:`LV_FS_LITTLEFS_LETTER` in ``lv_conf.h``. When enabled :c:macro:`lv_littlefs_set_handler` can be used to set up a mount point. diff --git a/docs/overview/fs.rst b/docs/overview/fs.rst index c470597d3..a54358085 100644 --- a/docs/overview/fs.rst +++ b/docs/overview/fs.rst @@ -9,6 +9,10 @@ any type of file system. A file system is identified by an assigned drive letter. For example, if an SD card is associated with the letter ``'S'``, a file can be reached using ``"S:path/to/file.txt"``. +.. note:: + + If you want to skip the drive prefix from the path, you can use the :c:macro:`LV_FS_DEFAULT_DRIVE_LETTER` config parameter. + Ready to use drivers ******************** diff --git a/docs/porting/display.rst b/docs/porting/display.rst index 82977eb30..2541ae239 100644 --- a/docs/porting/display.rst +++ b/docs/porting/display.rst @@ -160,7 +160,7 @@ are rendered directly in the frame buffer so they cannot be rotated later. Therefore in direct mode only the whole frame buffer can be rotated. The same is true for :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_FULL`. -In the case of :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL`the small rendered areas +In the case of :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` the small rendered areas can be rotated on their own before flushing to the frame buffer. Color format @@ -246,7 +246,7 @@ Force refreshing ---------------- Normally the invalidated areas (marked for redraw) are rendered in :cpp:func:`lv_timer_handler` in every -:cpp:macro:`LV_DEF_REFR_PERIOD`milliseconds. However, by using :cpp:func:`lv_refr_now(display)` you can ask LVGL to +:c:macro:`LV_DEF_REFR_PERIOD` milliseconds. However, by using :cpp:func:`lv_refr_now(display)` you can ask LVGL to redraw the invalid areas immediately. The refreshing will happen in :cpp:func:`lv_refr_now` which might take longer time. diff --git a/docs/porting/indev.rst b/docs/porting/indev.rst index beb038b82..82a8aef04 100644 --- a/docs/porting/indev.rst +++ b/docs/porting/indev.rst @@ -80,7 +80,7 @@ The rotary sensitivity can be adjusted on 2 levels: The final diff is calculated like this: -``diff_final = diff_in * (indev_sensitivity / 256) + (widget_sensitivity / 256); `` +``diff_final = diff_in * (indev_sensitivity / 256) + (widget_sensitivity / 256);`` For example, if both the indev and widget sensitivity is set to 128 (0.5), the input diff. will be multiplied by 0.25 (divided by 4). The value of the widget will be incremented by this value or diff --git a/docs/widgets/image.rst b/docs/widgets/image.rst index ab21867dd..4a38dcefa 100644 --- a/docs/widgets/image.rst +++ b/docs/widgets/image.rst @@ -41,7 +41,7 @@ To set the source of an image, use :cpp:expr:`lv_image_set_src(img, src)`. To generate a pixel array from a PNG, JPG or BMP image, use the `Online image converter tool `__ and set the converted image with its pointer :cpp:expr:`lv_image_set_src(img1, &converted_img_var)` To make the variable visible in the C file, you need to declare it with -:cpp:macro:`LV_IMAGE_DECLARE(converted_img_var)`. +:cpp:expr:`LV_IMAGE_DECLARE(converted_img_var)`. To use external files, you also need to convert the image files using the online converter tool but now you should select the binary output diff --git a/lv_conf_template.h b/lv_conf_template.h index 956e764fc..bef23926c 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -685,6 +685,9 @@ /*File system interfaces for common APIs */ +/*Setting a default driver letter allows skipping the driver prefix in filepaths*/ +#define LV_FS_DEFAULT_DRIVE_LETTER '\0' + /*API for fopen, fread, etc*/ #define LV_USE_FS_STDIO 0 #if LV_USE_FS_STDIO diff --git a/src/libs/fsdrv/lv_fs_arduino_esp_littlefs.cpp b/src/libs/fsdrv/lv_fs_arduino_esp_littlefs.cpp index 219ed73cb..cd8df4cf7 100644 --- a/src/libs/fsdrv/lv_fs_arduino_esp_littlefs.cpp +++ b/src/libs/fsdrv/lv_fs_arduino_esp_littlefs.cpp @@ -4,6 +4,19 @@ #include "../../core/lv_global.h" #include "LittleFS.h" +#if LV_FS_ARDUINO_ESP_LITTLEFS_LETTER == '\0' + #error "LV_FS_ARDUINO_ESP_LITTLEFS_LETTER must be set to a valid value" +#else + #if (LV_FS_ARDUINO_ESP_LITTLEFS_LETTER < 'A') || (LV_FS_ARDUINO_ESP_LITTLEFS_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_ARDUINO_ESP_LITTLEFS_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_ARDUINO_ESP_LITTLEFS_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif +#endif + typedef struct ArduinoEspLittleFile { File file; } ArduinoEspLittleFile; @@ -178,4 +191,11 @@ static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) return (int32_t)(*pos_p) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK; } +#else /*LV_USE_FS_ARDUINO_ESP_LITTLEFS == 0*/ + +#if defined(LV_FS_ARDUINO_ESP_LITTLEFS_LETTER) && LV_FS_ARDUINO_ESP_LITTLEFS_LETTER != '\0' + #warning "LV_USE_FS_ARDUINO_ESP_LITTLEFS is not enabled but LV_FS_ARDUINO_ESP_LITTLEFS_LETTER is set" #endif + +#endif /*LV_USE_FS_ARDUINO_ESP_LITTLEFS*/ + diff --git a/src/libs/fsdrv/lv_fs_arduino_sd.cpp b/src/libs/fsdrv/lv_fs_arduino_sd.cpp index 9d776fe71..c0706657f 100644 --- a/src/libs/fsdrv/lv_fs_arduino_sd.cpp +++ b/src/libs/fsdrv/lv_fs_arduino_sd.cpp @@ -5,6 +5,19 @@ #include #include "SD.h" +#if LV_FS_ARDUINO_SD_LETTER == '\0' + #error "LV_FS_ARDUINO_SD_LETTER must be set to a valid value" +#else + #if (LV_FS_ARDUINO_SD_LETTER < 'A') || (LV_FS_ARDUINO_SD_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_ARDUINO_SD_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_ARDUINO_SD_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif +#endif + typedef struct SdFile { File file; } SdFile; @@ -184,4 +197,10 @@ static lv_fs_res_t fs_tell(lv_fs_drv_t * drv, void * file_p, uint32_t * pos_p) return (int32_t)(*pos_p) < 0 ? LV_FS_RES_UNKNOWN : LV_FS_RES_OK; } +#else /*LV_USE_FS_ARDUINO_SD == 0*/ + +#if defined(LV_FS_ARDUINO_SD_LETTER) && LV_FS_ARDUINO_SD_LETTER != '\0' + #warning "LV_USE_FS_ARDUINO_SD is not enabled but LV_FS_ARDUINO_SD_LETTER is set" #endif + +#endif /*LV_USE_FS_ARDUINO_SD*/ diff --git a/src/libs/fsdrv/lv_fs_fatfs.c b/src/libs/fsdrv/lv_fs_fatfs.c index 579dc0fb2..79c62a367 100644 --- a/src/libs/fsdrv/lv_fs_fatfs.c +++ b/src/libs/fsdrv/lv_fs_fatfs.c @@ -21,7 +21,16 @@ #endif #if LV_FS_FATFS_LETTER == '\0' - #error "LV_FS_FATFS_LETTER must be an upper case ASCII letter" + #error "LV_FS_FATFS_LETTER must be set to a valid value" +#else + #if (LV_FS_FATFS_LETTER < 'A') || (LV_FS_FATFS_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_FATFS_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_FATFS_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif #endif /********************** diff --git a/src/libs/fsdrv/lv_fs_littlefs.c b/src/libs/fsdrv/lv_fs_littlefs.c index d6ad00310..490c6feeb 100644 --- a/src/libs/fsdrv/lv_fs_littlefs.c +++ b/src/libs/fsdrv/lv_fs_littlefs.c @@ -4,6 +4,19 @@ #include "lfs.h" #include "../../core/lv_global.h" +#if LV_FS_LITTLEFS_LETTER == '\0' + #error "LV_FS_LITTLEFS_LETTER must be set to a valid value" +#else + #if (LV_FS_LITTLEFS_LETTER < 'A') || (LV_FS_LITTLEFS_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_LITTLEFS_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_LITTLEFS_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif +#endif + typedef struct LittleFile { lfs_file_t file; } LittleFile; diff --git a/src/libs/fsdrv/lv_fs_memfs.c b/src/libs/fsdrv/lv_fs_memfs.c index 5b678f5a9..c207c76fd 100644 --- a/src/libs/fsdrv/lv_fs_memfs.c +++ b/src/libs/fsdrv/lv_fs_memfs.c @@ -47,6 +47,18 @@ /********************* * DEFINES *********************/ +#if LV_FS_MEMFS_LETTER == '\0' + #error "LV_FS_MEMFS_LETTER must be set to a valid value" +#else + #if (LV_FS_MEMFS_LETTER < 'A') || (LV_FS_MEMFS_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_MEMFS_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_MEMFS_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif +#endif /********************** * TYPEDEFS diff --git a/src/libs/fsdrv/lv_fs_posix.c b/src/libs/fsdrv/lv_fs_posix.c index 95269af24..f1e66fd23 100644 --- a/src/libs/fsdrv/lv_fs_posix.c +++ b/src/libs/fsdrv/lv_fs_posix.c @@ -23,7 +23,16 @@ *********************/ #if LV_FS_POSIX_LETTER == '\0' - #error "LV_FS_POSIX_LETTER must be an upper case ASCII letter" + #error "LV_FS_POSIX_LETTER must be set to a valid value" +#else + #if (LV_FS_POSIX_LETTER < 'A') || (LV_FS_POSIX_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_POSIX_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_POSIX_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif #endif /** The reason for 'fd + 1' is because open() may return a legal fd with a value of 0, diff --git a/src/libs/fsdrv/lv_fs_stdio.c b/src/libs/fsdrv/lv_fs_stdio.c index 1c3849aeb..a6c901e15 100644 --- a/src/libs/fsdrv/lv_fs_stdio.c +++ b/src/libs/fsdrv/lv_fs_stdio.c @@ -21,6 +21,19 @@ /********************* * DEFINES *********************/ +#if LV_FS_STDIO_LETTER == '\0' + #error "LV_FS_STDIO_LETTER must be set to a valid value" +#else + #if (LV_FS_STDIO_LETTER < 'A') || (LV_FS_STDIO_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_STDIO_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_STDIO_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif +#endif + #define MAX_PATH_LEN 256 /********************** diff --git a/src/libs/fsdrv/lv_fs_win32.c b/src/libs/fsdrv/lv_fs_win32.c index fd90f279f..d5fb36487 100644 --- a/src/libs/fsdrv/lv_fs_win32.c +++ b/src/libs/fsdrv/lv_fs_win32.c @@ -17,6 +17,19 @@ /********************* * DEFINES *********************/ +#if LV_FS_WIN32_LETTER == '\0' + #error "LV_FS_WIN32_LETTER must be set to a valid value" +#else + #if (LV_FS_WIN32_LETTER < 'A') || (LV_FS_WIN32_LETTER > 'Z') + #if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + #error "LV_FS_WIN32_LETTER must be an upper case ASCII letter" + #else /*Lean rules for backward compatibility*/ + #warning LV_FS_WIN32_LETTER should be an upper case ASCII letter. \ + Using a slash symbol as drive letter should be replaced with LV_FS_DEFAULT_DRIVE_LETTER mechanism + #endif + #endif +#endif + #define MAX_PATH_LEN 256 /********************** diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 1f950263d..8be76d0c9 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -2284,6 +2284,15 @@ /*File system interfaces for common APIs */ +/*Setting a default driver letter allows skipping the driver prefix in filepaths*/ +#ifndef LV_FS_DEFAULT_DRIVE_LETTER + #ifdef CONFIG_LV_FS_DEFAULT_DRIVE_LETTER + #define LV_FS_DEFAULT_DRIVE_LETTER CONFIG_LV_FS_DEFAULT_DRIVE_LETTER + #else + #define LV_FS_DEFAULT_DRIVE_LETTER '\0' + #endif +#endif + /*API for fopen, fread, etc*/ #ifndef LV_USE_FS_STDIO #ifdef CONFIG_LV_USE_FS_STDIO diff --git a/src/misc/lv_fs.c b/src/misc/lv_fs.c index 3c3a587eb..f71369880 100644 --- a/src/misc/lv_fs.c +++ b/src/misc/lv_fs.c @@ -17,16 +17,25 @@ /********************* * DEFINES *********************/ + +#if LV_FS_DEFAULT_DRIVE_LETTER != '\0' && (LV_FS_DEFAULT_DRIVE_LETTER < 'A' || 'Z' < LV_FS_DEFAULT_DRIVE_LETTER) + #error "When enabled, LV_FS_DEFAULT_DRIVE_LETTER needs to be a capital ASCII letter (A-Z)" +#endif + #define fsdrv_ll_p &(LV_GLOBAL_DEFAULT()->fsdrv_ll) /********************** * TYPEDEFS **********************/ +typedef struct { + char drive_letter; + const char * real_path; +} resolved_path_t; /********************** * STATIC PROTOTYPES **********************/ -static const char * lv_fs_get_real_path(const char * path); +static resolved_path_t lv_fs_resolve_path(const char * path); static lv_fs_res_t lv_fs_read_cached(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br); static lv_fs_res_t lv_fs_write_cached(lv_fs_file_t * file_p, const void * buf, uint32_t btw, uint32_t * bw); static lv_fs_res_t lv_fs_seek_cached(lv_fs_file_t * file_p, uint32_t pos, lv_fs_whence_t whence); @@ -71,8 +80,9 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo return LV_FS_RES_INV_PARAM; } - char letter = path[0]; - lv_fs_drv_t * drv = lv_fs_get_drv(letter); + resolved_path_t resolved_path = lv_fs_resolve_path(path); + + lv_fs_drv_t * drv = lv_fs_get_drv(resolved_path.drive_letter); if(drv == NULL) { LV_LOG_WARN("Can't open file (%s): unknown driver letter", path); @@ -100,8 +110,7 @@ lv_fs_res_t lv_fs_open(lv_fs_file_t * file_p, const char * path, lv_fs_mode_t mo file_p->file_d = file_p; } else { - const char * real_path = lv_fs_get_real_path(path); - void * file_d = drv->open_cb(drv, real_path, mode); + void * file_d = drv->open_cb(drv, resolved_path.real_path, mode); if(file_d == NULL || file_d == (void *)(-1)) { LV_PROFILER_END; return LV_FS_RES_UNKNOWN; @@ -297,8 +306,9 @@ lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path) { if(path == NULL) return LV_FS_RES_INV_PARAM; - char letter = path[0]; - lv_fs_drv_t * drv = lv_fs_get_drv(letter); + resolved_path_t resolved_path = lv_fs_resolve_path(path); + + lv_fs_drv_t * drv = lv_fs_get_drv(resolved_path.drive_letter); if(drv == NULL) { return LV_FS_RES_NOT_EX; @@ -316,8 +326,7 @@ lv_fs_res_t lv_fs_dir_open(lv_fs_dir_t * rddir_p, const char * path) LV_PROFILER_BEGIN; - const char * real_path = lv_fs_get_real_path(path); - void * dir_d = drv->dir_open_cb(drv, real_path); + void * dir_d = drv->dir_open_cb(drv, resolved_path.real_path); if(dir_d == NULL || dir_d == (void *)(-1)) { LV_PROFILER_END; @@ -494,16 +503,36 @@ const char * lv_fs_get_last(const char * path) **********************/ /** - * Skip the driver letter and the possible : after the letter + * Extract the drive letter and the real path from LVGL's "abstracted file system" path string * @param path path string (E.g. S:/folder/file.txt) - * @return pointer to the beginning of the real path (E.g. /folder/file.txt) */ -static const char * lv_fs_get_real_path(const char * path) +static resolved_path_t lv_fs_resolve_path(const char * path) { - path++; /*Ignore the driver letter*/ - if(*path == ':') path++; + resolved_path_t resolved; - return path; +#if LV_FS_DEFAULT_DRIVE_LETTER != '\0' /*When using default drive letter, strict format (X:) is mandatory*/ + bool has_drive_prefix = ('A' <= path[0]) && (path[0] <= 'Z') && (path[1] == ':'); + + if(has_drive_prefix) { + resolved.drive_letter = path[0]; + resolved.real_path = path + 2; + } + else { + resolved.drive_letter = LV_FS_DEFAULT_DRIVE_LETTER; + resolved.real_path = path; + } +# else /*Lean rules for backward compatibility*/ + resolved.drive_letter = path[0]; + + if(*path != '\0') { + path++; /*Ignore the driver letter*/ + if(*path == ':') path++; + } + + resolved.real_path = path; +#endif + + return resolved; } static lv_fs_res_t lv_fs_read_cached(lv_fs_file_t * file_p, void * buf, uint32_t btr, uint32_t * br)