369 lines
8.8 KiB
C++
369 lines
8.8 KiB
C++
#include "FileLib.h"
|
||
|
||
FileLibClass::FileLibClass(StorageType type) : _type(type) {}
|
||
|
||
FileLibClass::~FileLibClass()
|
||
{
|
||
_printMessage("Unmounting file system\n");
|
||
if (_type == StorageType::FL_SPIFFS)
|
||
{
|
||
LITTLEFS.end();
|
||
}
|
||
else if (_type == StorageType::FL_MMC)
|
||
{
|
||
SD_MMC.end();
|
||
}
|
||
else if (_type == StorageType::FL_SD)
|
||
{
|
||
SD.end();
|
||
}
|
||
}
|
||
|
||
bool FileLibClass::begin(uint8_t csPin, uint8_t misoPin, uint8_t mosiPin, uint8_t sckPin)
|
||
{
|
||
_printMessage("Initializing file system\n");
|
||
if (_type == StorageType::FL_SPIFFS)
|
||
{
|
||
_filesystem = &LITTLEFS;
|
||
return LITTLEFS.begin(true);
|
||
}
|
||
|
||
if (_type == StorageType::FL_MMC)
|
||
{
|
||
_filesystem = &SD_MMC;
|
||
return SD_MMC.begin();
|
||
}
|
||
|
||
if (_type == StorageType::FL_SD)
|
||
{
|
||
_spi.begin(sckPin, misoPin, mosiPin, csPin);
|
||
_filesystem = &SD;
|
||
return SD.begin(5, _spi);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
File FileLibClass::openForWriting(const char *fileName)
|
||
{
|
||
_printMessage("Opening file '%s' for writing\n", fileName);
|
||
return _filesystem->open(fileName, FILE_WRITE);
|
||
}
|
||
|
||
File FileLibClass::open(const char *fileName, const char *mode)
|
||
{
|
||
if (!_filesystem)
|
||
{
|
||
_printMessage("File system not initialized");
|
||
return File(); // Return an empty File object if filesystem is not initialized
|
||
}
|
||
return _filesystem->open(fileName, mode);
|
||
}
|
||
|
||
bool FileLibClass::readPartial(const char *fileName, uint32_t startPos, uint8_t *buffer, uint16_t bufferSize)
|
||
{
|
||
if (!_filesystem)
|
||
{
|
||
_printMessage("File system not initialized");
|
||
return false;
|
||
}
|
||
|
||
File file = _filesystem->open(fileName, FILE_READ);
|
||
if (!file)
|
||
{
|
||
_printMessage("Failed to open file");
|
||
return false;
|
||
}
|
||
|
||
if (!file.seek(startPos))
|
||
{
|
||
_printMessage("Failed to seek to position %u in file", startPos);
|
||
file.close();
|
||
return false;
|
||
}
|
||
|
||
size_t bytesRead = file.read(buffer, bufferSize);
|
||
file.close();
|
||
|
||
if (bytesRead == 0)
|
||
{
|
||
_printMessage("No data read from file");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool FileLibClass::write(const char *fileName, const uint8_t *data, size_t dataSize, bool append)
|
||
{
|
||
_printMessage("Writing %d bytes to file '%s'\n", dataSize, fileName);
|
||
File file = _filesystem->open(fileName, append ? FILE_APPEND : FILE_WRITE);
|
||
|
||
// Sanity check
|
||
if (!file || file.isDirectory())
|
||
{
|
||
_printMessage("Failed to open file '%s' for writing\n", fileName);
|
||
return false;
|
||
}
|
||
|
||
// size_t written = file.write(reinterpret_cast<const uint8_t *>(data), dataSize);
|
||
size_t written = 0;
|
||
for (size_t i = 0; i < dataSize; i++)
|
||
{
|
||
written += file.write(data[i]);
|
||
}
|
||
|
||
// Confirm that the data was written
|
||
if (written == dataSize)
|
||
{
|
||
file.close();
|
||
return true;
|
||
}
|
||
|
||
if (written > 0)
|
||
{
|
||
_printMessage("Only wrote %d bytes of %d\n", written, dataSize);
|
||
file.close();
|
||
return false;
|
||
}
|
||
|
||
_printMessage("Failed to write to file '%s'\n", fileName);
|
||
file.close();
|
||
return false;
|
||
}
|
||
|
||
bool FileLibClass::writeString(const char *fileName, const uint8_t *data, bool append)
|
||
{
|
||
_printMessage("Writing string to file '%s'\n", fileName);
|
||
// use strlen so we don't write the null terminator
|
||
int strLen = strlen((char *)&data);
|
||
return write(fileName, reinterpret_cast<const uint8_t *>(data), strLen, append);
|
||
}
|
||
|
||
void FileLibClass::listDir(const char *dirName, uint8_t levels)
|
||
{
|
||
if (!_verbose)
|
||
{
|
||
return;
|
||
}
|
||
|
||
_printMessage("Listing directory: %s\r\n", dirName);
|
||
|
||
File root = _filesystem->open(dirName);
|
||
if (!root)
|
||
{
|
||
_printMessage("− failed to open directory");
|
||
return;
|
||
}
|
||
|
||
if (!root.isDirectory())
|
||
{
|
||
_printMessage(" − not a directory");
|
||
return;
|
||
}
|
||
|
||
File file = root.openNextFile();
|
||
while (file)
|
||
{
|
||
if (file.isDirectory())
|
||
{
|
||
Serial.printf(" DIR : %s\n", file.name());
|
||
if (levels)
|
||
{
|
||
listDir(file.name(), levels - 1);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Serial.printf(" FILE: %s", file.name());
|
||
Serial.printf("\tSIZE: %d\n", file.size());
|
||
}
|
||
file = root.openNextFile();
|
||
}
|
||
}
|
||
|
||
bool FileLibClass::read(const char *fileName, uint8_t *buffer, uint16_t bufferSize, bool clearBuffer)
|
||
{
|
||
_printMessage("Reading file '%s'\n", fileName);
|
||
if (clearBuffer)
|
||
{
|
||
memset(buffer, 0, bufferSize);
|
||
}
|
||
|
||
File file = _filesystem->open(fileName, FILE_READ);
|
||
|
||
uint16_t fileSize = file.size();
|
||
|
||
// Sanity check
|
||
if (!file || file.isDirectory())
|
||
{
|
||
_printMessage("Failed to open file '%s'.\n", fileName);
|
||
return false;
|
||
}
|
||
|
||
// check if the buffer is big enough
|
||
if (bufferSize < fileSize)
|
||
{
|
||
_printMessage("Buffer size is too small for file '%s'.\n", fileName);
|
||
file.close();
|
||
return false;
|
||
}
|
||
|
||
if (!file.available())
|
||
{
|
||
_printMessage("File '%s' is empty.\n", fileName);
|
||
}
|
||
|
||
// size_t bytesRead = file.readBytes(buffer, fileSize);
|
||
// read the data byte by byte
|
||
for (size_t i = 0; i < fileSize; i++)
|
||
{
|
||
buffer[i] = file.read();
|
||
}
|
||
|
||
file.close();
|
||
return true;
|
||
}
|
||
|
||
bool FileLibClass::remove(const char *fileName)
|
||
{
|
||
_printMessage("Removing file '%s'\n", fileName);
|
||
if (!_filesystem->exists(fileName))
|
||
{
|
||
_printMessage("File '%s' does not exist.\n", fileName);
|
||
return false;
|
||
}
|
||
return _filesystem->remove(fileName);
|
||
}
|
||
|
||
bool FileLibClass::rename(const char *fileName, const char *newName, bool overwrite)
|
||
{
|
||
_printMessage("Renaming file '%s' to '%s'\n", fileName, newName);
|
||
if (_filesystem->exists(newName) && !overwrite)
|
||
{
|
||
_printMessage("File '%s' already exists.\n", newName);
|
||
return false;
|
||
}
|
||
|
||
return _filesystem->rename(fileName, newName);
|
||
}
|
||
|
||
bool FileLibClass::mkdir(const char *path)
|
||
{
|
||
_printMessage("Creating directory '%s'\n", path);
|
||
|
||
if (_filesystem->exists(path))
|
||
{
|
||
_printMessage("Directory '%s' already exists.\n", path);
|
||
return false;
|
||
}
|
||
|
||
return _filesystem->mkdir(path);
|
||
}
|
||
|
||
uint64_t FileLibClass::getFreeSpace()
|
||
{
|
||
_printMessage("Getting free space\n");
|
||
if (_type == StorageType::FL_SPIFFS)
|
||
{
|
||
return LITTLEFS.totalBytes() - LITTLEFS.usedBytes();
|
||
}
|
||
|
||
if (_type == StorageType::FL_MMC)
|
||
{
|
||
uint64_t cardSize = SD_MMC.totalBytes();
|
||
uint64_t usedSpace = SD_MMC.usedBytes();
|
||
|
||
if (usedSpace > cardSize)
|
||
{
|
||
_printMessage("ERROR: Used space is greater than card size \n");
|
||
return 0;
|
||
}
|
||
|
||
uint64_t freeSpace = cardSize - usedSpace;
|
||
return freeSpace;
|
||
}
|
||
|
||
if (_type == StorageType::FL_SD)
|
||
{
|
||
uint64_t cardSize = SD.totalBytes();
|
||
uint64_t usedSpace = SD.usedBytes();
|
||
|
||
if (usedSpace > cardSize)
|
||
{
|
||
_printMessage("Error: Used space is greater than card size \n");
|
||
return 0;
|
||
}
|
||
|
||
uint64_t freeSpace = cardSize - usedSpace;
|
||
return freeSpace;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
bool copy(File &source, File &dest)
|
||
{
|
||
if (!source || !dest)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
int bufferSize = 512;
|
||
char buffer[bufferSize];
|
||
|
||
while (source.available())
|
||
{
|
||
int bytesRead = source.readBytes(buffer, bufferSize);
|
||
int bytesWritten = dest.write((uint8_t *)&buffer, bytesRead);
|
||
|
||
if (bytesWritten != bytesRead)
|
||
{
|
||
return false;
|
||
}
|
||
}
|
||
|
||
dest.flush();
|
||
|
||
return true;
|
||
}
|
||
|
||
void FileLibClass::_printMessage(const char *message, ...)
|
||
{
|
||
if (_verbose)
|
||
{
|
||
// get the type name
|
||
const char *typeName;
|
||
switch (_type)
|
||
{
|
||
case FL_SPIFFS:
|
||
typeName = "FL_SPIFFS";
|
||
break;
|
||
case FL_SD:
|
||
typeName = "FL_SD";
|
||
break;
|
||
case FL_MMC:
|
||
typeName = "FL_MMC";
|
||
break;
|
||
default:
|
||
typeName = "Unknown";
|
||
break;
|
||
}
|
||
|
||
char buffer[256];
|
||
|
||
va_list args;
|
||
va_start(args, message);
|
||
vsnprintf(buffer, sizeof(buffer), message, args);
|
||
va_end(args);
|
||
// switch for different storage types
|
||
Serial.printf("%s: %s", typeName, buffer);
|
||
}
|
||
}
|
||
|
||
//Create FileLibClass::exists function
|
||
bool FileLibClass::exists(const char* fileName)
|
||
{
|
||
return _filesystem->exists(fileName);
|
||
}
|