mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-11-12 15:27:47 +00:00
exFAT microSD support
Signed-off-by: José Valdiviesso <zmiguel.alves@gmail.com>
This commit is contained in:
1 parent
53d17d0b0f
commit
c6ccb08d90
31 files changed
+25829
-19
No files matched your search
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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` |
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
@@ -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 */
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')"
|
||||
|
||||
Reference in new issue
Block a user