add HAL storage

This commit is contained in:
Xuan Son Nguyen 2026-01-22 22:38:25 +01:00
parent c869ca46ed
commit d65e0fe5f7
33 changed files with 217 additions and 168 deletions

View File

@ -3,7 +3,7 @@
#include <FsHelpers.h>
#include <HardwareSerial.h>
#include <JpegToBmpConverter.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <ZipFile.h>
#include "Epub/parsers/ContainerParser.h"
@ -101,12 +101,12 @@ bool Epub::parseTocNcxFile() const {
const auto tmpNcxPath = getCachePath() + "/toc.ncx";
FsFile tempNcxFile;
if (!SdMan.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) {
if (!HAL_STORAGE.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) {
return false;
}
readItemContentsToStream(tocNcxItem, tempNcxFile, 1024);
tempNcxFile.close();
if (!SdMan.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) {
if (!HAL_STORAGE.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) {
return false;
}
const auto ncxSize = tempNcxFile.size();
@ -141,7 +141,7 @@ bool Epub::parseTocNcxFile() const {
free(ncxBuffer);
tempNcxFile.close();
SdMan.remove(tmpNcxPath.c_str());
HAL_STORAGE.remove(tmpNcxPath.c_str());
Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis());
return true;
@ -158,12 +158,12 @@ bool Epub::parseTocNavFile() const {
const auto tmpNavPath = getCachePath() + "/toc.nav";
FsFile tempNavFile;
if (!SdMan.openFileForWrite("EBP", tmpNavPath, tempNavFile)) {
if (!HAL_STORAGE.openFileForWrite("EBP", tmpNavPath, tempNavFile)) {
return false;
}
readItemContentsToStream(tocNavItem, tempNavFile, 1024);
tempNavFile.close();
if (!SdMan.openFileForRead("EBP", tmpNavPath, tempNavFile)) {
if (!HAL_STORAGE.openFileForRead("EBP", tmpNavPath, tempNavFile)) {
return false;
}
const auto navSize = tempNavFile.size();
@ -198,7 +198,7 @@ bool Epub::parseTocNavFile() const {
free(navBuffer);
tempNavFile.close();
SdMan.remove(tmpNavPath.c_str());
HAL_STORAGE.remove(tmpNavPath.c_str());
Serial.printf("[%lu] [EBP] Parsed TOC nav items\n", millis());
return true;
@ -305,12 +305,12 @@ bool Epub::load(const bool buildIfMissing) {
}
bool Epub::clearCache() const {
if (!SdMan.exists(cachePath.c_str())) {
if (!HAL_STORAGE.exists(cachePath.c_str())) {
Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis());
return true;
}
if (!SdMan.removeDir(cachePath.c_str())) {
if (!HAL_STORAGE.removeDir(cachePath.c_str())) {
Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis());
return false;
}
@ -320,11 +320,11 @@ bool Epub::clearCache() const {
}
void Epub::setupCacheDir() const {
if (SdMan.exists(cachePath.c_str())) {
if (HAL_STORAGE.exists(cachePath.c_str())) {
return;
}
SdMan.mkdir(cachePath.c_str());
HAL_STORAGE.mkdir(cachePath.c_str());
}
const std::string& Epub::getCachePath() const { return cachePath; }
@ -365,7 +365,7 @@ std::string Epub::getCoverBmpPath(bool cropped) const {
bool Epub::generateCoverBmp(bool cropped) const {
// Already generated, return true
if (SdMan.exists(getCoverBmpPath(cropped).c_str())) {
if (HAL_STORAGE.exists(getCoverBmpPath(cropped).c_str())) {
return true;
}
@ -386,29 +386,29 @@ bool Epub::generateCoverBmp(bool cropped) const {
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
FsFile coverJpg;
if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
if (!HAL_STORAGE.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
return false;
}
readItemContentsToStream(coverImageHref, coverJpg, 1024);
coverJpg.close();
if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
if (!HAL_STORAGE.openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
return false;
}
FsFile coverBmp;
if (!SdMan.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) {
if (!HAL_STORAGE.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) {
coverJpg.close();
return false;
}
const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp);
coverJpg.close();
coverBmp.close();
SdMan.remove(coverJpgTempPath.c_str());
HAL_STORAGE.remove(coverJpgTempPath.c_str());
if (!success) {
Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis());
SdMan.remove(getCoverBmpPath(cropped).c_str());
HAL_STORAGE.remove(getCoverBmpPath(cropped).c_str());
}
Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no");
return success;
@ -423,7 +423,7 @@ std::string Epub::getThumbBmpPath() const { return cachePath + "/thumb.bmp"; }
bool Epub::generateThumbBmp() const {
// Already generated, return true
if (SdMan.exists(getThumbBmpPath().c_str())) {
if (HAL_STORAGE.exists(getThumbBmpPath().c_str())) {
return true;
}
@ -444,18 +444,18 @@ bool Epub::generateThumbBmp() const {
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
FsFile coverJpg;
if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
if (!HAL_STORAGE.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
return false;
}
readItemContentsToStream(coverImageHref, coverJpg, 1024);
coverJpg.close();
if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
if (!HAL_STORAGE.openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
return false;
}
FsFile thumbBmp;
if (!SdMan.openFileForWrite("EBP", getThumbBmpPath(), thumbBmp)) {
if (!HAL_STORAGE.openFileForWrite("EBP", getThumbBmpPath(), thumbBmp)) {
coverJpg.close();
return false;
}
@ -467,11 +467,11 @@ bool Epub::generateThumbBmp() const {
THUMB_TARGET_HEIGHT);
coverJpg.close();
thumbBmp.close();
SdMan.remove(coverJpgTempPath.c_str());
HAL_STORAGE.remove(coverJpgTempPath.c_str());
if (!success) {
Serial.printf("[%lu] [EBP] Failed to generate thumb BMP from JPG cover image\n", millis());
SdMan.remove(getThumbBmpPath().c_str());
HAL_STORAGE.remove(getThumbBmpPath().c_str());
}
Serial.printf("[%lu] [EBP] Generated thumb BMP from JPG cover image, success: %s\n", millis(),
success ? "yes" : "no");

View File

@ -29,7 +29,7 @@ bool BookMetadataCache::beginContentOpfPass() {
Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis());
// Open spine file for writing
return SdMan.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile);
return HAL_STORAGE.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile);
}
bool BookMetadataCache::endContentOpfPass() {
@ -41,10 +41,10 @@ bool BookMetadataCache::beginTocPass() {
Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis());
// Open spine file for reading
if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
if (!HAL_STORAGE.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
return false;
}
if (!SdMan.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) {
if (!HAL_STORAGE.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) {
spineFile.close();
return false;
}
@ -70,16 +70,16 @@ bool BookMetadataCache::endWrite() {
bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMetadata& metadata) {
// Open all three files, writing to meta, reading from spine and toc
if (!SdMan.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) {
if (!HAL_STORAGE.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) {
return false;
}
if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
if (!HAL_STORAGE.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
bookFile.close();
return false;
}
if (!SdMan.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) {
if (!HAL_STORAGE.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) {
bookFile.close();
spineFile.close();
return false;
@ -201,11 +201,11 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
}
bool BookMetadataCache::cleanupTmpFiles() const {
if (SdMan.exists((cachePath + tmpSpineBinFile).c_str())) {
SdMan.remove((cachePath + tmpSpineBinFile).c_str());
if (HAL_STORAGE.exists((cachePath + tmpSpineBinFile).c_str())) {
HAL_STORAGE.remove((cachePath + tmpSpineBinFile).c_str());
}
if (SdMan.exists((cachePath + tmpTocBinFile).c_str())) {
SdMan.remove((cachePath + tmpTocBinFile).c_str());
if (HAL_STORAGE.exists((cachePath + tmpTocBinFile).c_str())) {
HAL_STORAGE.remove((cachePath + tmpTocBinFile).c_str());
}
return true;
}
@ -273,7 +273,7 @@ void BookMetadataCache::createTocEntry(const std::string& title, const std::stri
/* ============= READING / LOADING FUNCTIONS ================ */
bool BookMetadataCache::load() {
if (!SdMan.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) {
if (!HAL_STORAGE.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) {
return false;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <SDCardManager.h>
#include <HalStorage.h>
#include <string>

View File

@ -1,6 +1,6 @@
#include "Section.h"
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
#include "Page.h"
@ -58,7 +58,7 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
const uint16_t viewportHeight, const bool hyphenationEnabled) {
if (!SdMan.openFileForRead("SCT", filePath, file)) {
if (!HAL_STORAGE.openFileForRead("SCT", filePath, file)) {
return false;
}
@ -106,12 +106,12 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
// Your updated class method (assuming you are using the 'SD' object, which is a wrapper for a specific filesystem)
bool Section::clearCache() const {
if (!SdMan.exists(filePath.c_str())) {
if (!HAL_STORAGE.exists(filePath.c_str())) {
Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis());
return true;
}
if (!SdMan.remove(filePath.c_str())) {
if (!HAL_STORAGE.remove(filePath.c_str())) {
Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis());
return false;
}
@ -132,7 +132,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
// Create cache directory if it doesn't exist
{
const auto sectionsDir = epub->getCachePath() + "/sections";
SdMan.mkdir(sectionsDir.c_str());
HAL_STORAGE.mkdir(sectionsDir.c_str());
}
// Retry logic for SD card timing issues
@ -145,12 +145,12 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
}
// Remove any incomplete file from previous attempt before retrying
if (SdMan.exists(tmpHtmlPath.c_str())) {
SdMan.remove(tmpHtmlPath.c_str());
if (HAL_STORAGE.exists(tmpHtmlPath.c_str())) {
HAL_STORAGE.remove(tmpHtmlPath.c_str());
}
FsFile tmpHtml;
if (!SdMan.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
if (!HAL_STORAGE.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
continue;
}
success = epub->readItemContentsToStream(localPath, tmpHtml, 1024);
@ -158,8 +158,8 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
tmpHtml.close();
// If streaming failed, remove the incomplete file immediately
if (!success && SdMan.exists(tmpHtmlPath.c_str())) {
SdMan.remove(tmpHtmlPath.c_str());
if (!success && HAL_STORAGE.exists(tmpHtmlPath.c_str())) {
HAL_STORAGE.remove(tmpHtmlPath.c_str());
Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis());
}
}
@ -176,7 +176,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
progressSetupFn();
}
if (!SdMan.openFileForWrite("SCT", filePath, file)) {
if (!HAL_STORAGE.openFileForWrite("SCT", filePath, file)) {
return false;
}
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth,
@ -191,11 +191,11 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
Hyphenator::setPreferredLanguage(epub->getLanguage());
success = visitor.parseAndBuildPages();
SdMan.remove(tmpHtmlPath.c_str());
HAL_STORAGE.remove(tmpHtmlPath.c_str());
if (!success) {
Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis());
file.close();
SdMan.remove(filePath.c_str());
HAL_STORAGE.remove(filePath.c_str());
return false;
}
@ -213,7 +213,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
if (hasFailedLutRecords) {
Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis());
file.close();
SdMan.remove(filePath.c_str());
HAL_STORAGE.remove(filePath.c_str());
return false;
}
@ -226,7 +226,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
}
std::unique_ptr<Page> Section::loadPageFromSectionFile() {
if (!SdMan.openFileForRead("SCT", filePath, file)) {
if (!HAL_STORAGE.openFileForRead("SCT", filePath, file)) {
return nullptr;
}

View File

@ -2,7 +2,7 @@
#include <GfxRenderer.h>
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <expat.h>
#include "../Page.h"
@ -264,7 +264,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
}
FsFile file;
if (!SdMan.openFileForRead("EHP", filepath, file)) {
if (!HAL_STORAGE.openFileForRead("EHP", filepath, file)) {
XML_ParserFree(parser);
return false;
}

View File

@ -35,8 +35,8 @@ ContentOpfParser::~ContentOpfParser() {
if (tempItemStore) {
tempItemStore.close();
}
if (SdMan.exists((cachePath + itemCacheFile).c_str())) {
SdMan.remove((cachePath + itemCacheFile).c_str());
if (HAL_STORAGE.exists((cachePath + itemCacheFile).c_str())) {
HAL_STORAGE.remove((cachePath + itemCacheFile).c_str());
}
}
@ -114,7 +114,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
if (self->state == IN_PACKAGE && (strcmp(name, "manifest") == 0 || strcmp(name, "opf:manifest") == 0)) {
self->state = IN_MANIFEST;
if (!SdMan.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
if (!HAL_STORAGE.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
Serial.printf(
"[%lu] [COF] Couldn't open temp items file for writing. This is probably going to be a fatal error.\n",
millis());
@ -124,7 +124,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
if (self->state == IN_PACKAGE && (strcmp(name, "spine") == 0 || strcmp(name, "opf:spine") == 0)) {
self->state = IN_SPINE;
if (!SdMan.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
if (!HAL_STORAGE.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
Serial.printf(
"[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n",
millis());
@ -136,7 +136,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
self->state = IN_GUIDE;
// TODO Remove print
Serial.printf("[%lu] [COF] Entering guide state.\n", millis());
if (!SdMan.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
if (!HAL_STORAGE.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
Serial.printf(
"[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n",
millis());

View File

@ -2,7 +2,7 @@
#include <HardwareSerial.h>
#include <MD5Builder.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
// Initialize the static instance
@ -32,10 +32,10 @@ void KOReaderCredentialStore::obfuscate(std::string& data) const {
bool KOReaderCredentialStore::saveToFile() const {
// Make sure the directory exists
SdMan.mkdir("/.crosspoint");
HAL_STORAGE.mkdir("/.crosspoint");
FsFile file;
if (!SdMan.openFileForWrite("KRS", KOREADER_FILE, file)) {
if (!HAL_STORAGE.openFileForWrite("KRS", KOREADER_FILE, file)) {
return false;
}
@ -64,7 +64,7 @@ bool KOReaderCredentialStore::saveToFile() const {
bool KOReaderCredentialStore::loadFromFile() {
FsFile file;
if (!SdMan.openFileForRead("KRS", KOREADER_FILE, file)) {
if (!HAL_STORAGE.openFileForRead("KRS", KOREADER_FILE, file)) {
Serial.printf("[%lu] [KRS] No credentials file found\n", millis());
return false;
}

View File

@ -2,7 +2,7 @@
#include <HardwareSerial.h>
#include <MD5Builder.h>
#include <SDCardManager.h>
#include <HalStorage.h>
namespace {
// Extract filename from path (everything after last '/')
@ -43,7 +43,7 @@ size_t KOReaderDocumentId::getOffset(int i) {
std::string KOReaderDocumentId::calculate(const std::string& filePath) {
FsFile file;
if (!SdMan.openFileForRead("KODoc", filePath, file)) {
if (!HAL_STORAGE.openFileForRead("KODoc", filePath, file)) {
Serial.printf("[%lu] [KODoc] Failed to open file: %s\n", millis(), filePath.c_str());
return "";
}

View File

@ -15,13 +15,13 @@ bool Txt::load() {
return true;
}
if (!SdMan.exists(filepath.c_str())) {
if (!HAL_STORAGE.exists(filepath.c_str())) {
Serial.printf("[%lu] [TXT] File does not exist: %s\n", millis(), filepath.c_str());
return false;
}
FsFile file;
if (!SdMan.openFileForRead("TXT", filepath, file)) {
if (!HAL_STORAGE.openFileForRead("TXT", filepath, file)) {
Serial.printf("[%lu] [TXT] Failed to open file: %s\n", millis(), filepath.c_str());
return false;
}
@ -48,11 +48,11 @@ std::string Txt::getTitle() const {
}
void Txt::setupCacheDir() const {
if (!SdMan.exists(cacheBasePath.c_str())) {
SdMan.mkdir(cacheBasePath.c_str());
if (!HAL_STORAGE.exists(cacheBasePath.c_str())) {
HAL_STORAGE.mkdir(cacheBasePath.c_str());
}
if (!SdMan.exists(cachePath.c_str())) {
SdMan.mkdir(cachePath.c_str());
if (!HAL_STORAGE.exists(cachePath.c_str())) {
HAL_STORAGE.mkdir(cachePath.c_str());
}
}
@ -73,7 +73,7 @@ std::string Txt::findCoverImage() const {
// First priority: look for image with same name as txt file (e.g., mybook.jpg)
for (const auto& ext : extensions) {
std::string coverPath = folder + "/" + baseName + ext;
if (SdMan.exists(coverPath.c_str())) {
if (HAL_STORAGE.exists(coverPath.c_str())) {
Serial.printf("[%lu] [TXT] Found matching cover image: %s\n", millis(), coverPath.c_str());
return coverPath;
}
@ -84,7 +84,7 @@ std::string Txt::findCoverImage() const {
for (const auto& name : coverNames) {
for (const auto& ext : extensions) {
std::string coverPath = folder + "/" + std::string(name) + ext;
if (SdMan.exists(coverPath.c_str())) {
if (HAL_STORAGE.exists(coverPath.c_str())) {
Serial.printf("[%lu] [TXT] Found fallback cover image: %s\n", millis(), coverPath.c_str());
return coverPath;
}
@ -98,7 +98,7 @@ std::string Txt::getCoverBmpPath() const { return cachePath + "/cover.bmp"; }
bool Txt::generateCoverBmp() const {
// Already generated, return true
if (SdMan.exists(getCoverBmpPath().c_str())) {
if (HAL_STORAGE.exists(getCoverBmpPath().c_str())) {
return true;
}
@ -122,10 +122,10 @@ bool Txt::generateCoverBmp() const {
// Copy BMP file to cache
Serial.printf("[%lu] [TXT] Copying BMP cover image to cache\n", millis());
FsFile src, dst;
if (!SdMan.openFileForRead("TXT", coverImagePath, src)) {
if (!HAL_STORAGE.openFileForRead("TXT", coverImagePath, src)) {
return false;
}
if (!SdMan.openFileForWrite("TXT", getCoverBmpPath(), dst)) {
if (!HAL_STORAGE.openFileForWrite("TXT", getCoverBmpPath(), dst)) {
src.close();
return false;
}
@ -144,10 +144,10 @@ bool Txt::generateCoverBmp() const {
// Convert JPG/JPEG to BMP (same approach as Epub)
Serial.printf("[%lu] [TXT] Generating BMP from JPG cover image\n", millis());
FsFile coverJpg, coverBmp;
if (!SdMan.openFileForRead("TXT", coverImagePath, coverJpg)) {
if (!HAL_STORAGE.openFileForRead("TXT", coverImagePath, coverJpg)) {
return false;
}
if (!SdMan.openFileForWrite("TXT", getCoverBmpPath(), coverBmp)) {
if (!HAL_STORAGE.openFileForWrite("TXT", getCoverBmpPath(), coverBmp)) {
coverJpg.close();
return false;
}
@ -157,7 +157,7 @@ bool Txt::generateCoverBmp() const {
if (!success) {
Serial.printf("[%lu] [TXT] Failed to generate BMP from JPG cover image\n", millis());
SdMan.remove(getCoverBmpPath().c_str());
HAL_STORAGE.remove(getCoverBmpPath().c_str());
} else {
Serial.printf("[%lu] [TXT] Generated BMP from JPG cover image\n", millis());
}
@ -175,7 +175,7 @@ bool Txt::readContent(uint8_t* buffer, size_t offset, size_t length) const {
}
FsFile file;
if (!SdMan.openFileForRead("TXT", filepath, file)) {
if (!HAL_STORAGE.openFileForRead("TXT", filepath, file)) {
return false;
}

View File

@ -1,6 +1,6 @@
#pragma once
#include <SDCardManager.h>
#include <HalStorage.h>
#include <memory>
#include <string>

View File

@ -9,7 +9,7 @@
#include <FsHelpers.h>
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
bool Xtc::load() {
Serial.printf("[%lu] [XTC] Loading XTC: %s\n", millis(), filepath.c_str());
@ -31,12 +31,12 @@ bool Xtc::load() {
}
bool Xtc::clearCache() const {
if (!SdMan.exists(cachePath.c_str())) {
if (!HAL_STORAGE.exists(cachePath.c_str())) {
Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis());
return true;
}
if (!SdMan.removeDir(cachePath.c_str())) {
if (!HAL_STORAGE.removeDir(cachePath.c_str())) {
Serial.printf("[%lu] [XTC] Failed to clear cache\n", millis());
return false;
}
@ -46,17 +46,17 @@ bool Xtc::clearCache() const {
}
void Xtc::setupCacheDir() const {
if (SdMan.exists(cachePath.c_str())) {
if (HAL_STORAGE.exists(cachePath.c_str())) {
return;
}
// Create directories recursively
for (size_t i = 1; i < cachePath.length(); i++) {
if (cachePath[i] == '/') {
SdMan.mkdir(cachePath.substr(0, i).c_str());
HAL_STORAGE.mkdir(cachePath.substr(0, i).c_str());
}
}
SdMan.mkdir(cachePath.c_str());
HAL_STORAGE.mkdir(cachePath.c_str());
}
std::string Xtc::getTitle() const {
@ -106,7 +106,7 @@ std::string Xtc::getCoverBmpPath() const { return cachePath + "/cover.bmp"; }
bool Xtc::generateCoverBmp() const {
// Already generated
if (SdMan.exists(getCoverBmpPath().c_str())) {
if (HAL_STORAGE.exists(getCoverBmpPath().c_str())) {
return true;
}
@ -158,7 +158,7 @@ bool Xtc::generateCoverBmp() const {
// Create BMP file
FsFile coverBmp;
if (!SdMan.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) {
if (!HAL_STORAGE.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) {
Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis());
free(pageBuffer);
return false;
@ -297,7 +297,7 @@ std::string Xtc::getThumbBmpPath() const { return cachePath + "/thumb.bmp"; }
bool Xtc::generateThumbBmp() const {
// Already generated
if (SdMan.exists(getThumbBmpPath().c_str())) {
if (HAL_STORAGE.exists(getThumbBmpPath().c_str())) {
return true;
}
@ -339,8 +339,8 @@ bool Xtc::generateThumbBmp() const {
// Copy cover.bmp to thumb.bmp
if (generateCoverBmp()) {
FsFile src, dst;
if (SdMan.openFileForRead("XTC", getCoverBmpPath(), src)) {
if (SdMan.openFileForWrite("XTC", getThumbBmpPath(), dst)) {
if (HAL_STORAGE.openFileForRead("XTC", getCoverBmpPath(), src)) {
if (HAL_STORAGE.openFileForWrite("XTC", getThumbBmpPath(), dst)) {
uint8_t buffer[512];
while (src.available()) {
size_t bytesRead = src.read(buffer, sizeof(buffer));
@ -351,7 +351,7 @@ bool Xtc::generateThumbBmp() const {
src.close();
}
Serial.printf("[%lu] [XTC] Copied cover to thumb (no scaling needed)\n", millis());
return SdMan.exists(getThumbBmpPath().c_str());
return HAL_STORAGE.exists(getThumbBmpPath().c_str());
}
return false;
}
@ -385,7 +385,7 @@ bool Xtc::generateThumbBmp() const {
// Create thumbnail BMP file - use 1-bit format for fast home screen rendering (no gray passes)
FsFile thumbBmp;
if (!SdMan.openFileForWrite("XTC", getThumbBmpPath(), thumbBmp)) {
if (!HAL_STORAGE.openFileForWrite("XTC", getThumbBmpPath(), thumbBmp)) {
Serial.printf("[%lu] [XTC] Failed to create thumb BMP file\n", millis());
free(pageBuffer);
return false;

View File

@ -9,7 +9,7 @@
#include <FsHelpers.h>
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <cstring>
@ -34,7 +34,7 @@ XtcError XtcParser::open(const char* filepath) {
}
// Open file
if (!SdMan.openFileForRead("XTC", filepath, m_file)) {
if (!HAL_STORAGE.openFileForRead("XTC", filepath, m_file)) {
m_lastError = XtcError::FILE_NOT_FOUND;
return m_lastError;
}
@ -421,7 +421,7 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex,
bool XtcParser::isValidXtcFile(const char* filepath) {
FsFile file;
if (!SdMan.openFileForRead("XTC", filepath, file)) {
if (!HAL_STORAGE.openFileForRead("XTC", filepath, file)) {
return false;
}

View File

@ -1,7 +1,7 @@
#include "ZipFile.h"
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <miniz.h>
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
@ -243,7 +243,7 @@ bool ZipFile::loadZipDetails() {
}
bool ZipFile::open() {
if (!SdMan.openFileForRead("ZIP", filePath, file)) {
if (!HAL_STORAGE.openFileForRead("ZIP", filePath, file)) {
return false;
}
return true;

0
lib/hal/HalStorage.cpp Normal file
View File

49
lib/hal/HalStorage.h Normal file
View File

@ -0,0 +1,49 @@
#pragma once
#include <SDCardManager.h>
#include <vector>
class HalStorage {
public:
HalStorage();
bool begin();
bool ready() const;
std::vector<String> listFiles(const char* path = "/", int maxFiles = 200);
// Read the entire file at `path` into a String. Returns empty string on failure.
String readFile(const char* path);
// Low-memory helpers:
// Stream the file contents to a `Print` (e.g. `Serial`, or any `Print`-derived object).
// Returns true on success, false on failure.
bool readFileToStream(const char* path, Print& out, size_t chunkSize = 256);
// Read up to `bufferSize-1` bytes into `buffer`, null-terminating it. Returns bytes read.
size_t readFileToBuffer(const char* path, char* buffer, size_t bufferSize, size_t maxBytes = 0);
// Write a string to `path` on the SD card. Overwrites existing file.
// Returns true on success.
bool writeFile(const char* path, const String& content);
// Ensure a directory exists, creating it if necessary. Returns true on success.
bool ensureDirectoryExists(const char* path);
FsFile open(const char* path, const oflag_t oflag = O_RDONLY);
bool mkdir(const char* path, const bool pFlag = true);
bool exists(const char* path);
bool remove(const char* path);
bool rmdir(const char* path);
bool openFileForRead(const char* moduleName, const char* path, FsFile& file);
bool openFileForRead(const char* moduleName, const std::string& path, FsFile& file);
bool openFileForRead(const char* moduleName, const String& path, FsFile& file);
bool openFileForWrite(const char* moduleName, const char* path, FsFile& file);
bool openFileForWrite(const char* moduleName, const std::string& path, FsFile& file);
bool openFileForWrite(const char* moduleName, const String& path, FsFile& file);
bool removeDir(const char* path);
static HalStorage& getInstance() { return instance; }
private:
static HalStorage instance;
bool initialized = false;
SdFat sd;
};
#define HAL_STORAGE HalStorage::getInstance()

View File

@ -1,7 +1,7 @@
#include "CrossPointSettings.h"
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
#include <cstring>
@ -20,10 +20,10 @@ constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
bool CrossPointSettings::saveToFile() const {
// Make sure the directory exists
SdMan.mkdir("/.crosspoint");
HAL_STORAGE.mkdir("/.crosspoint");
FsFile outputFile;
if (!SdMan.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) {
if (!HAL_STORAGE.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) {
return false;
}
@ -57,7 +57,7 @@ bool CrossPointSettings::saveToFile() const {
bool CrossPointSettings::loadFromFile() {
FsFile inputFile;
if (!SdMan.openFileForRead("CPS", SETTINGS_FILE, inputFile)) {
if (!HAL_STORAGE.openFileForRead("CPS", SETTINGS_FILE, inputFile)) {
return false;
}

View File

@ -1,7 +1,7 @@
#include "CrossPointState.h"
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
namespace {
@ -13,7 +13,7 @@ CrossPointState CrossPointState::instance;
bool CrossPointState::saveToFile() const {
FsFile outputFile;
if (!SdMan.openFileForWrite("CPS", STATE_FILE, outputFile)) {
if (!HAL_STORAGE.openFileForWrite("CPS", STATE_FILE, outputFile)) {
return false;
}
@ -26,7 +26,7 @@ bool CrossPointState::saveToFile() const {
bool CrossPointState::loadFromFile() {
FsFile inputFile;
if (!SdMan.openFileForRead("CPS", STATE_FILE, inputFile)) {
if (!HAL_STORAGE.openFileForRead("CPS", STATE_FILE, inputFile)) {
return false;
}

View File

@ -1,7 +1,7 @@
#include "RecentBooksStore.h"
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
#include <algorithm>
@ -34,10 +34,10 @@ void RecentBooksStore::addBook(const std::string& path) {
bool RecentBooksStore::saveToFile() const {
// Make sure the directory exists
SdMan.mkdir("/.crosspoint");
HAL_STORAGE.mkdir("/.crosspoint");
FsFile outputFile;
if (!SdMan.openFileForWrite("RBS", RECENT_BOOKS_FILE, outputFile)) {
if (!HAL_STORAGE.openFileForWrite("RBS", RECENT_BOOKS_FILE, outputFile)) {
return false;
}
@ -56,7 +56,7 @@ bool RecentBooksStore::saveToFile() const {
bool RecentBooksStore::loadFromFile() {
FsFile inputFile;
if (!SdMan.openFileForRead("RBS", RECENT_BOOKS_FILE, inputFile)) {
if (!HAL_STORAGE.openFileForRead("RBS", RECENT_BOOKS_FILE, inputFile)) {
return false;
}

View File

@ -1,7 +1,7 @@
#include "WifiCredentialStore.h"
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
// Initialize the static instance
@ -29,10 +29,10 @@ void WifiCredentialStore::obfuscate(std::string& data) const {
bool WifiCredentialStore::saveToFile() const {
// Make sure the directory exists
SdMan.mkdir("/.crosspoint");
HAL_STORAGE.mkdir("/.crosspoint");
FsFile file;
if (!SdMan.openFileForWrite("WCS", WIFI_FILE, file)) {
if (!HAL_STORAGE.openFileForWrite("WCS", WIFI_FILE, file)) {
return false;
}
@ -60,7 +60,7 @@ bool WifiCredentialStore::saveToFile() const {
bool WifiCredentialStore::loadFromFile() {
FsFile file;
if (!SdMan.openFileForRead("WCS", WIFI_FILE, file)) {
if (!HAL_STORAGE.openFileForRead("WCS", WIFI_FILE, file)) {
return false;
}

View File

@ -2,7 +2,7 @@
#include <Epub.h>
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Txt.h>
#include <Xtc.h>
@ -47,7 +47,7 @@ void SleepActivity::renderPopup(const char* message) const {
void SleepActivity::renderCustomSleepScreen() const {
// Check if we have a /sleep directory
auto dir = SdMan.open("/sleep");
auto dir = HAL_STORAGE.open("/sleep");
if (dir && dir.isDirectory()) {
std::vector<std::string> files;
char name[500];
@ -90,7 +90,7 @@ void SleepActivity::renderCustomSleepScreen() const {
APP_STATE.saveToFile();
const auto filename = "/sleep/" + files[randomFileIndex];
FsFile file;
if (SdMan.openFileForRead("SLP", filename, file)) {
if (HAL_STORAGE.openFileForRead("SLP", filename, file)) {
Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
delay(100);
Bitmap bitmap(file, true);
@ -107,7 +107,7 @@ void SleepActivity::renderCustomSleepScreen() const {
// Look for sleep.bmp on the root of the sd card to determine if we should
// render a custom sleep screen instead of the default.
FsFile file;
if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) {
if (HAL_STORAGE.openFileForRead("SLP", "/sleep.bmp", file)) {
Bitmap bitmap(file, true);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis());
@ -257,7 +257,7 @@ void SleepActivity::renderCoverSleepScreen() const {
}
FsFile file;
if (SdMan.openFileForRead("SLP", coverBmpPath, file)) {
if (HAL_STORAGE.openFileForRead("SLP", coverBmpPath, file)) {
Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
renderBitmapSleepScreen(bitmap);

View File

@ -3,7 +3,7 @@
#include <Bitmap.h>
#include <Epub.h>
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Xtc.h>
#include <cstring>
@ -35,7 +35,7 @@ void HomeActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex();
// Check if we have a book to continue reading
hasContinueReading = !APP_STATE.openEpubPath.empty() && SdMan.exists(APP_STATE.openEpubPath.c_str());
hasContinueReading = !APP_STATE.openEpubPath.empty() && HAL_STORAGE.exists(APP_STATE.openEpubPath.c_str());
// Check if OPDS browser URL is configured
hasOpdsUrl = strlen(SETTINGS.opdsServerUrl) > 0;
@ -239,7 +239,7 @@ void HomeActivity::render() {
if (hasContinueReading && hasCoverImage && !coverBmpPath.empty() && !coverRendered) {
// First time: load cover from SD and render
FsFile file;
if (SdMan.openFileForRead("HOME", coverBmpPath, file)) {
if (HAL_STORAGE.openFileForRead("HOME", coverBmpPath, file)) {
Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
// Calculate position to center image within the book card

View File

@ -1,7 +1,7 @@
#include "MyLibraryActivity.h"
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <algorithm>
@ -80,7 +80,7 @@ void MyLibraryActivity::loadRecentBooks() {
}
// Skip if file no longer exists
if (!SdMan.exists(path.c_str())) {
if (!HAL_STORAGE.exists(path.c_str())) {
continue;
}
@ -99,7 +99,7 @@ void MyLibraryActivity::loadRecentBooks() {
void MyLibraryActivity::loadFiles() {
files.clear();
auto root = SdMan.open(basepath.c_str());
auto root = HAL_STORAGE.open(basepath.c_str());
if (!root || !root.isDirectory()) {
if (root) root.close();
return;

View File

@ -2,7 +2,7 @@
#include <GfxRenderer.h>
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <WiFi.h>
#include <cstring>
@ -592,7 +592,7 @@ void CalibreWirelessActivity::handleSendBook(const std::string& data) {
setStatus("Receiving: " + filename);
// Open file for writing
if (!SdMan.openFileForWrite("CAL", currentFilename.c_str(), currentFile)) {
if (!HAL_STORAGE.openFileForWrite("CAL", currentFilename.c_str(), currentFile)) {
setError("Failed to create file");
sendJsonResponse(OpCode::ERROR, "{\"message\":\"Failed to create file\"}");
return;

View File

@ -1,5 +1,5 @@
#pragma once
#include <SDCardManager.h>
#include <HalStorage.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <freertos/FreeRTOS.h>

View File

@ -3,7 +3,7 @@
#include <Epub/Page.h>
#include <FsHelpers.h>
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include "CrossPointSettings.h"
#include "CrossPointState.h"
@ -55,7 +55,7 @@ void EpubReaderActivity::onEnter() {
epub->setupCacheDir();
FsFile f;
if (SdMan.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
if (HAL_STORAGE.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
if (f.read(data, 4) == 4) {
currentSpineIndex = data[0] + (data[1] << 8);
@ -375,7 +375,7 @@ void EpubReaderActivity::renderScreen() {
}
FsFile f;
if (SdMan.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
if (HAL_STORAGE.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
data[0] = currentSpineIndex & 0xFF;
data[1] = (currentSpineIndex >> 8) & 0xFF;

View File

@ -28,7 +28,7 @@ bool ReaderActivity::isTxtFile(const std::string& path) {
}
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SdMan.exists(path.c_str())) {
if (!HAL_STORAGE.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
@ -43,7 +43,7 @@ std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
}
std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
if (!SdMan.exists(path.c_str())) {
if (!HAL_STORAGE.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}
@ -58,7 +58,7 @@ std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
}
std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
if (!SdMan.exists(path.c_str())) {
if (!HAL_STORAGE.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr;
}

View File

@ -1,7 +1,7 @@
#include "TxtReaderActivity.h"
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <Serialization.h>
#include <Utf8.h>
@ -538,7 +538,7 @@ void TxtReaderActivity::renderStatusBar(const int orientedMarginRight, const int
void TxtReaderActivity::saveProgress() const {
FsFile f;
if (SdMan.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) {
if (HAL_STORAGE.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
data[0] = currentPage & 0xFF;
data[1] = (currentPage >> 8) & 0xFF;
@ -551,7 +551,7 @@ void TxtReaderActivity::saveProgress() const {
void TxtReaderActivity::loadProgress() {
FsFile f;
if (SdMan.openFileForRead("TRS", txt->getCachePath() + "/progress.bin", f)) {
if (HAL_STORAGE.openFileForRead("TRS", txt->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
if (f.read(data, 4) == 4) {
currentPage = data[0] + (data[1] << 8);
@ -582,7 +582,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
std::string cachePath = txt->getCachePath() + "/index.bin";
FsFile f;
if (!SdMan.openFileForRead("TRS", cachePath, f)) {
if (!HAL_STORAGE.openFileForRead("TRS", cachePath, f)) {
Serial.printf("[%lu] [TRS] No page index cache found\n", millis());
return false;
}
@ -674,7 +674,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
void TxtReaderActivity::savePageIndexCache() const {
std::string cachePath = txt->getCachePath() + "/index.bin";
FsFile f;
if (!SdMan.openFileForWrite("TRS", cachePath, f)) {
if (!HAL_STORAGE.openFileForWrite("TRS", cachePath, f)) {
Serial.printf("[%lu] [TRS] Failed to save page index cache\n", millis());
return;
}

View File

@ -9,7 +9,7 @@
#include <FsHelpers.h>
#include <GfxRenderer.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include "CrossPointSettings.h"
#include "CrossPointState.h"
@ -362,7 +362,7 @@ void XtcReaderActivity::renderPage() {
void XtcReaderActivity::saveProgress() const {
FsFile f;
if (SdMan.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
if (HAL_STORAGE.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
data[0] = currentPage & 0xFF;
data[1] = (currentPage >> 8) & 0xFF;
@ -375,7 +375,7 @@ void XtcReaderActivity::saveProgress() const {
void XtcReaderActivity::loadProgress() {
FsFile f;
if (SdMan.openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) {
if (HAL_STORAGE.openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
if (f.read(data, 4) == 4) {
currentPage = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);

View File

@ -2,7 +2,7 @@
#include <GfxRenderer.h>
#include <HardwareSerial.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include "MappedInputManager.h"
#include "fontIds.h"
@ -106,7 +106,7 @@ void ClearCacheActivity::clearCache() {
Serial.printf("[%lu] [CLEAR_CACHE] Clearing cache...\n", millis());
// Open .crosspoint directory
auto root = SdMan.open("/.crosspoint");
auto root = HAL_STORAGE.open("/.crosspoint");
if (!root || !root.isDirectory()) {
Serial.printf("[%lu] [CLEAR_CACHE] Failed to open cache directory\n", millis());
if (root) root.close();
@ -131,7 +131,7 @@ void ClearCacheActivity::clearCache() {
file.close(); // Close before attempting to delete
if (SdMan.removeDir(fullPath.c_str())) {
if (HAL_STORAGE.removeDir(fullPath.c_str())) {
clearedCount++;
} else {
Serial.printf("[%lu] [CLEAR_CACHE] Failed to remove: %s\n", millis(), fullPath.c_str());

View File

@ -3,7 +3,7 @@
#include <Epub.h>
#include <GfxRenderer.h>
#include <InputManager.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <SPI.h>
#include <builtinFonts/all.h>
@ -311,7 +311,7 @@ void setup() {
// SD Card Initialization
// We need 6 open files concurrently when parsing a new chapter
if (!SdMan.begin()) {
if (!HAL_STORAGE.begin()) {
Serial.printf("[%lu] [ ] SD card initialization failed\n", millis());
setupDisplayAndFonts();
exitActivity();

View File

@ -3,7 +3,7 @@
#include <ArduinoJson.h>
#include <Epub.h>
#include <FsHelpers.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <WiFi.h>
#include <esp_task_wdt.h>
@ -231,7 +231,7 @@ void CrossPointWebServer::handleStatus() const {
}
void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const {
FsFile root = SdMan.open(path);
FsFile root = HAL_STORAGE.open(path);
if (!root) {
Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path);
return;
@ -441,15 +441,15 @@ void CrossPointWebServer::handleUpload() const {
// Check if file already exists - SD operations can be slow
esp_task_wdt_reset();
if (SdMan.exists(filePath.c_str())) {
if (HAL_STORAGE.exists(filePath.c_str())) {
Serial.printf("[%lu] [WEB] [UPLOAD] Overwriting existing file: %s\n", millis(), filePath.c_str());
esp_task_wdt_reset();
SdMan.remove(filePath.c_str());
HAL_STORAGE.remove(filePath.c_str());
}
// Open file for writing - this can be slow due to FAT cluster allocation
esp_task_wdt_reset();
if (!SdMan.openFileForWrite("WEB", filePath, uploadFile)) {
if (!HAL_STORAGE.openFileForWrite("WEB", filePath, uploadFile)) {
uploadError = "Failed to create file on SD card";
Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str());
return;
@ -527,7 +527,7 @@ void CrossPointWebServer::handleUpload() const {
String filePath = uploadPath;
if (!filePath.endsWith("/")) filePath += "/";
filePath += uploadFileName;
SdMan.remove(filePath.c_str());
HAL_STORAGE.remove(filePath.c_str());
}
uploadError = "Upload aborted";
Serial.printf("[%lu] [WEB] Upload aborted\n", millis());
@ -578,13 +578,13 @@ void CrossPointWebServer::handleCreateFolder() const {
Serial.printf("[%lu] [WEB] Creating folder: %s\n", millis(), folderPath.c_str());
// Check if already exists
if (SdMan.exists(folderPath.c_str())) {
if (HAL_STORAGE.exists(folderPath.c_str())) {
server->send(400, "text/plain", "Folder already exists");
return;
}
// Create the folder
if (SdMan.mkdir(folderPath.c_str())) {
if (HAL_STORAGE.mkdir(folderPath.c_str())) {
Serial.printf("[%lu] [WEB] Folder created successfully: %s\n", millis(), folderPath.c_str());
server->send(200, "text/plain", "Folder created: " + folderName);
} else {
@ -634,7 +634,7 @@ void CrossPointWebServer::handleDelete() const {
}
// Check if item exists
if (!SdMan.exists(itemPath.c_str())) {
if (!HAL_STORAGE.exists(itemPath.c_str())) {
Serial.printf("[%lu] [WEB] Delete failed - item not found: %s\n", millis(), itemPath.c_str());
server->send(404, "text/plain", "Item not found");
return;
@ -646,7 +646,7 @@ void CrossPointWebServer::handleDelete() const {
if (itemType == "folder") {
// For folders, try to remove (will fail if not empty)
FsFile dir = SdMan.open(itemPath.c_str());
FsFile dir = HAL_STORAGE.open(itemPath.c_str());
if (dir && dir.isDirectory()) {
// Check if folder is empty
FsFile entry = dir.openNextFile();
@ -660,10 +660,10 @@ void CrossPointWebServer::handleDelete() const {
}
dir.close();
}
success = SdMan.rmdir(itemPath.c_str());
success = HAL_STORAGE.rmdir(itemPath.c_str());
} else {
// For files, use remove
success = SdMan.remove(itemPath.c_str());
success = HAL_STORAGE.remove(itemPath.c_str());
}
if (success) {
@ -699,7 +699,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
String filePath = wsUploadPath;
if (!filePath.endsWith("/")) filePath += "/";
filePath += wsUploadFileName;
SdMan.remove(filePath.c_str());
HAL_STORAGE.remove(filePath.c_str());
Serial.printf("[%lu] [WS] Deleted incomplete upload: %s\n", millis(), filePath.c_str());
}
wsUploadInProgress = false;
@ -743,13 +743,13 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
// Check if file exists and remove it
esp_task_wdt_reset();
if (SdMan.exists(filePath.c_str())) {
SdMan.remove(filePath.c_str());
if (HAL_STORAGE.exists(filePath.c_str())) {
HAL_STORAGE.remove(filePath.c_str());
}
// Open file for writing
esp_task_wdt_reset();
if (!SdMan.openFileForWrite("WS", filePath, wsUploadFile)) {
if (!HAL_STORAGE.openFileForWrite("WS", filePath, wsUploadFile)) {
wsServer->sendTXT(num, "ERROR:Failed to create file");
wsUploadInProgress = false;
return;

View File

@ -83,13 +83,13 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
Serial.printf("[%lu] [HTTP] Content-Length: %zu\n", millis(), contentLength);
// Remove existing file if present
if (SdMan.exists(destPath.c_str())) {
SdMan.remove(destPath.c_str());
if (HAL_STORAGE.exists(destPath.c_str())) {
HAL_STORAGE.remove(destPath.c_str());
}
// Open file for writing
FsFile file;
if (!SdMan.openFileForWrite("HTTP", destPath.c_str(), file)) {
if (!HAL_STORAGE.openFileForWrite("HTTP", destPath.c_str(), file)) {
Serial.printf("[%lu] [HTTP] Failed to open file for writing\n", millis());
http.end();
return FILE_ERROR;
@ -100,7 +100,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
if (!stream) {
Serial.printf("[%lu] [HTTP] Failed to get stream\n", millis());
file.close();
SdMan.remove(destPath.c_str());
HAL_STORAGE.remove(destPath.c_str());
http.end();
return HTTP_ERROR;
}
@ -128,7 +128,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
if (written != bytesRead) {
Serial.printf("[%lu] [HTTP] Write failed: wrote %zu of %zu bytes\n", millis(), written, bytesRead);
file.close();
SdMan.remove(destPath.c_str());
HAL_STORAGE.remove(destPath.c_str());
http.end();
return FILE_ERROR;
}
@ -148,7 +148,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
// Verify download size if known
if (contentLength > 0 && downloaded != contentLength) {
Serial.printf("[%lu] [HTTP] Size mismatch: got %zu, expected %zu\n", millis(), downloaded, contentLength);
SdMan.remove(destPath.c_str());
HAL_STORAGE.remove(destPath.c_str());
return HTTP_ERROR;
}

View File

@ -1,5 +1,5 @@
#pragma once
#include <SDCardManager.h>
#include <HalStorage.h>
#include <functional>
#include <string>