firmware/src/FSCommon.cpp

342 lines
9.2 KiB
C++
Raw Normal View History

2023-07-26 23:34:36 +00:00
/**
* @file FSCommon.cpp
2023-07-27 00:08:04 +00:00
* @brief This file contains functions for common filesystem operations such as copying, renaming, listing and deleting files and
* directories.
*
* The functions in this file are used to perform common filesystem operations such as copying, renaming, listing and deleting
* files and directories. These functions are used in the Meshtastic-device project to manage files and directories on the
* device's filesystem.
*
2023-07-26 23:34:36 +00:00
*/
#include "FSCommon.h"
2023-01-21 13:34:29 +00:00
#include "configuration.h"
2022-11-12 07:14:13 +00:00
#ifdef HAS_SDCARD
#include <SD.h>
2023-01-21 13:34:29 +00:00
#include <SPI.h>
2022-11-12 07:14:13 +00:00
2023-01-21 13:34:29 +00:00
#ifdef SDCARD_USE_SPI1
2022-11-12 07:14:13 +00:00
SPIClass SPI1(HSPI);
#define SDHandler SPI1
#else
#define SDHandler SPI
2022-11-12 07:14:13 +00:00
#endif
2023-01-21 13:34:29 +00:00
#endif // HAS_SDCARD
2022-11-12 07:14:13 +00:00
2023-07-26 23:34:36 +00:00
/**
* @brief Copies a file from one location to another.
2023-07-27 00:08:04 +00:00
*
2023-07-26 23:34:36 +00:00
* @param from The path of the source file.
* @param to The path of the destination file.
* @return true if the file was successfully copied, false otherwise.
*/
2023-01-21 13:34:29 +00:00
bool copyFile(const char *from, const char *to)
{
#ifdef FSCom
unsigned char cbuffer[16];
2023-01-21 13:34:29 +00:00
File f1 = FSCom.open(from, FILE_O_READ);
2023-01-21 13:34:29 +00:00
if (!f1) {
LOG_ERROR("Failed to open source file %s\n", from);
return false;
}
File f2 = FSCom.open(to, FILE_O_WRITE);
if (!f2) {
LOG_ERROR("Failed to open destination file %s\n", to);
return false;
}
2023-01-21 13:34:29 +00:00
while (f1.available() > 0) {
byte i = f1.read(cbuffer, 16);
f2.write(cbuffer, i);
}
2023-01-21 13:34:29 +00:00
f2.flush();
f2.close();
f1.close();
return true;
#endif
}
2023-07-26 23:34:36 +00:00
/**
* Renames a file from pathFrom to pathTo.
2023-07-27 00:08:04 +00:00
*
2023-07-26 23:34:36 +00:00
* @param pathFrom The original path of the file.
* @param pathTo The new path of the file.
2023-07-27 00:08:04 +00:00
*
2023-07-26 23:34:36 +00:00
* @return True if the file was successfully renamed, false otherwise.
*/
2023-01-21 13:34:29 +00:00
bool renameFile(const char *pathFrom, const char *pathTo)
{
#ifdef FSCom
#ifdef ARCH_ESP32
// rename was fixed for ESP32 IDF LittleFS in April
return FSCom.rename(pathFrom, pathTo);
2022-09-23 19:03:53 +00:00
#else
2023-01-21 13:34:29 +00:00
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) {
return true;
2023-01-21 13:34:29 +00:00
} else {
return false;
}
#endif
#endif
}
2023-07-26 23:34:36 +00:00
/**
* Lists the contents of a directory.
*
* @param dirname The name of the directory to list.
* @param levels The number of levels of subdirectories to list.
* @param del Whether or not to delete the contents of the directory after listing.
*/
void listDir(const char *dirname, uint8_t levels, bool del = false)
{
#ifdef FSCom
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
char buffer[255];
#endif
File root = FSCom.open(dirname, FILE_O_READ);
2023-01-21 13:34:29 +00:00
if (!root) {
return;
}
2023-01-21 13:34:29 +00:00
if (!root.isDirectory()) {
return;
}
File file = root.openNextFile();
2023-01-21 13:34:29 +00:00
while (file) {
if (file.isDirectory() && !String(file.name()).endsWith(".")) {
if (levels) {
2022-09-21 15:05:10 +00:00
#ifdef ARCH_ESP32
2023-01-21 13:34:29 +00:00
listDir(file.path(), levels - 1, del);
if (del) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Removing %s\n", file.path());
strncpy(buffer, file.path(), sizeof(buffer));
file.close();
FSCom.rmdir(buffer);
} else {
file.close();
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
2023-01-21 13:34:29 +00:00
listDir(file.name(), levels - 1, del);
if (del) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Removing %s\n", file.name());
strncpy(buffer, file.name(), sizeof(buffer));
file.close();
FSCom.rmdir(buffer);
} else {
file.close();
2023-01-21 13:34:29 +00:00
}
2022-09-21 15:05:10 +00:00
#else
2023-01-21 13:34:29 +00:00
listDir(file.name(), levels - 1, del);
file.close();
2022-09-21 15:05:10 +00:00
#endif
}
} else {
2022-09-21 15:05:10 +00:00
#ifdef ARCH_ESP32
2023-01-21 13:34:29 +00:00
if (del) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Deleting %s\n", file.path());
strncpy(buffer, file.path(), sizeof(buffer));
file.close();
FSCom.remove(buffer);
} else {
2023-01-21 13:34:29 +00:00
LOG_DEBUG(" %s (%i Bytes)\n", file.path(), file.size());
file.close();
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
2023-01-21 13:34:29 +00:00
if (del) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Deleting %s\n", file.name());
strncpy(buffer, file.name(), sizeof(buffer));
file.close();
FSCom.remove(buffer);
} else {
2022-12-30 02:41:37 +00:00
LOG_DEBUG(" %s (%i Bytes)\n", file.name(), file.size());
file.close();
}
2022-09-21 15:05:10 +00:00
#else
2022-12-30 02:41:37 +00:00
LOG_DEBUG(" %s (%i Bytes)\n", file.name(), file.size());
file.close();
2023-01-21 13:34:29 +00:00
#endif
}
file = root.openNextFile();
}
2023-01-21 13:34:29 +00:00
#ifdef ARCH_ESP32
if (del) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Removing %s\n", root.path());
strncpy(buffer, root.path(), sizeof(buffer));
root.close();
FSCom.rmdir(buffer);
} else {
root.close();
}
#elif (defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
2023-01-21 13:34:29 +00:00
if (del) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Removing %s\n", root.name());
strncpy(buffer, root.name(), sizeof(buffer));
root.close();
FSCom.rmdir(buffer);
} else {
root.close();
}
#else
root.close();
#endif
#endif
}
2023-07-26 23:34:36 +00:00
/**
* @brief Removes a directory and all its contents.
2023-07-27 00:08:04 +00:00
*
2023-07-26 23:34:36 +00:00
* This function recursively removes a directory and all its contents, including subdirectories and files.
2023-07-27 00:08:04 +00:00
*
2023-07-26 23:34:36 +00:00
* @param dirname The name of the directory to remove.
*/
2023-01-21 13:34:29 +00:00
void rmDir(const char *dirname)
{
#ifdef FSCom
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
listDir(dirname, 10, true);
2022-09-23 19:03:53 +00:00
#elif defined(ARCH_NRF52)
// nRF52 implementation of LittleFS has a recursive delete function
FSCom.rmdir_r(dirname);
#endif
#endif
}
bool fsCheck()
{
#if defined(ARCH_NRF52)
2024-05-07 06:33:16 +00:00
size_t write_size = 0;
size_t read_size = 0;
char buf[32] = {0};
Adafruit_LittleFS_Namespace::File file(FSCom);
const char *text = "meshtastic fs test";
size_t text_length = strlen(text);
const char *filename = "/meshtastic.txt";
LOG_DEBUG("Try create file .\n");
if (file.open(filename, FILE_O_WRITE)) {
write_size = file.write(text);
} else {
2024-05-07 06:33:16 +00:00
LOG_DEBUG("Open file failed .\n");
goto FORMAT_FS;
}
if (write_size != text_length) {
LOG_DEBUG("Text bytes do not match .\n");
file.close();
goto FORMAT_FS;
}
file.close();
if (!file.open(filename, FILE_O_READ)) {
LOG_DEBUG("Open file failed .\n");
goto FORMAT_FS;
}
read_size = file.readBytes(buf, text_length);
if (read_size != text_length) {
LOG_DEBUG("Text bytes do not match .\n");
file.close();
goto FORMAT_FS;
}
if (memcmp(buf, text, text_length) != 0) {
LOG_DEBUG("The written bytes do not match the read bytes .\n");
file.close();
goto FORMAT_FS;
}
return true;
FORMAT_FS:
LOG_DEBUG("Format FS ....\n");
FSCom.format();
FSCom.begin();
return false;
#else
return true;
#endif
}
void fsInit()
{
#ifdef FSCom
2023-01-21 13:34:29 +00:00
if (!FSBegin()) {
2023-01-07 12:16:58 +00:00
LOG_ERROR("Filesystem mount Failed.\n");
2023-01-07 12:25:29 +00:00
// assert(0); This auto-formats the partition, so no need to fail here.
}
2024-05-03 10:37:19 +00:00
#if defined(ARCH_ESP32)
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Filesystem files (%d/%d Bytes):\n", FSCom.usedBytes(), FSCom.totalBytes());
#elif defined(ARCH_NRF52)
/*
2024-05-03 10:37:19 +00:00
* nRF52840 has a certain chance of automatic formatting failure.
* Try to create a file after initializing the file system. If the creation fails,
* it means that the file system is not working properly. Please format it manually again.
* To check the normality of the file system, you need to disable the LFS_NO_ASSERT assertion.
* Otherwise, the assertion will be entered at the moment of reading or opening, and the FS will not be formatted.
2024-05-03 10:37:19 +00:00
* */
bool ret = false;
uint8_t retry = 3;
while (retry--) {
ret = fsCheck();
if (ret) {
LOG_DEBUG("File system check is OK.\n");
break;
}
delay(10);
}
// It may not be possible to reach this step.
// Add a loop here to prevent unpredictable situations from happening.
// Can add a screen to display error status later.
if (!ret) {
while (1) {
2024-05-08 00:45:24 +00:00
LOG_ERROR("The file system is damaged and cannot proceed to the next step.\n");
2024-05-07 06:33:16 +00:00
delay(1000);
}
}
2022-09-21 15:05:10 +00:00
#else
2022-12-30 02:41:37 +00:00
LOG_DEBUG("Filesystem files:\n");
2022-09-21 15:05:10 +00:00
#endif
2022-03-15 21:49:06 +00:00
listDir("/", 10);
#endif
}
2022-11-12 07:14:13 +00:00
2023-07-26 23:34:36 +00:00
/**
* Initializes the SD card and mounts the file system.
*/
2022-11-12 07:14:13 +00:00
void setupSDCard()
{
#ifdef HAS_SDCARD
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if (!SD.begin(SDCARD_CS, SDHandler)) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("No SD_MMC card detected\n");
2023-01-21 13:34:29 +00:00
return;
2022-11-12 07:14:13 +00:00
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("No SD_MMC card attached\n");
2023-01-21 13:34:29 +00:00
return;
2022-11-12 07:14:13 +00:00
}
2022-12-30 02:41:37 +00:00
LOG_DEBUG("SD_MMC Card Type: ");
2022-11-12 07:14:13 +00:00
if (cardType == CARD_MMC) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("MMC\n");
2022-11-12 07:14:13 +00:00
} else if (cardType == CARD_SD) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("SDSC\n");
2022-11-12 07:14:13 +00:00
} else if (cardType == CARD_SDHC) {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("SDHC\n");
2022-11-12 07:14:13 +00:00
} else {
2022-12-30 02:41:37 +00:00
LOG_DEBUG("UNKNOWN\n");
2022-11-12 07:14:13 +00:00
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
2022-12-30 02:41:37 +00:00
LOG_DEBUG("SD Card Size: %lluMB\n", cardSize);
LOG_DEBUG("Total space: %llu MB\n", SD.totalBytes() / (1024 * 1024));
LOG_DEBUG("Used space: %llu MB\n", SD.usedBytes() / (1024 * 1024));
2022-11-12 07:14:13 +00:00
#endif
2023-07-27 00:08:04 +00:00
}