exFAT microSD support

Signed-off-by: José Valdiviesso <zmiguel.alves@gmail.com>
This commit is contained in:
José Valdiviesso committed 2026-11-06 18:38:40 +01:00
1 parent 53d17d0b0f
commit c6ccb08d90
31 files changed
+25829 -19

No files matched your search

+1 -1
View File
@@ -20,7 +20,7 @@ pio device monitor -b 115200
## Quick MP3 test from SD
1. Use a FAT32 SD card and create these paths on it:
1. Use a FAT32 or exFAT SD card and create these paths on it:
```text
/Music/test.mp3
+1 -1
View File
@@ -119,7 +119,7 @@ USB) and the [GitHub releases](https://github.com/ALLFATHER-BV/wadamesh/releases
and [reference radio pin map](https://github.com/meshtastic/firmware/blob/master/variants/esp32s3/elecrow_panel/variant.h).
An optional external GPS can be connected to UART1 (CrowPanel RX GPIO18 /
TX GPIO17, 9600 baud). Data
can use a FAT32 microSD card for data, offline maps, File Manager and browser
can use a FAT32 or exFAT microSD card for data, offline maps, File Manager and browser
Transfer. The card uses software SPI (SCLK 5, MISO 4, MOSI 6, CS 7), leaving
the display and radio SPI hosts untouched; missing or unreadable cards fall
back to SPIFFS. The dedicated LittleFS partition remains the internal tile
+6
View File
@@ -64,6 +64,12 @@ minimp3 (bundled in lib/minimp3)
AsyncElegantOTA (vendored in arch/esp32/AsyncElegantOTA)
Copyright (c) Ayush Sharma — MIT License
ESP-IDF FatFs component (vendored in arch/esp32/fatfs_exfat, built with exFAT)
FatFs: Copyright (c) ChaN — FatFs license (BSD-style) — http://elm-chan.org/fsw/ff/
ESP-IDF glue: Copyright (c) Espressif Systems — Apache License 2.0
Copied unchanged from ESP-IDF v4.4.7 components/fatfs, except FF_FS_EXFAT and
FF_USE_LFN in src/ffconf.h.
TFT_eSPI (T-LoRa Pager display backend)
Copyright (c) Bodmer — MIT / FreeBSD License — https://github.com/Bodmer/TFT_eSPI
+1 -1
View File
@@ -430,7 +430,7 @@ truth — that's what our own `TLoraPagerBoard.cpp` already uses.
| IO expander | **XL9555** (addr `0x20`): DRV_EN ch0, AMP_EN ch1, KB_RST ch2, LORA_EN ch3, GPS_EN ch4, NFC_EN ch5, **DISP_RST ch6 — the ST7796 panel's hardware reset** (missing from BOTH the LilyGoLib doc's channel table and arduino-esp32 master's pins header; confirmed from LilyGoLib's `LilyGo_LoRa_Pager.cpp` begin(), which pulses it LOW→50ms→HIGH before display init — leaving it floating was M7's intermittent-black-screen root cause, see `TLORA_PAGER_M7_HW_DEBUG_LOG.md` session 2), GPS_RST ch7, KB_EN ch8, GPIO_EN ch9, SD_DET ch10, SD_PULLEN ch11, SD_EN ch12 |
| GPS | u-blox **MIA-M10Q**: TX 12, RX 4, PPS 13 |
| I²C bus | SDA 3, SCL 2 — shared by TCA8418 (`0x34`), XL9555 (`0x20`), BQ25896 (`0x6B`), BQ27220 (`0x55`), PCF85063 RTC (`0x51`), BHI260AP IMU (`0x28`), DRV2605 haptics (`0x5A`), ES8311 codec (`0x18`) |
| SD | microSD on the shared SPI bus, CS 21, card-detect via expander (ch10), max 32 GB, **FAT32 only** |
| SD | microSD on the shared SPI bus, CS 21, card-detect via expander (ch10), FAT32 or exFAT |
| Audio | ES8311 codec (I²C `0x18`; I2S MCLK 10, SCK/BCK 11, WS 18, SDOUT 45, SDIN 17 — confirmed against arduino-esp32's canonical `variants/lilygo_tlora_pager/pins_arduino.h`, matching LilyGoLib's own `codec.setPins(I2S_MCLK, I2S_SCK, I2S_WS, I2S_SDOUT, I2S_SDIN)` call in `LilyGo_LoRa_Pager.cpp`) driving an **NS4150B** 3 W Class-D amp (enabled via expander AMP_EN ch1, toggled at runtime around playback — not the boot-time permanently-on drive; see Decision below) |
| Misc | PCF85063A RTC (INT 1), BHI260AP IMU (INT 8), ST25R3916 NFC (unused — CS 39, INT 5, powered via expander NFC_EN ch5), USB VID/PID `0x303A:0x82D4` |
+93
View File
@@ -0,0 +1,93 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2016 */
/* ESP-IDF port Copyright 2016 Espressif Systems (Shanghai) PTE LTD */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#include "diskio_impl.h"
#include "ffconf.h"
#include "ff.h"
static ff_diskio_impl_t * s_impls[FF_VOLUMES] = { NULL };
#if FF_MULTI_PARTITION /* Multiple partition configuration */
PARTITION VolToPart[] = {
{0, 0}, /* Logical drive 0 ==> Physical drive 0, auto detection */
{1, 0} /* Logical drive 1 ==> Physical drive 1, auto detection */
};
#endif
esp_err_t ff_diskio_get_drive(BYTE* out_pdrv)
{
BYTE i;
for(i=0; i<FF_VOLUMES; i++) {
if (!s_impls[i]) {
*out_pdrv = i;
return ESP_OK;
}
}
return ESP_ERR_NOT_FOUND;
}
void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl)
{
assert(pdrv < FF_VOLUMES);
if (s_impls[pdrv]) {
ff_diskio_impl_t* im = s_impls[pdrv];
s_impls[pdrv] = NULL;
free(im);
}
if (!discio_impl) {
return;
}
ff_diskio_impl_t * impl = (ff_diskio_impl_t *)malloc(sizeof(ff_diskio_impl_t));
assert(impl != NULL);
memcpy(impl, discio_impl, sizeof(ff_diskio_impl_t));
s_impls[pdrv] = impl;
}
DSTATUS ff_disk_initialize (BYTE pdrv)
{
return s_impls[pdrv]->init(pdrv);
}
DSTATUS ff_disk_status (BYTE pdrv)
{
return s_impls[pdrv]->status(pdrv);
}
DRESULT ff_disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
return s_impls[pdrv]->read(pdrv, buff, sector, count);
}
DRESULT ff_disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
{
return s_impls[pdrv]->write(pdrv, buff, sector, count);
}
DRESULT ff_disk_ioctl (BYTE pdrv, BYTE cmd, void* buff)
{
return s_impls[pdrv]->ioctl(pdrv, cmd, buff);
}
DWORD get_fattime(void)
{
time_t t = time(NULL);
struct tm tmr;
localtime_r(&t, &tmr);
int year = tmr.tm_year < 80 ? 0 : tmr.tm_year - 80;
return ((DWORD)(year) << 25)
| ((DWORD)(tmr.tm_mon + 1) << 21)
| ((DWORD)tmr.tm_mday << 16)
| (WORD)(tmr.tm_hour << 11)
| (WORD)(tmr.tm_min << 5)
| (WORD)(tmr.tm_sec >> 1);
}
@@ -0,0 +1,72 @@
// Copyright 2017-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.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
typedef unsigned int UINT;
typedef unsigned char BYTE;
typedef uint32_t DWORD;
#define FF_DRV_NOT_USED 0xFF
#include "diskio.h"
#include "esp_err.h"
/**
* Structure of pointers to disk IO driver functions.
*
* See FatFs documentation for details about these functions
*/
typedef struct {
DSTATUS (*init) (unsigned char pdrv); /*!< disk initialization function */
DSTATUS (*status) (unsigned char pdrv); /*!< disk status check function */
DRESULT (*read) (unsigned char pdrv, unsigned char* buff, uint32_t sector, unsigned count); /*!< sector read function */
DRESULT (*write) (unsigned char pdrv, const unsigned char* buff, uint32_t sector, unsigned count); /*!< sector write function */
DRESULT (*ioctl) (unsigned char pdrv, unsigned char cmd, void* buff); /*!< function to get info about disk and do some misc operations */
} ff_diskio_impl_t;
/**
* Register or unregister diskio driver for given drive number.
*
* When FATFS library calls one of disk_xxx functions for driver number pdrv,
* corresponding function in discio_impl for given pdrv will be called.
*
* @param pdrv drive number
* @param discio_impl pointer to ff_diskio_impl_t structure with diskio functions
* or NULL to unregister and free previously registered drive
*/
void ff_diskio_register(BYTE pdrv, const ff_diskio_impl_t* discio_impl);
#define ff_diskio_unregister(pdrv_) ff_diskio_register(pdrv_, NULL)
/**
* Get next available drive number
*
* @param out_pdrv pointer to the byte to set if successful
*
* @return ESP_OK on success
* ESP_ERR_NOT_FOUND if all drives are attached
*/
esp_err_t ff_diskio_get_drive(BYTE* out_pdrv);
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,105 @@
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "diskio_impl.h"
#include "ffconf.h"
#include "ff.h"
#include "esp_log.h"
#include "diskio_rawflash.h"
#include "esp_compiler.h"
static const char* TAG = "diskio_rawflash";
const esp_partition_t* ff_raw_handles[FF_VOLUMES];
DSTATUS ff_raw_initialize (BYTE pdrv)
{
return 0;
}
DSTATUS ff_raw_status (BYTE pdrv)
{
return 0;
}
DRESULT ff_raw_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
ESP_LOGV(TAG, "ff_raw_read - pdrv=%i, sector=%i, count=%in", (unsigned int)pdrv, (unsigned int)sector, (unsigned int)count);
const esp_partition_t* part = ff_raw_handles[pdrv];
assert(part);
esp_err_t err = esp_partition_read(part, sector * SPI_FLASH_SEC_SIZE, buff, count * SPI_FLASH_SEC_SIZE);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "esp_partition_read failed (0x%x)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_raw_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
return RES_ERROR;
}
DRESULT ff_raw_ioctl (BYTE pdrv, BYTE cmd, void *buff)
{
const esp_partition_t* part = ff_raw_handles[pdrv];
ESP_LOGV(TAG, "ff_raw_ioctl: cmd=%in", cmd);
assert(part);
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD *) buff) = part->size / SPI_FLASH_SEC_SIZE;
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *) buff) = SPI_FLASH_SEC_SIZE;
return RES_OK;
case GET_BLOCK_SIZE:
return RES_ERROR;
}
return RES_ERROR;
}
esp_err_t ff_diskio_register_raw_partition(BYTE pdrv, const esp_partition_t* part_handle)
{
if (pdrv >= FF_VOLUMES) {
return ESP_ERR_INVALID_ARG;
}
static const ff_diskio_impl_t raw_impl = {
.init = &ff_raw_initialize,
.status = &ff_raw_status,
.read = &ff_raw_read,
.write = &ff_raw_write,
.ioctl = &ff_raw_ioctl
};
ff_diskio_register(pdrv, &raw_impl);
ff_raw_handles[pdrv] = part_handle;
return ESP_OK;
}
BYTE ff_diskio_get_pdrv_raw(const esp_partition_t* part_handle)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (part_handle == ff_raw_handles[i]) {
return i;
}
}
return 0xff;
}
@@ -0,0 +1,37 @@
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DISKIO_RAWFLASH_DEFINED
#define _DISKIO_RAWFLASH_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_partition.h"
/**
* Register spi flash partition
*
* @param pdrv drive number
* @param part_handle pointer to raw flash partition.
*/
esp_err_t ff_diskio_register_raw_partition(unsigned char pdrv, const esp_partition_t* part_handle);
unsigned char ff_diskio_get_pdrv_raw(const esp_partition_t* part_handle);
#ifdef __cplusplus
}
#endif
#endif // _DISKIO_RAWFLASH_DEFINED
@@ -0,0 +1,110 @@
/*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "diskio_impl.h"
#include "ffconf.h"
#include "ff.h"
#include "sdmmc_cmd.h"
#include "esp_log.h"
#include "esp_compiler.h"
static sdmmc_card_t* s_cards[FF_VOLUMES] = { NULL };
static const char* TAG = "diskio_sdmmc";
//Check if SD/MMC card is present
static DSTATUS ff_sdmmc_card_available(BYTE pdrv)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_get_status(card);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "Check status failed (0x%x)", err);
return STA_NOINIT;
}
return 0;
}
/**
* ff_sdmmc_status() and ff_sdmmc_initialize() return STA_NOINIT when sdmmc_get_status()
* fails. This error value is checked throughout the FATFS code.
* Both functions return 0 on success.
*/
DSTATUS ff_sdmmc_initialize (BYTE pdrv)
{
return ff_sdmmc_card_available(pdrv);
}
DSTATUS ff_sdmmc_status (BYTE pdrv)
{
return ff_sdmmc_card_available(pdrv);
}
DRESULT ff_sdmmc_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_read_sectors(card, buff, sector, count);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_read_blocks failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_sdmmc_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_write_sectors(card, buff, sector, count);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_write_blocks failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_sdmmc_ioctl (BYTE pdrv, BYTE cmd, void* buff)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
switch(cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD*) buff) = card->csd.capacity;
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD*) buff) = card->csd.sector_size;
return RES_OK;
case GET_BLOCK_SIZE:
return RES_ERROR;
}
return RES_ERROR;
}
void ff_diskio_register_sdmmc(BYTE pdrv, sdmmc_card_t* card)
{
static const ff_diskio_impl_t sdmmc_impl = {
.init = &ff_sdmmc_initialize,
.status = &ff_sdmmc_status,
.read = &ff_sdmmc_read,
.write = &ff_sdmmc_write,
.ioctl = &ff_sdmmc_ioctl
};
s_cards[pdrv] = card;
ff_diskio_register(pdrv, &sdmmc_impl);
}
BYTE ff_diskio_get_pdrv_card(const sdmmc_card_t* card)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (card == s_cards[i]) {
return i;
}
}
return 0xff;
}
@@ -0,0 +1,42 @@
// Copyright 2017-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.
#pragma once
#include "sdmmc_cmd.h"
#include "driver/sdmmc_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Register SD/MMC diskio driver
*
* @param pdrv drive number
* @param card pointer to sdmmc_card_t structure describing a card; card should be initialized before calling f_mount.
*/
void ff_diskio_register_sdmmc(unsigned char pdrv, sdmmc_card_t* card);
/**
* @brief Get the driver number corresponding to a card
*
* @param card The card to get its driver
* @return Driver number to the card
*/
BYTE ff_diskio_get_pdrv_card(const sdmmc_card_t* card);
#ifdef __cplusplus
}
#endif
+127
View File
@@ -0,0 +1,127 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "diskio_impl.h"
#include "ffconf.h"
#include "ff.h"
#include "esp_log.h"
#include "diskio_wl.h"
#include "wear_levelling.h"
#include "esp_compiler.h"
static const char* TAG = "ff_diskio_spiflash";
wl_handle_t ff_wl_handles[FF_VOLUMES] = {
WL_INVALID_HANDLE,
WL_INVALID_HANDLE,
};
DSTATUS ff_wl_initialize (BYTE pdrv)
{
return 0;
}
DSTATUS ff_wl_status (BYTE pdrv)
{
return 0;
}
DRESULT ff_wl_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count)
{
ESP_LOGV(TAG, "ff_wl_read - pdrv=%i, sector=%i, count=%i\n", (unsigned int)pdrv, (unsigned int)sector, (unsigned int)count);
wl_handle_t wl_handle = ff_wl_handles[pdrv];
assert(wl_handle + 1);
esp_err_t err = wl_read(wl_handle, sector * wl_sector_size(wl_handle), buff, count * wl_sector_size(wl_handle));
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "wl_read failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_wl_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count)
{
ESP_LOGV(TAG, "ff_wl_write - pdrv=%i, sector=%i, count=%i\n", (unsigned int)pdrv, (unsigned int)sector, (unsigned int)count);
wl_handle_t wl_handle = ff_wl_handles[pdrv];
assert(wl_handle + 1);
esp_err_t err = wl_erase_range(wl_handle, sector * wl_sector_size(wl_handle), count * wl_sector_size(wl_handle));
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "wl_erase_range failed (%d)", err);
return RES_ERROR;
}
err = wl_write(wl_handle, sector * wl_sector_size(wl_handle), buff, count * wl_sector_size(wl_handle));
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "wl_write failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_wl_ioctl (BYTE pdrv, BYTE cmd, void *buff)
{
wl_handle_t wl_handle = ff_wl_handles[pdrv];
ESP_LOGV(TAG, "ff_wl_ioctl: cmd=%i\n", cmd);
assert(wl_handle + 1);
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD *) buff) = wl_size(wl_handle) / wl_sector_size(wl_handle);
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *) buff) = wl_sector_size(wl_handle);
return RES_OK;
case GET_BLOCK_SIZE:
return RES_ERROR;
}
return RES_ERROR;
}
esp_err_t ff_diskio_register_wl_partition(BYTE pdrv, wl_handle_t flash_handle)
{
if (pdrv >= FF_VOLUMES) {
return ESP_ERR_INVALID_ARG;
}
static const ff_diskio_impl_t wl_impl = {
.init = &ff_wl_initialize,
.status = &ff_wl_status,
.read = &ff_wl_read,
.write = &ff_wl_write,
.ioctl = &ff_wl_ioctl
};
ff_wl_handles[pdrv] = flash_handle;
ff_diskio_register(pdrv, &wl_impl);
return ESP_OK;
}
BYTE ff_diskio_get_pdrv_wl(wl_handle_t flash_handle)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (flash_handle == ff_wl_handles[i]) {
return i;
}
}
return 0xff;
}
void ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (flash_handle == ff_wl_handles[i]) {
ff_wl_handles[i] = WL_INVALID_HANDLE;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DISKIO_WL_DEFINED
#define _DISKIO_WL_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#include "wear_levelling.h"
/**
* Register spi flash partition
*
* @param pdrv drive number
* @param flash_handle handle of the wear levelling partition.
*/
esp_err_t ff_diskio_register_wl_partition(unsigned char pdrv, wl_handle_t flash_handle);
unsigned char ff_diskio_get_pdrv_wl(wl_handle_t flash_handle);
void ff_diskio_clear_pdrv_wl(wl_handle_t flash_handle);
#ifdef __cplusplus
}
#endif
#endif // _DISKIO_WL_DEFINED
@@ -0,0 +1,108 @@
/*------------------------------------------------------------------------*/
/* Sample Code of OS Dependent Functions for FatFs */
/* (C)ChaN, 2017 */
/*------------------------------------------------------------------------*/
#include <string.h>
#include <stdlib.h>
#include "ff.h"
#include "sdkconfig.h"
#ifdef CONFIG_FATFS_ALLOC_PREFER_EXTRAM
#include "esp_heap_caps.h"
#endif
void* ff_memalloc ( /* Returns pointer to the allocated memory block (null on not enough core) */
unsigned msize /* Number of bytes to allocate */
)
{
#ifdef CONFIG_FATFS_ALLOC_PREFER_EXTRAM
return heap_caps_malloc_prefer(msize, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM,
MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL);
#else
return malloc(msize);
#endif
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free (nothing to do for null) */
)
{
free(mblock); /* Free the memory block with POSIX API */
}
#if FF_FS_REENTRANT /* Mutal exclusion */
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object for the volume, such as semaphore and mutex.
/ When a 0 is returned, the f_mount() function fails with FR_INT_ERR.
*/
int ff_cre_syncobj ( /* 1:Function succeeded, 0:Could not create the sync object */
BYTE vol, /* Corresponding volume (logical drive number) */
FF_SYNC_t *sobj /* Pointer to return the created sync object */
)
{
*sobj = xSemaphoreCreateMutex();
return (*sobj != NULL) ? 1 : 0;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj() function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* 1:Function succeeded, 0:Could not delete due to an error */
FF_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
vSemaphoreDelete(sobj);
return 1;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
FF_SYNC_t sobj /* Sync object to wait */
)
{
return (xSemaphoreTake(sobj, FF_FS_TIMEOUT) == pdTRUE) ? 1 : 0;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
FF_SYNC_t sobj /* Sync object to be signaled */
)
{
xSemaphoreGive(sobj);
}
#endif // FF_FS_REENTRANT
+77
View File
@@ -0,0 +1,77 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
#define ISDIO_READ 55 /* Read data form SD iSDIO register */
#define ISDIO_WRITE 56 /* Write data to SD iSDIO register */
#define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif
File diff suppressed because it is too large. Load diff
+405
View File
@@ -0,0 +1,405 @@
/*----------------------------------------------------------------------------/
/ FatFs - Generic FAT Filesystem module R0.13c /
/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2018, ChaN, all right reserved.
/
/ FatFs module is an open source software. Redistribution and use of FatFs in
/ source and binary forms, with or without modification, are permitted provided
/ that the following condition is met:
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/
/----------------------------------------------------------------------------*/
#ifndef FF_DEFINED
#define FF_DEFINED 86604 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "ffconf.h" /* FatFs configuration options */
#if FF_DEFINED != FFCONF_DEF
#error Wrong configuration file (ffconf.h).
#endif
/* Integer types used for FatFs API */
#if defined(_WIN32) /* Main development platform */
#define FF_INTDEF 2
#include <windows.h>
typedef unsigned __int64 QWORD;
#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__cplusplus) /* C99 or later */
#define FF_INTDEF 2
#include <stdint.h>
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef uint16_t WORD; /* 16-bit unsigned integer */
typedef uint16_t WCHAR; /* 16-bit unsigned integer */
typedef uint32_t DWORD; /* 32-bit unsigned integer */
typedef uint64_t QWORD; /* 64-bit unsigned integer */
#else /* Earlier than C99 */
#define FF_INTDEF 1
typedef unsigned int UINT; /* int must be 16-bit or 32-bit */
typedef unsigned char BYTE; /* char must be 8-bit */
typedef unsigned short WORD; /* 16-bit unsigned integer */
typedef unsigned short WCHAR; /* 16-bit unsigned integer */
typedef unsigned long DWORD; /* 32-bit unsigned integer */
#endif
/* Definitions of volume management */
#if FF_MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#endif
#if FF_STR_VOLUME_ID
#ifndef FF_VOLUME_STRS
extern const char* VolumeStr[FF_VOLUMES]; /* User defied volume ID */
#endif
#endif
/* Type of path name strings on FatFs API */
#ifndef _INC_TCHAR
#define _INC_TCHAR
#if FF_USE_LFN && FF_LFN_UNICODE == 1 /* Unicode in UTF-16 encoding */
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 2 /* Unicode in UTF-8 encoding */
typedef char TCHAR;
#define _T(x) u8 ## x
#define _TEXT(x) u8 ## x
#elif FF_USE_LFN && FF_LFN_UNICODE == 3 /* Unicode in UTF-32 encoding */
typedef DWORD TCHAR;
#define _T(x) U ## x
#define _TEXT(x) U ## x
#elif FF_USE_LFN && (FF_LFN_UNICODE < 0 || FF_LFN_UNICODE > 3)
#error Wrong FF_LFN_UNICODE setting
#else /* ANSI/OEM code in SBCS/DBCS */
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* Type of file size variables */
#if FF_FS_EXFAT
#if FF_INTDEF != 2
#error exFAT feature wants C99 or later
#endif
typedef QWORD FSIZE_t;
#else
typedef DWORD FSIZE_t;
#endif
/* Filesystem object structure (FATFS) */
typedef struct {
BYTE fs_type; /* Filesystem type (0:not mounted) */
BYTE pdrv; /* Associated physical drive */
BYTE n_fats; /* Number of FATs (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* Volume mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
WORD csize; /* Cluster size [sectors] */
#if FF_MAX_SS != FF_MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif
#if FF_USE_LFN
WCHAR* lfnbuf; /* LFN working buffer */
#endif
#if FF_FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer for exFAT */
#endif
#if FF_FS_REENTRANT
FF_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !FF_FS_READONLY
DWORD last_clst; /* Last allocated cluster */
DWORD free_clst; /* Number of free clusters */
#endif
#if FF_FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#if FF_FS_EXFAT
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
#endif
#endif
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
DWORD fsize; /* Size of an FAT [sectors] */
DWORD volbase; /* Volume base sector */
DWORD fatbase; /* FAT base sector */
DWORD dirbase; /* Root directory base sector/cluster */
DWORD database; /* Data base sector */
#if FF_FS_EXFAT
DWORD bitbase; /* Allocation bitmap base sector */
#endif
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[FF_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* Object ID and allocation information (FFOBJID) */
typedef struct {
FATFS* fs; /* Pointer to the hosting volume of this object */
WORD id; /* Hosting volume mount ID */
BYTE attr; /* Object attribute */
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous, =3:fragmented in this session, b2:sub-directory stretched) */
DWORD sclust; /* Object data start cluster (0:no cluster or root directory) */
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
#if FF_FS_EXFAT
DWORD n_cont; /* Size of first fragment - 1 (valid when stat == 3) */
DWORD n_frag; /* Size of last fragment needs to be written to FAT (valid when not zero) */
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
DWORD c_ofs; /* Offset in the containing directory (valid when file object and sclust != 0) */
#endif
#if FF_FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
} FFOBJID;
/* File object structure (FIL) */
typedef struct {
FFOBJID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
#if !FF_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry (not used at exFAT) */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] (not used at exFAT) */
#endif
#if FF_USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !FF_FS_TINY
BYTE buf[FF_MAX_SS]; /* File private data read/write window */
#endif
} FIL;
/* Directory object structure (FF_DIR) */
typedef struct {
FFOBJID obj; /* Object identifier */
DWORD dptr; /* Current read/write offset */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector (0:Read operation has terminated) */
BYTE* dir; /* Pointer to the directory item in the win[] */
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if FF_USE_LFN
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
#endif
#if FF_USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} FF_DIR;
/* File information structure (FILINFO) */
typedef struct {
FSIZE_t fsize; /* File size */
WORD fdate; /* Modified date */
WORD ftime; /* Modified time */
BYTE fattrib; /* File attribute */
#if FF_USE_LFN
TCHAR altname[FF_SFN_BUF + 1];/* Altenative file name */
TCHAR fname[FF_LFN_BUF + 1]; /* Primary file name */
#else
TCHAR fname[12 + 1]; /* File name */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
FRESULT f_truncate (FIL* fp); /* Truncate the file */
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
FRESULT f_opendir (FF_DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (FF_DIR* dp); /* Close an open directory */
FRESULT f_readdir (FF_DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (FF_DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (FF_DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t fsz, BYTE opt); /* Allocate a contiguous block to the file */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
FRESULT f_setcp (WORD cp); /* Set current code page */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->obj.objsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#define f_rmdir(path) f_unlink(path)
#define f_unmount(path) f_mount(0, path, 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !FF_FS_READONLY && !FF_FS_NORTC
DWORD get_fattime (void);
#endif
/* LFN support functions */
#if FF_USE_LFN >= 1 /* Code conversion (defined in unicode.c) */
WCHAR ff_oem2uni (WCHAR oem, WORD cp); /* OEM code to Unicode conversion */
WCHAR ff_uni2oem (DWORD uni, WORD cp); /* Unicode to OEM code conversion */
DWORD ff_wtoupper (DWORD uni); /* Unicode upper-case conversion */
#endif
#if FF_USE_LFN == 3 /* Dynamic memory allocation */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
/* Sync functions */
#if FF_FS_REENTRANT
int ff_cre_syncobj (BYTE vol, FF_SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (FF_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (FF_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (FF_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA_OPEN_APPEND 0x30
/* Fast seek controls (2nd argument of f_lseek) */
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
/* Format options (2nd argument of f_mkfs) */
#define FM_FAT 0x01
#define FM_FAT32 0x02
#define FM_EXFAT 0x04
#define FM_ANY 0x07
#define FM_SFD 0x08
/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
/* File attribute bits for directory entry (FILINFO.fattrib) */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#ifdef __cplusplus
}
#endif
#endif /* FF_DEFINED */
+323
View File
@@ -0,0 +1,323 @@
#include "sdkconfig.h"
/*---------------------------------------------------------------------------/
/ FatFs Functional Configurations
/---------------------------------------------------------------------------*/
#define FFCONF_DEF 86604 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define FF_FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: Basic functions are fully enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
/ are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define FF_USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define FF_USE_FIND 0
/* This option switches filtered directory read functions, f_findfirst() and
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
#define FF_USE_MKFS 1
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_USE_FASTSEEK CONFIG_FATFS_USE_FASTSEEK
/* This option switches fast seek function. (0:Disable or 1:Enable) */
#define FF_USE_EXPAND 0
/* This option switches f_expand function. (0:Disable or 1:Enable) */
#define FF_USE_CHMOD 1
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
/ (0:Disable or 1:Enable) Also FF_FS_READONLY needs to be 0 to enable this option. */
#define FF_USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define FF_USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define FF_CODE_PAGE CONFIG_FATFS_CODEPAGE
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect code page setting can cause a file open failure.
/
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 771 - KBL
/ 775 - Baltic
/ 850 - Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian
/ 869 - Greek 2
/ 932 - Japanese (DBCS)
/ 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese (DBCS)
/ 0 - Include all code pages above and configured by f_setcp()
*/
/* wadamesh: always the HEAP working buffer. The framework's sdkconfig picks the STACK
/ one, and with exFAT that buffer grows from 512 to 1120 bytes on the stack of every
/ task that touches a file. The heap one costs one PSRAM-preferred allocation per
/ call instead (ff_memalloc, CONFIG_FATFS_ALLOC_PREFER_EXTRAM). */
#define FF_USE_LFN 3
#ifdef CONFIG_FATFS_MAX_LFN
#define FF_MAX_LFN CONFIG_FATFS_MAX_LFN
#endif
/* The FF_USE_LFN switches the support for LFN (long file name).
/
/ 0: Disable LFN. FF_MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ To enable the LFN, ffunicode.c needs to be added to the project. The LFN function
/ requiers certain internal working buffer occupies (FF_MAX_LFN + 1) * 2 bytes and
/ additional (FF_MAX_LFN + 44) / 15 * 32 bytes when exFAT is enabled.
/ The FF_MAX_LFN defines size of the working buffer in UTF-16 code unit and it can
/ be in range of 12 to 255. It is recommended to be set 255 to fully support LFN
/ specification.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree() in ffsystem.c, need to be added to the project. */
#ifdef CONFIG_FATFS_API_ENCODING_UTF_8
#define FF_LFN_UNICODE 2
#elif defined(CONFIG_FATFS_API_ENCODING_UTF_16)
#define FF_LFN_UNICODE 1
#else /* CONFIG_FATFS_API_ENCODING_ANSI_OEM */
#define FF_LFN_UNICODE 0
#endif
/* This option switches the character encoding on the API when LFN is enabled.
/
/ 0: ANSI/OEM in current CP (TCHAR = char)
/ 1: Unicode in UTF-16 (TCHAR = WCHAR)
/ 2: Unicode in UTF-8 (TCHAR = char)
/ 3: Unicode in UTF-32 (TCHAR = DWORD)
/
/ Also behavior of string I/O functions will be affected by this option.
/ When LFN is not enabled, this option has no effect. */
#define FF_LFN_BUF 255
#define FF_SFN_BUF 12
/* This set of options defines size of file name members in the FILINFO structure
/ which is used to read out directory items. These values should be suffcient for
/ the file names to read. The maximum possible length of the read file name depends
/ on character encoding. When LFN is not enabled, these options have no effect. */
#define FF_STRF_ENCODE 3
/* When FF_LFN_UNICODE >= 1 with LFN enabled, string I/O functions, f_gets(),
/ f_putc(), f_puts and f_printf() convert the character encoding in it.
/ This option selects assumption of character encoding ON THE FILE to be
/ read/written via those functions.
/
/ 0: ANSI/OEM in current CP
/ 1: Unicode in UTF-16LE
/ 2: Unicode in UTF-16BE
/ 3: Unicode in UTF-8
*/
#define FF_FS_RPATH 0
/* This option configures support for relative path.
/
/ 0: Disable relative path and remove related functions.
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
*/
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define FF_VOLUMES 2
/* Number of volumes (logical drives) to be used. (1-10) */
#define FF_STR_VOLUME_ID 0
#define FF_VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings.
/ When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive
/ number in the path name. FF_VOLUME_STRS defines the volume ID strings for each
/ logical drives. Number of items must not be less than FF_VOLUMES. Valid
/ characters for the volume ID strings are A-Z, a-z and 0-9, however, they are
/ compared in case-insensitive. If FF_STR_VOLUME_ID >= 1 and FF_VOLUME_STRS is
/ not defined, a user defined volume string table needs to be defined as:
/
/ const char* VolumeStr[FF_VOLUMES] = {"ram","flash","sd","usb",...
*/
#define FF_MULTI_PARTITION 1
/* This option switches support for multiple volumes on the physical drive.
/ By default (0), each logical drive number is bound to the same physical drive
/ number and only an FAT volume found on the physical drive will be mounted.
/ When this function is enabled (1), each logical drive number can be bound to
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
/ funciton will be available. */
/* SD card sector size */
#define FF_SS_SDCARD 512
/* wear_levelling library sector size */
#define FF_SS_WL CONFIG_WL_SECTOR_SIZE
#define FF_MIN_SS MIN(FF_SS_SDCARD, FF_SS_WL)
#define FF_MAX_SS MAX(FF_SS_SDCARD, FF_SS_WL)
/* This set of options configures the range of sector size to be supported. (512,
/ 1024, 2048 or 4096) Always set both 512 for most systems, generic memory card and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When FF_MAX_SS is larger than FF_MIN_SS, FatFs is configured
/ for variable sector size mode and disk_ioctl() function needs to implement
/ GET_SECTOR_SIZE command. */
#define FF_USE_TRIM 0
/* This option switches support for ATA-TRIM. (0:Disable or 1:Enable)
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define FF_FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define FF_FS_TINY (!CONFIG_FATFS_PER_FILE_CACHE)
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of file object (FIL) is shrinked FF_MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the filesystem object (FATFS) is used for the file data transfer. */
#define FF_FS_EXFAT 1 /* wadamesh: the reason this copy exists (SDXC cards ship as exFAT) */
/* This option switches support for exFAT filesystem. (0:Disable or 1:Enable)
/ To enable exFAT, also LFN needs to be enabled. (FF_USE_LFN >= 1)
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
#define FF_FS_NORTC 0
#define FF_NORTC_MON 1
#define FF_NORTC_MDAY 1
#define FF_NORTC_YEAR 2018
/* The option FF_FS_NORTC switches timestamp functiton. If the system does not have
/ any RTC function or valid timestamp is not needed, set FF_FS_NORTC = 1 to disable
/ the timestamp function. Every object modified by FatFs will have a fixed timestamp
/ defined by FF_NORTC_MON, FF_NORTC_MDAY and FF_NORTC_YEAR in local time.
/ To enable timestamp function (FF_FS_NORTC = 0), get_fattime() function need to be
/ added to the project to read current time form real-time clock. FF_NORTC_MON,
/ FF_NORTC_MDAY and FF_NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (FF_FS_READONLY = 1). */
#define FF_FS_LOCK CONFIG_FATFS_FS_LOCK
/* The option FF_FS_LOCK switches file lock function to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when FF_FS_READONLY
/ is 1.
/
/ 0: Disable file lock function. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock function. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock control is independent of re-entrancy. */
#define FF_FS_REENTRANT 1
#define FF_FS_TIMEOUT (CONFIG_FATFS_TIMEOUT_MS / portTICK_PERIOD_MS)
#define FF_SYNC_t SemaphoreHandle_t
/* The option FF_FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this function.
/
/ 0: Disable re-entrancy. FF_FS_TIMEOUT and FF_SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The FF_FS_TIMEOUT defines timeout period in unit of time tick.
/ The FF_SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.h. */
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
/* Some memory allocation functions are declared here in addition to ff.h, so that
they can be used also by external code when LFN feature is disabled.
*/
void* ff_memalloc (unsigned msize);
void ff_memfree(void*);
/*--- End of configuration options ---*/
/* Redefine names of disk IO functions to prevent name collisions */
#define disk_initialize ff_disk_initialize
#define disk_status ff_disk_status
#define disk_read ff_disk_read
#define disk_write ff_disk_write
#define disk_ioctl ff_disk_ioctl
File diff suppressed because it is too large. Load diff
+295
View File
@@ -0,0 +1,295 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include <stddef.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "driver/sdmmc_types.h"
#include "driver/sdspi_host.h"
#include "ff.h"
#include "wear_levelling.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Register FATFS with VFS component
*
* This function registers given FAT drive in VFS, at the specified base path.
* If only one drive is used, fat_drive argument can be an empty string.
* Refer to FATFS library documentation on how to specify FAT drive.
* This function also allocates FATFS structure which should be used for f_mount
* call.
*
* @note This function doesn't mount the drive into FATFS, it just connects
* POSIX and C standard library IO function with FATFS. You need to mount
* desired drive into FATFS separately.
*
* @param base_path path prefix where FATFS should be registered
* @param fat_drive FATFS drive specification; if only one drive is used, can be an empty string
* @param max_files maximum number of files which can be open at the same time
* @param[out] out_fs pointer to FATFS structure which can be used for FATFS f_mount call is returned via this argument.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_register was already called
* - ESP_ERR_NO_MEM if not enough memory or too many VFSes already registered
*/
esp_err_t esp_vfs_fat_register(const char* base_path, const char* fat_drive,
size_t max_files, FATFS** out_fs);
/**
* @brief Un-register FATFS from VFS
*
* @note FATFS structure returned by esp_vfs_fat_register is destroyed after
* this call. Make sure to call f_mount function to unmount it before
* calling esp_vfs_fat_unregister_ctx.
* Difference between this function and the one above is that this one
* will release the correct drive, while the one above will release
* the last registered one
*
* @param base_path path prefix where FATFS is registered. This is the same
* used when esp_vfs_fat_register was called
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if FATFS is not registered in VFS
*/
esp_err_t esp_vfs_fat_unregister_path(const char* base_path);
/**
* @brief Configuration arguments for esp_vfs_fat_sdmmc_mount and esp_vfs_fat_spiflash_mount functions
*/
typedef struct {
/**
* If FAT partition can not be mounted, and this parameter is true,
* create partition table and format the filesystem.
*/
bool format_if_mount_failed;
int max_files; ///< Max number of open files
/**
* If format_if_mount_failed is set, and mount fails, format the card
* with given allocation unit size. Must be a power of 2, between sector
* size and 128 * sector size.
* For SD cards, sector size is always 512 bytes. For wear_levelling,
* sector size is determined by CONFIG_WL_SECTOR_SIZE option.
*
* Using larger allocation unit size will result in higher read/write
* performance and higher overhead when storing small files.
*
* Setting this field to 0 will result in allocation unit set to the
* sector size.
*/
size_t allocation_unit_size;
} esp_vfs_fat_mount_config_t;
// Compatibility definition
typedef esp_vfs_fat_mount_config_t esp_vfs_fat_sdmmc_mount_config_t;
/**
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
*
* This is an all-in-one function which does the following:
* - initializes SDMMC driver or SPI driver with configuration in host_config
* - initializes SD card with configuration in slot_config
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
* For real world applications, developers should implement the logic of
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
* with proper error checking and handling of exceptional conditions.
*
* @note Use this API to mount a card through SDSPI is deprecated. Please call
* `esp_vfs_fat_sdspi_mount()` instead for that case.
*
* @param base_path path where partition should be registered (e.g. "/sdcard")
* @param host_config Pointer to structure describing SDMMC host. When using
* SDMMC peripheral, this structure can be initialized using
* SDMMC_HOST_DEFAULT() macro. When using SPI peripheral,
* this structure can be initialized using SDSPI_HOST_DEFAULT()
* macro.
* @param slot_config Pointer to structure with slot configuration.
* For SDMMC peripheral, pass a pointer to sdmmc_slot_config_t
* structure initialized using SDMMC_SLOT_CONFIG_DEFAULT.
* (Deprecated) For SPI peripheral, pass a pointer to sdspi_slot_config_t
* structure initialized using SDSPI_SLOT_CONFIG_DEFAULT().
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] out_card if not NULL, pointer to the card information structure will be returned via this argument
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
*/
esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
const sdmmc_host_t* host_config,
const void* slot_config,
const esp_vfs_fat_mount_config_t* mount_config,
sdmmc_card_t** out_card);
/**
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
*
* This is an all-in-one function which does the following:
* - initializes an SPI Master device based on the SPI Master driver with configuration in
* slot_config, and attach it to an initialized SPI bus.
* - initializes SD card with configuration in host_config_input
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
* For real world applications, developers should implement the logic of
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
* with proper error checking and handling of exceptional conditions.
*
* @note This function try to attach the new SD SPI device to the bus specified in host_config.
* Make sure the SPI bus specified in `host_config->slot` have been initialized by
* `spi_bus_initialize()` before.
*
* @param base_path path where partition should be registered (e.g. "/sdcard")
* @param host_config_input Pointer to structure describing SDMMC host. This structure can be
* initialized using SDSPI_HOST_DEFAULT() macro.
* @param slot_config Pointer to structure with slot configuration.
* For SPI peripheral, pass a pointer to sdspi_device_config_t
* structure initialized using SDSPI_DEVICE_CONFIG_DEFAULT().
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] out_card If not NULL, pointer to the card information structure will be returned via
* this argument. It is suggested to hold this handle and use it to unmount the card later if
* needed. Otherwise it's not suggested to use more than one card at the same time and unmount one
* of them in your application.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
*/
esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path,
const sdmmc_host_t* host_config_input,
const sdspi_device_config_t* slot_config,
const esp_vfs_fat_mount_config_t* mount_config,
sdmmc_card_t** out_card);
/**
* @brief Unmount FAT filesystem and release resources acquired using esp_vfs_fat_sdmmc_mount
*
* @deprecated Use `esp_vfs_fat_sdcard_unmount()` instead.
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount hasn't been called
*/
esp_err_t esp_vfs_fat_sdmmc_unmount(void);
/**
* @brief Unmount an SD card from the FAT filesystem and release resources acquired using
* `esp_vfs_fat_sdmmc_mount()` or `esp_vfs_fat_sdspi_mount()`
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if the card argument is unregistered
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount hasn't been called
*/
esp_err_t esp_vfs_fat_sdcard_unmount(const char *base_path, sdmmc_card_t *card);
/**
* @brief Convenience function to initialize FAT filesystem in SPI flash and register it in VFS
*
* This is an all-in-one function which does the following:
*
* - finds the partition with defined partition_label. Partition label should be
* configured in the partition table.
* - initializes flash wear levelling library on top of the given partition
* - mounts FAT partition using FATFS library on top of flash wear levelling
* library
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
*
* @param base_path path where FATFS partition should be mounted (e.g. "/spiflash")
* @param partition_label label of the partition which should be used
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] wl_handle wear levelling driver handle
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_FOUND if the partition table does not contain FATFS partition with given label
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from wear levelling library, SPI flash driver, or FATFS drivers
*/
esp_err_t esp_vfs_fat_spiflash_mount(const char* base_path,
const char* partition_label,
const esp_vfs_fat_mount_config_t* mount_config,
wl_handle_t* wl_handle);
/**
* @brief Unmount FAT filesystem and release resources acquired using esp_vfs_fat_spiflash_mount
*
* @param base_path path where partition should be registered (e.g. "/spiflash")
* @param wl_handle wear levelling driver handle returned by esp_vfs_fat_spiflash_mount
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount hasn't been called
*/
esp_err_t esp_vfs_fat_spiflash_unmount(const char* base_path, wl_handle_t wl_handle);
/**
* @brief Convenience function to initialize read-only FAT filesystem and register it in VFS
*
* This is an all-in-one function which does the following:
*
* - finds the partition with defined partition_label. Partition label should be
* configured in the partition table.
* - mounts FAT partition using FATFS library
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* @note Wear levelling is not used when FAT is mounted in read-only mode using this function.
*
* @param base_path path where FATFS partition should be mounted (e.g. "/spiflash")
* @param partition_label label of the partition which should be used
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @return
* - ESP_OK on success
* - ESP_ERR_NOT_FOUND if the partition table does not contain FATFS partition with given label
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_rawflash_mount was already called for the same partition
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SPI flash driver, or FATFS drivers
*/
esp_err_t esp_vfs_fat_rawflash_mount(const char* base_path,
const char* partition_label,
const esp_vfs_fat_mount_config_t* mount_config);
/**
* @brief Unmount FAT filesystem and release resources acquired using esp_vfs_fat_rawflash_mount
*
* @param base_path path where partition should be registered (e.g. "/spiflash")
* @param partition_label label of partition to be unmounted
*
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_spiflash_mount hasn't been called
*/
esp_err_t esp_vfs_fat_rawflash_unmount(const char* base_path, const char* partition_label);
#ifdef __cplusplus
}
#endif
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,30 @@
// Copyright 2018 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.
#pragma once
#include "esp_vfs_fat.h"
#include <sys/param.h>
#include <stddef.h>
static inline size_t esp_vfs_fat_get_allocation_unit_size(
size_t sector_size, size_t requested_size)
{
size_t alloc_unit_size = requested_size;
const size_t max_sectors_per_cylinder = 128;
const size_t max_size = sector_size * max_sectors_per_cylinder;
alloc_unit_size = MAX(alloc_unit_size, sector_size);
alloc_unit_size = MIN(alloc_unit_size, max_size);
return alloc_unit_size;
}
+400
View File
@@ -0,0 +1,400 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "vfs_fat_internal.h"
#include "driver/sdspi_host.h"
#include "sdmmc_cmd.h"
#include "diskio_impl.h"
#include "diskio_sdmmc.h"
#include "soc/soc_caps.h"
#include "driver/sdmmc_defs.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
static const char* TAG = "vfs_fat_sdmmc";
static sdmmc_card_t* s_card = NULL;
static uint8_t s_pdrv = FF_DRV_NOT_USED;
static char * s_base_path = NULL;
#define CHECK_EXECUTE_RESULT(err, str) do { \
if ((err) !=ESP_OK) { \
ESP_LOGE(TAG, str" (0x%x).", err); \
goto cleanup; \
} \
} while(0)
static void call_host_deinit(const sdmmc_host_t *host_config);
static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config,
const char *drv, sdmmc_card_t *card, BYTE pdrv);
static esp_err_t mount_prepare_mem(const char *base_path,
BYTE *out_pdrv,
char **out_dup_path,
sdmmc_card_t** out_card)
{
esp_err_t err = ESP_OK;
char* dup_path = NULL;
sdmmc_card_t* card = NULL;
// connect SDMMC driver to FATFS
BYTE pdrv = FF_DRV_NOT_USED;
if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == FF_DRV_NOT_USED) {
ESP_LOGD(TAG, "the maximum count of volumes is already mounted");
return ESP_ERR_NO_MEM;
}
// not using ff_memalloc here, as allocation in internal RAM is preferred
card = (sdmmc_card_t*)malloc(sizeof(sdmmc_card_t));
if (card == NULL) {
ESP_LOGD(TAG, "could not locate new sdmmc_card_t");
err = ESP_ERR_NO_MEM;
goto cleanup;
}
dup_path = strdup(base_path);
if(!dup_path){
ESP_LOGD(TAG, "could not copy base_path");
err = ESP_ERR_NO_MEM;
goto cleanup;
}
*out_card = card;
*out_pdrv = pdrv;
*out_dup_path = dup_path;
return ESP_OK;
cleanup:
free(card);
free(dup_path);
return err;
}
static esp_err_t mount_to_vfs_fat(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv,
const char *base_path)
{
FATFS* fs = NULL;
esp_err_t err;
ff_diskio_register_sdmmc(pdrv, card);
ESP_LOGD(TAG, "using pdrv=%i", pdrv);
char drv[3] = {(char)('0' + pdrv), ':', 0};
// connect FATFS to VFS
err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
if (err == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (err != ESP_OK) {
ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", err);
goto fail;
}
// Try to mount partition
FRESULT res = f_mount(fs, drv, 1);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGW(TAG, "failed to mount card (%d)", res);
if (!((res == FR_NO_FILESYSTEM || res == FR_INT_ERR)
&& mount_config->format_if_mount_failed)) {
goto fail;
}
err = partition_card(mount_config, drv, card, pdrv);
if (err != ESP_OK) {
goto fail;
}
ESP_LOGW(TAG, "mounting again");
res = f_mount(fs, drv, 0);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res);
goto fail;
}
}
return ESP_OK;
fail:
if (fs) {
f_mount(NULL, drv, 0);
}
esp_vfs_fat_unregister_path(base_path);
ff_diskio_unregister(pdrv);
return err;
}
static esp_err_t partition_card(const esp_vfs_fat_mount_config_t *mount_config,
const char *drv, sdmmc_card_t *card, BYTE pdrv)
{
FRESULT res = FR_OK;
esp_err_t err;
const size_t workbuf_size = 4096;
void* workbuf = NULL;
ESP_LOGW(TAG, "partitioning card");
workbuf = ff_memalloc(workbuf_size);
if (workbuf == NULL) {
return ESP_ERR_NO_MEM;
}
DWORD plist[] = {100, 0, 0, 0};
res = f_fdisk(pdrv, plist, workbuf);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_fdisk failed (%d)", res);
goto fail;
}
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(
card->csd.sector_size,
mount_config->allocation_unit_size);
ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size);
res = f_mkfs(drv, FM_ANY, alloc_unit_size, workbuf, workbuf_size);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
goto fail;
}
free(workbuf);
return ESP_OK;
fail:
free(workbuf);
return err;
}
#if SOC_SDMMC_HOST_SUPPORTED
static esp_err_t init_sdmmc_host(int slot, const void *slot_config, int *out_slot)
{
*out_slot = slot;
return sdmmc_host_init_slot(slot, (const sdmmc_slot_config_t*) slot_config);
}
static esp_err_t init_sdspi_host_deprecated(int slot, const void *slot_config, int *out_slot)
{
*out_slot = slot;
return sdspi_host_init_slot(slot, (const sdspi_slot_config_t*) slot_config);
}
esp_err_t esp_vfs_fat_sdmmc_mount(const char* base_path,
const sdmmc_host_t* host_config,
const void* slot_config,
const esp_vfs_fat_mount_config_t* mount_config,
sdmmc_card_t** out_card)
{
esp_err_t err;
int card_handle = -1; //uninitialized
sdmmc_card_t* card = NULL;
BYTE pdrv = FF_DRV_NOT_USED;
char* dup_path = NULL;
bool host_inited = false;
err = mount_prepare_mem(base_path, &pdrv, &dup_path, &card);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount_prepare failed");
return err;
}
if (host_config->flags == SDMMC_HOST_FLAG_SPI) {
//Deprecated API
//the init() function is usually empty, doesn't require any deinit to revert it
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
err = init_sdspi_host_deprecated(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
//Set `host_inited` to true to indicate that host_config->deinit() needs
//to be called to revert `init_sdspi_host_deprecated`; set `card_handle`
//to -1 to indicate that no other deinit is required.
host_inited = true;
card_handle = -1;
} else {
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
//deinit() needs to be called to revert the init
host_inited = true;
//If this failed (indicated by card_handle != -1), slot deinit needs to called()
//leave card_handle as is to indicate that (though slot deinit not implemented yet.
err = init_sdmmc_host(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
}
// probe and initialize card
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
*out_card = card;
}
if (s_card == NULL) {
//store the ctx locally to be back-compatible
s_card = card;
s_pdrv = pdrv;
s_base_path = dup_path;
} else {
free(dup_path);
}
return ESP_OK;
cleanup:
if (host_inited) {
call_host_deinit(host_config);
}
free(card);
free(dup_path);
return err;
}
#endif
static esp_err_t init_sdspi_host(int slot, const void *slot_config, int *out_slot)
{
esp_err_t err = sdspi_host_init_device((const sdspi_device_config_t*)slot_config, out_slot);
if (err != ESP_OK) {
ESP_LOGE(TAG,
"Failed to attach sdspi device onto an SPI bus (rc=0x%x), please initialize the \
bus first and check the device parameters."
, err);
}
return err;
}
esp_err_t esp_vfs_fat_sdspi_mount(const char* base_path,
const sdmmc_host_t* host_config_input,
const sdspi_device_config_t* slot_config,
const esp_vfs_fat_mount_config_t* mount_config,
sdmmc_card_t** out_card)
{
const sdmmc_host_t* host_config = host_config_input;
esp_err_t err;
int card_handle = -1; //uninitialized
bool host_inited = false;
BYTE pdrv = FF_DRV_NOT_USED;
sdmmc_card_t* card = NULL;
char* dup_path = NULL;
err = mount_prepare_mem(base_path, &pdrv, &dup_path, &card);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount_prepare failed");
return err;
}
//the init() function is usually empty, doesn't require any deinit to revert it
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
err = init_sdspi_host(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
//Set `host_inited` to true to indicate that host_config->deinit() needs
//to be called to revert `init_sdspi_host`
host_inited = true;
/*
* The `slot` argument inside host_config should be replaced by the SD SPI handled returned
* above. But the input pointer is const, so create a new variable.
*/
sdmmc_host_t new_config;
if (card_handle != host_config->slot) {
new_config = *host_config_input;
host_config = &new_config;
new_config.slot = card_handle;
}
// probe and initialize card
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
err = mount_to_vfs_fat(mount_config, card, pdrv, dup_path);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
*out_card = card;
}
if (s_card == NULL) {
//store the ctx locally to be back-compatible
s_card = card;
s_pdrv = pdrv;
s_base_path = dup_path;
} else {
free(dup_path);
}
return ESP_OK;
cleanup:
if (host_inited) {
call_host_deinit(host_config);
}
free(card);
free(dup_path);
return err;
}
static void local_card_remove(void)
{
s_card = NULL;
free(s_base_path);
s_base_path = NULL;
s_pdrv = FF_DRV_NOT_USED;
}
static void call_host_deinit(const sdmmc_host_t *host_config)
{
if (host_config->flags & SDMMC_HOST_FLAG_DEINIT_ARG) {
host_config->deinit_p(host_config->slot);
} else {
host_config->deinit();
}
}
static esp_err_t unmount_card_core(const char *base_path, sdmmc_card_t *card)
{
BYTE pdrv = ff_diskio_get_pdrv_card(card);
if (pdrv == 0xff) {
return ESP_ERR_INVALID_ARG;
}
// unmount
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
// release SD driver
ff_diskio_unregister(pdrv);
call_host_deinit(&card->host);
free(card);
esp_err_t err = esp_vfs_fat_unregister_path(base_path);
return err;
}
esp_err_t esp_vfs_fat_sdmmc_unmount(void)
{
sdmmc_card_t* card = s_card;
esp_err_t err = unmount_card_core(s_base_path, card);
local_card_remove();
return err;
}
esp_err_t esp_vfs_fat_sdcard_unmount(const char *base_path, sdmmc_card_t *card)
{
esp_err_t err = unmount_card_core(base_path, card);
if (s_card == card) {
local_card_remove();
}
return err;
}
@@ -0,0 +1,209 @@
// Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <string.h>
#include "esp_log.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "vfs_fat_internal.h"
#include "diskio_impl.h"
#include "diskio_rawflash.h"
#include "wear_levelling.h"
#include "diskio_wl.h"
static const char *TAG = "vfs_fat_spiflash";
esp_err_t esp_vfs_fat_spiflash_mount(const char* base_path,
const char* partition_label,
const esp_vfs_fat_mount_config_t* mount_config,
wl_handle_t* wl_handle)
{
esp_err_t result = ESP_OK;
const size_t workbuf_size = 4096;
void *workbuf = NULL;
esp_partition_subtype_t subtype = partition_label ?
ESP_PARTITION_SUBTYPE_ANY : ESP_PARTITION_SUBTYPE_DATA_FAT;
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
subtype, partition_label);
if (data_partition == NULL) {
ESP_LOGE(TAG, "Failed to find FATFS partition (type='data', subtype='fat', partition_label='%s'). Check the partition table.", partition_label);
return ESP_ERR_NOT_FOUND;
}
result = wl_mount(data_partition, wl_handle);
if (result != ESP_OK) {
ESP_LOGE(TAG, "failed to mount wear levelling layer. result = %i", result);
return result;
}
// connect driver to FATFS
BYTE pdrv = 0xFF;
if (ff_diskio_get_drive(&pdrv) != ESP_OK) {
ESP_LOGD(TAG, "the maximum count of volumes is already mounted");
return ESP_ERR_NO_MEM;
}
ESP_LOGD(TAG, "using pdrv=%i", pdrv);
char drv[3] = {(char)('0' + pdrv), ':', 0};
result = ff_diskio_register_wl_partition(pdrv, *wl_handle);
if (result != ESP_OK) {
ESP_LOGE(TAG, "ff_diskio_register_wl_partition failed pdrv=%i, error - 0x(%x)", pdrv, result);
goto fail;
}
FATFS *fs;
result = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
if (result == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (result != ESP_OK) {
ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", result);
goto fail;
}
// Try to mount partition
FRESULT fresult = f_mount(fs, drv, 1);
if (fresult != FR_OK) {
ESP_LOGW(TAG, "f_mount failed (%d)", fresult);
if (!((fresult == FR_NO_FILESYSTEM || fresult == FR_INT_ERR)
&& mount_config->format_if_mount_failed)) {
result = ESP_FAIL;
goto fail;
}
workbuf = ff_memalloc(workbuf_size);
if (workbuf == NULL) {
result = ESP_ERR_NO_MEM;
goto fail;
}
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(
CONFIG_WL_SECTOR_SIZE,
mount_config->allocation_unit_size);
ESP_LOGI(TAG, "Formatting FATFS partition, allocation unit size=%d", alloc_unit_size);
fresult = f_mkfs(drv, FM_ANY | FM_SFD, alloc_unit_size, workbuf, workbuf_size);
if (fresult != FR_OK) {
result = ESP_FAIL;
ESP_LOGE(TAG, "f_mkfs failed (%d)", fresult);
goto fail;
}
free(workbuf);
workbuf = NULL;
ESP_LOGI(TAG, "Mounting again");
fresult = f_mount(fs, drv, 0);
if (fresult != FR_OK) {
result = ESP_FAIL;
ESP_LOGE(TAG, "f_mount failed after formatting (%d)", fresult);
goto fail;
}
}
return ESP_OK;
fail:
free(workbuf);
esp_vfs_fat_unregister_path(base_path);
ff_diskio_unregister(pdrv);
return result;
}
esp_err_t esp_vfs_fat_spiflash_unmount(const char *base_path, wl_handle_t wl_handle)
{
BYTE pdrv = ff_diskio_get_pdrv_wl(wl_handle);
if (pdrv == 0xff) {
return ESP_ERR_INVALID_STATE;
}
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
ff_diskio_unregister(pdrv);
ff_diskio_clear_pdrv_wl(wl_handle);
// release partition driver
esp_err_t err_drv = wl_unmount(wl_handle);
esp_err_t err = esp_vfs_fat_unregister_path(base_path);
if (err == ESP_OK) err = err_drv;
return err;
}
esp_err_t esp_vfs_fat_rawflash_mount(const char* base_path,
const char* partition_label,
const esp_vfs_fat_mount_config_t* mount_config)
{
esp_err_t result = ESP_OK;
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_FAT, partition_label);
if (data_partition == NULL) {
ESP_LOGE(TAG, "Failed to find FATFS partition (type='data', subtype='fat', partition_label='%s'). Check the partition table.", partition_label);
return ESP_ERR_NOT_FOUND;
}
// connect driver to FATFS
BYTE pdrv = 0xFF;
if (ff_diskio_get_drive(&pdrv) != ESP_OK) {
ESP_LOGD(TAG, "the maximum count of volumes is already mounted");
return ESP_ERR_NO_MEM;
}
ESP_LOGD(TAG, "using pdrv=%i", pdrv);
char drv[3] = {(char)('0' + pdrv), ':', 0};
result = ff_diskio_register_raw_partition(pdrv, data_partition);
if (result != ESP_OK) {
ESP_LOGE(TAG, "ff_diskio_register_raw_partition failed pdrv=%i, error - 0x(%x)", pdrv, result);
goto fail;
}
FATFS *fs;
result = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
if (result == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (result != ESP_OK) {
ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", result);
goto fail;
}
// Try to mount partition
FRESULT fresult = f_mount(fs, drv, 1);
if (fresult != FR_OK) {
ESP_LOGW(TAG, "f_mount failed (%d)", fresult);
result = ESP_FAIL;
goto fail;
}
return ESP_OK;
fail:
esp_vfs_fat_unregister_path(base_path);
ff_diskio_unregister(pdrv);
return result;
}
esp_err_t esp_vfs_fat_rawflash_unmount(const char *base_path, const char* partition_label)
{
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_FAT, partition_label);
if (data_partition == NULL) {
ESP_LOGE(TAG, "Failed to find FATFS partition (type='data', subtype='fat', partition_label='%s'). Check the partition table.", partition_label);
return ESP_ERR_NOT_FOUND;
}
BYTE pdrv = ff_diskio_get_pdrv_raw(data_partition);
if (pdrv == 0xff) {
return ESP_ERR_INVALID_STATE;
}
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
ff_diskio_unregister(pdrv);
esp_err_t err = esp_vfs_fat_unregister_path(base_path);
return err;
}
+3
View File
@@ -67,6 +67,9 @@ fi
unset VIRTUAL_ENV CONDA_PREFIX
# shellcheck disable=SC1091
source esp-idf/export.sh >/dev/null 2>&1
# exFAT microSD cards (all SDXC, 64 GB and up). IDF hard-codes it off; idempotent, fails on drift.
python3 "$(cd .. && pwd)/scripts/build/patch_idf_fatfs_exfat.py" \
--patch-file "$IDF_PATH/components/fatfs/src/ffconf.h"
WADA_FW_TAG="${WADA_FW_TAG:-$(git describe --tags --match 'beta_*' --always 2>/dev/null || echo dev)}"
WADA_FW_DATE="$(date '+%-d %b %Y')"
+13 -13
View File
@@ -17,7 +17,7 @@ framework = arduino
board = heltec_v4
monitor_speed = 115200
board_build.partitions = partitions_tft_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
; perf_lvgl.py is here for the V4-R8, which extends this env; the V4 itself sets no options
; (no flash left for -O2, no internal RAM for IRAM), so its LVGL builds exactly as before.
@@ -349,7 +349,7 @@ framework = arduino
board = attaky_mesh_series
monitor_speed = 115200
board_build.partitions = partitions_tft_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM, paid by the band in PSRAM
@@ -538,7 +538,7 @@ framework = arduino
board = t-deck
monitor_speed = 115200
board_build.partitions = variants/lilygo_tdeck/partitions_tdeck_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py): ~5% less time a frame, ~39 KB flash
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM: ~8% less a frame, ~6 KB internal RAM
@@ -727,7 +727,7 @@ board_build.flash_size = 16MB
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = variants/lilygo_tdeck/partitions_tdeck_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, merge-bin.py
build_unflags =
-std=gnu++11
@@ -964,7 +964,7 @@ board_build.flash_size = 16MB
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = variants/lilygo_tdeck/partitions_tdeck_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, merge-bin.py
build_unflags =
-std=gnu++11
@@ -1173,7 +1173,7 @@ board_build.flash_size = 16MB
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = partitions_tft_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_lgfx_dmadesc.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_lgfx_dmadesc.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM, paid by the band in PSRAM
@@ -1348,7 +1348,7 @@ board_build.flash_size = 16MB
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = partitions_tft_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_lgfx_dmadesc.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_lgfx_dmadesc.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM, paid by the band in PSRAM
@@ -1503,7 +1503,7 @@ board_build.flash_size = 16MB
board_upload.flash_size = 16MB
board_upload.maximum_size = 16777216
board_build.partitions = partitions_tft_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_lgfx_dmadesc.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_lgfx_dmadesc.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM
@@ -1661,7 +1661,7 @@ board_build.flash_size = 8MB
board_upload.flash_size = 8MB
board_upload.maximum_size = 8388608
board_build.partitions = variants/sensecap_indicator/partitions_sensecap_indicator.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
; No custom_lvgl_iram: it costs +5.9 KB IRAM, and with this board's 23 KB internal draw
; band (see UITask::begin) that would leave less internal heap than the T-Deck's.
@@ -1809,7 +1809,7 @@ framework = arduino
board = lilygo-t-lora-pager
monitor_speed = 115200
board_build.partitions = variants/lilygo_tlora_pager/partitions_tlora_pager_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/patch_nimble_freertos_timer.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/patch_nimble_freertos_timer.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py): measured 5-12% less a frame on the Pager
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM (~7 KB internal RAM with -O2), paid by the band in PSRAM
@@ -2045,7 +2045,7 @@ framework = arduino
board = lilygo-t-lora-pager
monitor_speed = 115200
board_build.partitions = variants/lilygo_tlora_pager/partitions_tlora_pager_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/patch_nimble_freertos_timer.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/patch_nimble_freertos_timer.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py): measured 5-12% less a frame on the Pager
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM (~7 KB internal RAM with -O2), paid by the band in PSRAM
@@ -2270,7 +2270,7 @@ board_build.partitions = variants/thinknode_m9/partitions_m9_touch.csv
; DriveDiosInSleepMode (0x012A, FW 0x0308+) with CMD_PERR -> begin() = -706.
; The pre-script makes RadioLib's config() skip it on old FW (idempotent,
; per-env libdeps copy). See scripts/build/patch_radiolib_lr11x0.py.
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/patch_radiolib_lr11x0.py, pre:scripts/build/patch_meshcore_rv3028_define.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/patch_radiolib_lr11x0.py, pre:scripts/build/patch_meshcore_rv3028_define.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM, paid by the band in PSRAM
@@ -2540,7 +2540,7 @@ board = rak_tap_v2
monitor_speed = 115200
board_build.flash_mode = dio ; RAK3312 requires DIO (board JSON defaults to qio)
board_build.partitions = variants/rak_tap_v2/partitions_rak_tap_v2_touch.csv
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
extra_scripts = pre:scripts/build/pre_gen_baked.py, pre:scripts/inject_wifi_env.py, pre:scripts/build/fatfs_exfat.py, pre:scripts/build/patch_lvgl_anim_uaf.py, pre:scripts/build/patch_lvgl_arabic.py, pre:scripts/build/patch_meshcore_txt_timestamp.py, pre:scripts/build/perf_lvgl.py, merge-bin.py
custom_lvgl_o2 = yes ; LVGL at -O2 (scripts/build/perf_lvgl.py), like the T-Deck
custom_lvgl_iram = lv_draw_sw_blend.c, lv_draw_label.c ; their hot loops in IRAM, paid by the band in PSRAM
+27
View File
@@ -0,0 +1,27 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# PlatformIO pre-script: build FatFs with exFAT for the Arduino-ESP32 boards.
#
# Arduino-ESP32 2.0.17 links a precompiled libfatfs.a (ESP-IDF v4.4.7) built with
# FF_FS_EXFAT=0, so every SDXC card (64 GB and up ships as exFAT) failed to mount.
# arch/esp32/fatfs_exfat is that same component, copied unchanged from ESP-IDF
# v4.4.7 (components/fatfs: diskio/, port/freertos/, src/, vfs/; the framework's
# headers are byte-identical to it), except for two lines in src/ffconf.h:
# FF_FS_EXFAT=1 and the heap LFN buffer (see the comment there).
#
# - Its objects go straight into the program, so the linker resolves every f_*,
# ff_* and esp_vfs_fat_* symbol from them and never pulls a member of
# libfatfs.a. Object files are not archive members: there is no duplicate.
# - exFAT changes the layout of FATFS, FIL and FILINFO. Every translation unit
# that includes ff.h (the Arduino SD, SD_MMC and FFat libraries, sd_diskio,
# CrowPanel35SD, UsbFilesSession) must see this ffconf.h, not the framework's.
# A pre-script runs before the framework adds its include paths, so the ones
# prepended here come first, and every library builder clones this env.
import os
Import("env") # noqa: F821 - provided by PlatformIO/SCons
ROOT = os.path.join(env.subst("$PROJECT_DIR"), "arch", "esp32", "fatfs_exfat") # noqa: F821
env.Prepend(CPPPATH=[os.path.join(ROOT, d) for d in ("src", "vfs", "diskio")]) # noqa: F821
env.BuildSources(os.path.join("$BUILD_DIR", "fatfs_exfat"), ROOT) # noqa: F821
+48
View File
@@ -0,0 +1,48 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# ESP-IDF hard-codes FF_FS_EXFAT 0 in components/fatfs/src/ffconf.h (there is no
# Kconfig option for it), so SD_MMC could not mount exFAT cards, which is how
# every SDXC card (64 GB and up) ships. The IDF builds (Tanmatsu, T-Display P4,
# CrowPanel P4) all compile FatFs from that tree, so they switch it on here. IDF's
# own vfs_fat.c already handles FF_FS_EXFAT; LFN, which exFAT requires, is on in
# tanmatsu/sdkconfigs/general (CONFIG_FATFS_LFN_HEAP), shared by all three.
#
# The PlatformIO boards link a precompiled FatFs instead; scripts/build/fatfs_exfat.py
# covers them.
#
# Idempotent and fail-closed, like patch_lvgl_anim_uaf.py:
# python3 patch_idf_fatfs_exfat.py --patch-file "$IDF_PATH/components/fatfs/src/ffconf.h"
import sys
OLD = "#define FF_FS_EXFAT\t\t0"
NEW = "#define FF_FS_EXFAT\t\t1\t/* wadamesh: exFAT microSD (scripts/build/patch_idf_fatfs_exfat.py) */"
def patch_source(source):
if source.count(OLD) == 0 and source.count(NEW) == 1:
return source, False
if source.count(OLD) != 1 or source.count(NEW) != 0:
raise RuntimeError("ffconf.h FF_FS_EXFAT line does not match ESP-IDF 5.5 (IDF version drift?)")
return source.replace(OLD, NEW, 1), True
def patch_file(path):
with open(path, encoding="utf-8", newline="") as source_file:
source = source_file.read()
patched, changed = patch_source(source)
if changed:
with open(path, "w", encoding="utf-8", newline="") as source_file:
source_file.write(patched)
return changed
if __name__ == "__main__":
if len(sys.argv) != 3 or sys.argv[1] != "--patch-file":
raise SystemExit("usage: patch_idf_fatfs_exfat.py --patch-file PATH")
try:
changed = patch_file(sys.argv[2])
except (OSError, RuntimeError) as error:
print("patch_idf_fatfs_exfat: ERROR: %s" % error, file=sys.stderr)
raise SystemExit(1)
print("patch_idf_fatfs_exfat: %s" % ("patched" if changed else "already patched"))
+2 -2
View File
@@ -13,8 +13,8 @@ tool fills a card for it:
- A .txt or .md file is copied to /library/ as it is: the Reader pages through it.
- /home.htm is (re)written to list everything in /library, so the Reader opens on it.
Only the Python standard library. The card must be FAT32 (the firmware does not
read exFAT). Pages stay well under the Reader's limits (it reads up to 48 KB of a
Only the Python standard library. The card must be FAT32 or exFAT (FAT16 works
too). Pages stay well under the Reader's limits (it reads up to 48 KB of a
page on the smallest boards and shows up to 280 links).
"""
import html, os, posixpath, re, shutil, sys, zipfile
+1 -1
View File
@@ -27953,7 +27953,7 @@ static void fmSdDoFormat() {
s_sd_format_pending = 2;
}
// Tap on an unmounted SD row: try to mount, and if the card is unreadable
// (e.g. exFAT, which this build can't read — only FAT16/FAT32) offer to format.
// (no FAT16/FAT32/exFAT volume, or a corrupt one) offer to format.
static void fmSdMountOrFormatCb(lv_event_t* e) {
if (lv_event_get_code(e) != LV_EVENT_CLICKED) return;
s_sd_retry_after_ms = 0; // explicit user retry — bypass the mount backoff
+3
View File
@@ -31,6 +31,9 @@ fi
unset VIRTUAL_ENV CONDA_PREFIX
# shellcheck disable=SC1091
source esp-idf/export.sh >/dev/null 2>&1
# exFAT microSD cards (all SDXC, 64 GB and up). IDF hard-codes it off; idempotent, fails on drift.
python3 "$(cd .. && pwd)/scripts/build/patch_idf_fatfs_exfat.py" \
--patch-file "$IDF_PATH/components/fatfs/src/ffconf.h"
# Firmware tag shown on About + used by the update check. Derived from git so dev
# builds are honest ("beta_28-14-gabc123" = 14 commits past beta_28) and a release
+3
View File
@@ -77,6 +77,9 @@ fi
unset VIRTUAL_ENV CONDA_PREFIX
# shellcheck disable=SC1091
source esp-idf/export.sh >/dev/null 2>&1
# exFAT microSD cards (all SDXC, 64 GB and up). IDF hard-codes it off; idempotent, fails on drift.
python3 "$(cd .. && pwd)/scripts/build/patch_idf_fatfs_exfat.py" \
--patch-file "$IDF_PATH/components/fatfs/src/ffconf.h"
WADA_FW_TAG="${WADA_FW_TAG:-$(git describe --tags --match 'beta_*' --always 2>/dev/null || echo dev)}"
WADA_FW_DATE="$(date '+%-d %b %Y')"