From 6345861b12c59e6deb06d133fbecf6ee61ae8c8f Mon Sep 17 00:00:00 2001 From: Dave Allie Date: Mon, 29 Dec 2025 21:23:25 +1100 Subject: [PATCH] Add exFAT support --- lib/Epub/Epub.cpp | 40 +++++----- lib/Epub/Epub.h | 2 + lib/Epub/Epub/BookMetadataCache.cpp | 31 ++++---- lib/Epub/Epub/BookMetadataCache.h | 16 ++-- lib/Epub/Epub/Page.cpp | 8 +- lib/Epub/Epub/Page.h | 12 +-- lib/Epub/Epub/Section.cpp | 31 ++++---- lib/Epub/Epub/Section.h | 2 +- lib/Epub/Epub/blocks/TextBlock.cpp | 4 +- lib/Epub/Epub/blocks/TextBlock.h | 6 +- .../Epub/parsers/ChapterHtmlSlimParser.cpp | 6 +- lib/Epub/Epub/parsers/ContentOpfParser.cpp | 8 +- lib/Epub/Epub/parsers/ContentOpfParser.h | 2 +- lib/FsHelpers/FsHelpers.cpp | 74 ------------------- lib/FsHelpers/FsHelpers.h | 9 +-- lib/GfxRenderer/Bitmap.cpp | 10 +-- lib/GfxRenderer/Bitmap.h | 10 +-- lib/GfxRenderer/GfxRenderer.h | 1 - lib/JpegToBmpConverter/JpegToBmpConverter.cpp | 6 +- lib/JpegToBmpConverter/JpegToBmpConverter.h | 6 +- lib/Serialization/Serialization.h | 12 +-- lib/Xtc/Xtc.cpp | 18 ++--- lib/Xtc/Xtc/XtcParser.cpp | 7 +- lib/Xtc/Xtc/XtcParser.h | 4 +- lib/ZipFile/ZipFile.cpp | 56 +++++++------- lib/ZipFile/ZipFile.h | 4 +- open-x4-sdk | 2 +- platformio.ini | 2 + src/CrossPointSettings.cpp | 13 ++-- src/CrossPointState.cpp | 10 +-- src/WifiCredentialStore.cpp | 13 ++-- src/activities/Activity.h | 3 +- src/activities/boot_sleep/SleepActivity.cpp | 26 ++++--- src/activities/home/HomeActivity.cpp | 6 +- .../network/CrossPointWebServerActivity.cpp | 2 +- .../network/NetworkModeSelectionActivity.cpp | 2 +- .../network/WifiSelectionActivity.cpp | 1 + src/activities/reader/EpubReaderActivity.cpp | 11 +-- .../EpubReaderChapterSelectionActivity.cpp | 3 +- .../reader/FileSelectionActivity.cpp | 16 ++-- src/activities/reader/ReaderActivity.cpp | 6 +- src/activities/reader/XtcReaderActivity.cpp | 12 +-- src/activities/settings/OtaUpdateActivity.cpp | 2 +- src/activities/settings/SettingsActivity.cpp | 2 +- src/activities/util/KeyboardEntryActivity.cpp | 1 + src/main.cpp | 5 +- src/network/CrossPointWebServer.cpp | 34 +++++---- 47 files changed, 238 insertions(+), 319 deletions(-) diff --git a/lib/Epub/Epub.cpp b/lib/Epub/Epub.cpp index 941e11b..1373b41 100644 --- a/lib/Epub/Epub.cpp +++ b/lib/Epub/Epub.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include "Epub/parsers/ContainerParser.h" @@ -94,13 +94,13 @@ bool Epub::parseTocNcxFile() const { Serial.printf("[%lu] [EBP] Parsing toc ncx file: %s\n", millis(), tocNcxItem.c_str()); const auto tmpNcxPath = getCachePath() + "/toc.ncx"; - File tempNcxFile; - if (!FsHelpers::openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) { + FsFile tempNcxFile; + if (!SdMan.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) { return false; } readItemContentsToStream(tocNcxItem, tempNcxFile, 1024); tempNcxFile.close(); - if (!FsHelpers::openFileForRead("EBP", tmpNcxPath, tempNcxFile)) { + if (!SdMan.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) { return false; } const auto ncxSize = tempNcxFile.size(); @@ -132,7 +132,7 @@ bool Epub::parseTocNcxFile() const { free(ncxBuffer); tempNcxFile.close(); - SD.remove(tmpNcxPath.c_str()); + SdMan.remove(tmpNcxPath.c_str()); Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis()); return true; @@ -218,12 +218,12 @@ bool Epub::load() { } bool Epub::clearCache() const { - if (!SD.exists(cachePath.c_str())) { + if (!SdMan.exists(cachePath.c_str())) { Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis()); return true; } - if (!FsHelpers::removeDir(cachePath.c_str())) { + if (!SdMan.removeDir(cachePath.c_str())) { Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis()); return false; } @@ -233,17 +233,11 @@ bool Epub::clearCache() const { } void Epub::setupCacheDir() const { - if (SD.exists(cachePath.c_str())) { + if (SdMan.exists(cachePath.c_str())) { return; } - // Loop over each segment of the cache path and create directories as needed - for (size_t i = 1; i < cachePath.length(); i++) { - if (cachePath[i] == '/') { - SD.mkdir(cachePath.substr(0, i).c_str()); - } - } - SD.mkdir(cachePath.c_str()); + SdMan.mkdir(cachePath.c_str()); } const std::string& Epub::getCachePath() const { return cachePath; } @@ -263,7 +257,7 @@ std::string Epub::getCoverBmpPath() const { return cachePath + "/cover.bmp"; } bool Epub::generateCoverBmp() const { // Already generated, return true - if (SD.exists(getCoverBmpPath().c_str())) { + if (SdMan.exists(getCoverBmpPath().c_str())) { return true; } @@ -283,30 +277,30 @@ bool Epub::generateCoverBmp() const { Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image\n", millis()); const auto coverJpgTempPath = getCachePath() + "/.cover.jpg"; - File coverJpg; - if (!FsHelpers::openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { + FsFile coverJpg; + if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { return false; } readItemContentsToStream(coverImageHref, coverJpg, 1024); coverJpg.close(); - if (!FsHelpers::openFileForRead("EBP", coverJpgTempPath, coverJpg)) { + if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { return false; } - File coverBmp; - if (!FsHelpers::openFileForWrite("EBP", getCoverBmpPath(), coverBmp)) { + FsFile coverBmp; + if (!SdMan.openFileForWrite("EBP", getCoverBmpPath(), coverBmp)) { coverJpg.close(); return false; } const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp); coverJpg.close(); coverBmp.close(); - SD.remove(coverJpgTempPath.c_str()); + SdMan.remove(coverJpgTempPath.c_str()); if (!success) { Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis()); - SD.remove(getCoverBmpPath().c_str()); + SdMan.remove(getCoverBmpPath().c_str()); } Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no"); return success; diff --git a/lib/Epub/Epub.h b/lib/Epub/Epub.h index c785008..8ce1843 100644 --- a/lib/Epub/Epub.h +++ b/lib/Epub/Epub.h @@ -1,5 +1,7 @@ #pragma once +#include + #include #include #include diff --git a/lib/Epub/Epub/BookMetadataCache.cpp b/lib/Epub/Epub/BookMetadataCache.cpp index 8fcee28..f42de94 100644 --- a/lib/Epub/Epub/BookMetadataCache.cpp +++ b/lib/Epub/Epub/BookMetadataCache.cpp @@ -1,7 +1,6 @@ #include "BookMetadataCache.h" #include -#include #include #include @@ -30,7 +29,7 @@ bool BookMetadataCache::beginContentOpfPass() { Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis()); // Open spine file for writing - return FsHelpers::openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile); + return SdMan.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile); } bool BookMetadataCache::endContentOpfPass() { @@ -42,10 +41,10 @@ bool BookMetadataCache::beginTocPass() { Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis()); // Open spine file for reading - if (!FsHelpers::openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { + if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { return false; } - if (!FsHelpers::openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) { + if (!SdMan.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) { spineFile.close(); return false; } @@ -71,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 (!FsHelpers::openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) { + if (!SdMan.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) { return false; } - if (!FsHelpers::openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { + if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { bookFile.close(); return false; } - if (!FsHelpers::openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) { + if (!SdMan.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) { bookFile.close(); spineFile.close(); return false; @@ -195,16 +194,16 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta } bool BookMetadataCache::cleanupTmpFiles() const { - if (SD.exists((cachePath + tmpSpineBinFile).c_str())) { - SD.remove((cachePath + tmpSpineBinFile).c_str()); + if (SdMan.exists((cachePath + tmpSpineBinFile).c_str())) { + SdMan.remove((cachePath + tmpSpineBinFile).c_str()); } - if (SD.exists((cachePath + tmpTocBinFile).c_str())) { - SD.remove((cachePath + tmpTocBinFile).c_str()); + if (SdMan.exists((cachePath + tmpTocBinFile).c_str())) { + SdMan.remove((cachePath + tmpTocBinFile).c_str()); } return true; } -size_t BookMetadataCache::writeSpineEntry(File& file, const SpineEntry& entry) const { +size_t BookMetadataCache::writeSpineEntry(FsFile& file, const SpineEntry& entry) const { const auto pos = file.position(); serialization::writeString(file, entry.href); serialization::writePod(file, entry.cumulativeSize); @@ -212,7 +211,7 @@ size_t BookMetadataCache::writeSpineEntry(File& file, const SpineEntry& entry) c return pos; } -size_t BookMetadataCache::writeTocEntry(File& file, const TocEntry& entry) const { +size_t BookMetadataCache::writeTocEntry(FsFile& file, const TocEntry& entry) const { const auto pos = file.position(); serialization::writeString(file, entry.title); serialization::writeString(file, entry.href); @@ -267,7 +266,7 @@ void BookMetadataCache::createTocEntry(const std::string& title, const std::stri /* ============= READING / LOADING FUNCTIONS ================ */ bool BookMetadataCache::load() { - if (!FsHelpers::openFileForRead("BMC", cachePath + bookBinFile, bookFile)) { + if (!SdMan.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) { return false; } @@ -330,7 +329,7 @@ BookMetadataCache::TocEntry BookMetadataCache::getTocEntry(const int index) { return readTocEntry(bookFile); } -BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(File& file) const { +BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(FsFile& file) const { SpineEntry entry; serialization::readString(file, entry.href); serialization::readPod(file, entry.cumulativeSize); @@ -338,7 +337,7 @@ BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(File& file) cons return entry; } -BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(File& file) const { +BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(FsFile& file) const { TocEntry entry; serialization::readString(file, entry.title); serialization::readString(file, entry.href); diff --git a/lib/Epub/Epub/BookMetadataCache.h b/lib/Epub/Epub/BookMetadataCache.h index 7f9f419..06597a2 100644 --- a/lib/Epub/Epub/BookMetadataCache.h +++ b/lib/Epub/Epub/BookMetadataCache.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include @@ -46,15 +46,15 @@ class BookMetadataCache { bool loaded; bool buildMode; - File bookFile; + FsFile bookFile; // Temp file handles during build - File spineFile; - File tocFile; + FsFile spineFile; + FsFile tocFile; - size_t writeSpineEntry(File& file, const SpineEntry& entry) const; - size_t writeTocEntry(File& file, const TocEntry& entry) const; - SpineEntry readSpineEntry(File& file) const; - TocEntry readTocEntry(File& file) const; + size_t writeSpineEntry(FsFile& file, const SpineEntry& entry) const; + size_t writeTocEntry(FsFile& file, const TocEntry& entry) const; + SpineEntry readSpineEntry(FsFile& file) const; + TocEntry readTocEntry(FsFile& file) const; public: BookMetadata coreMetadata; diff --git a/lib/Epub/Epub/Page.cpp b/lib/Epub/Epub/Page.cpp index c50fe30..65ce569 100644 --- a/lib/Epub/Epub/Page.cpp +++ b/lib/Epub/Epub/Page.cpp @@ -7,7 +7,7 @@ void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset block->render(renderer, fontId, xPos + xOffset, yPos + yOffset); } -bool PageLine::serialize(File& file) { +bool PageLine::serialize(FsFile& file) { serialization::writePod(file, xPos); serialization::writePod(file, yPos); @@ -15,7 +15,7 @@ bool PageLine::serialize(File& file) { return block->serialize(file); } -std::unique_ptr PageLine::deserialize(File& file) { +std::unique_ptr PageLine::deserialize(FsFile& file) { int16_t xPos; int16_t yPos; serialization::readPod(file, xPos); @@ -31,7 +31,7 @@ void Page::render(GfxRenderer& renderer, const int fontId, const int xOffset, co } } -bool Page::serialize(File& file) const { +bool Page::serialize(FsFile& file) const { const uint32_t count = elements.size(); serialization::writePod(file, count); @@ -46,7 +46,7 @@ bool Page::serialize(File& file) const { return true; } -std::unique_ptr Page::deserialize(File& file) { +std::unique_ptr Page::deserialize(FsFile& file) { auto page = std::unique_ptr(new Page()); uint32_t count; diff --git a/lib/Epub/Epub/Page.h b/lib/Epub/Epub/Page.h index 841ef6b..2006194 100644 --- a/lib/Epub/Epub/Page.h +++ b/lib/Epub/Epub/Page.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include @@ -18,7 +18,7 @@ class PageElement { explicit PageElement(const int16_t xPos, const int16_t yPos) : xPos(xPos), yPos(yPos) {} virtual ~PageElement() = default; virtual void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) = 0; - virtual bool serialize(File& file) = 0; + virtual bool serialize(FsFile& file) = 0; }; // a line from a block element @@ -29,8 +29,8 @@ class PageLine final : public PageElement { PageLine(std::shared_ptr block, const int16_t xPos, const int16_t yPos) : PageElement(xPos, yPos), block(std::move(block)) {} void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override; - bool serialize(File& file) override; - static std::unique_ptr deserialize(File& file); + bool serialize(FsFile& file) override; + static std::unique_ptr deserialize(FsFile& file); }; class Page { @@ -38,6 +38,6 @@ class Page { // the list of block index and line numbers on this page std::vector> elements; void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const; - bool serialize(File& file) const; - static std::unique_ptr deserialize(File& file); + bool serialize(FsFile& file) const; + static std::unique_ptr deserialize(FsFile& file); }; diff --git a/lib/Epub/Epub/Section.cpp b/lib/Epub/Epub/Section.cpp index 9cc19ea..e7a7637 100644 --- a/lib/Epub/Epub/Section.cpp +++ b/lib/Epub/Epub/Section.cpp @@ -1,7 +1,6 @@ #include "Section.h" -#include -#include +#include #include #include "Page.h" @@ -52,7 +51,7 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing, const int viewportWidth, const int viewportHeight) { - if (!FsHelpers::openFileForRead("SCT", filePath, file)) { + if (!SdMan.openFileForRead("SCT", filePath, file)) { return false; } @@ -94,12 +93,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 (!SD.exists(filePath.c_str())) { + if (!SdMan.exists(filePath.c_str())) { Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis()); return true; } - if (!SD.remove(filePath.c_str())) { + if (!SdMan.remove(filePath.c_str())) { Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis()); return false; } @@ -126,12 +125,12 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c } // Remove any incomplete file from previous attempt before retrying - if (SD.exists(tmpHtmlPath.c_str())) { - SD.remove(tmpHtmlPath.c_str()); + if (SdMan.exists(tmpHtmlPath.c_str())) { + SdMan.remove(tmpHtmlPath.c_str()); } - File tmpHtml; - if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { + FsFile tmpHtml; + if (!SdMan.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { continue; } success = epub->readItemContentsToStream(localPath, tmpHtml, 1024); @@ -139,8 +138,8 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c tmpHtml.close(); // If streaming failed, remove the incomplete file immediately - if (!success && SD.exists(tmpHtmlPath.c_str())) { - SD.remove(tmpHtmlPath.c_str()); + if (!success && SdMan.exists(tmpHtmlPath.c_str())) { + SdMan.remove(tmpHtmlPath.c_str()); Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis()); } } @@ -157,7 +156,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c progressSetupFn(); } - if (!FsHelpers::openFileForWrite("SCT", filePath, file)) { + if (!SdMan.openFileForWrite("SCT", filePath, file)) { return false; } writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight); @@ -169,11 +168,11 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c progressFn); success = visitor.parseAndBuildPages(); - SD.remove(tmpHtmlPath.c_str()); + SdMan.remove(tmpHtmlPath.c_str()); if (!success) { Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis()); file.close(); - SD.remove(filePath.c_str()); + SdMan.remove(filePath.c_str()); return false; } @@ -191,7 +190,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(); - SD.remove(filePath.c_str()); + SdMan.remove(filePath.c_str()); return false; } @@ -204,7 +203,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c } std::unique_ptr Section::loadPageFromSectionFile() { - if (!FsHelpers::openFileForRead("SCT", filePath, file)) { + if (!SdMan.openFileForRead("SCT", filePath, file)) { return nullptr; } diff --git a/lib/Epub/Epub/Section.h b/lib/Epub/Epub/Section.h index 93e0d6c..f48fe75 100644 --- a/lib/Epub/Epub/Section.h +++ b/lib/Epub/Epub/Section.h @@ -12,7 +12,7 @@ class Section { const int spineIndex; GfxRenderer& renderer; std::string filePath; - File file; + FsFile file; void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, int viewportWidth, int viewportHeight); diff --git a/lib/Epub/Epub/blocks/TextBlock.cpp b/lib/Epub/Epub/blocks/TextBlock.cpp index c20b37d..3119305 100644 --- a/lib/Epub/Epub/blocks/TextBlock.cpp +++ b/lib/Epub/Epub/blocks/TextBlock.cpp @@ -24,7 +24,7 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int } } -bool TextBlock::serialize(File& file) const { +bool TextBlock::serialize(FsFile& file) const { if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) { Serial.printf("[%lu] [TXB] Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), words.size(), wordXpos.size(), wordStyles.size()); @@ -43,7 +43,7 @@ bool TextBlock::serialize(File& file) const { return true; } -std::unique_ptr TextBlock::deserialize(File& file) { +std::unique_ptr TextBlock::deserialize(FsFile& file) { uint32_t wc; std::list words; std::list wordXpos; diff --git a/lib/Epub/Epub/blocks/TextBlock.h b/lib/Epub/Epub/blocks/TextBlock.h index 9dfde60..95d8884 100644 --- a/lib/Epub/Epub/blocks/TextBlock.h +++ b/lib/Epub/Epub/blocks/TextBlock.h @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include @@ -36,6 +36,6 @@ class TextBlock final : public Block { // given a renderer works out where to break the words into lines void render(const GfxRenderer& renderer, int fontId, int x, int y) const; BlockType getType() override { return TEXT_BLOCK; } - bool serialize(File& file) const; - static std::unique_ptr deserialize(File& file); + bool serialize(FsFile& file) const; + static std::unique_ptr deserialize(FsFile& file); }; diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index b2dc2c0..a2b6189 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -1,8 +1,8 @@ #include "ChapterHtmlSlimParser.h" -#include #include #include +#include #include #include "../Page.h" @@ -218,8 +218,8 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() { return false; } - File file; - if (!FsHelpers::openFileForRead("EHP", filepath, file)) { + FsFile file; + if (!SdMan.openFileForRead("EHP", filepath, file)) { XML_ParserFree(parser); return false; } diff --git a/lib/Epub/Epub/parsers/ContentOpfParser.cpp b/lib/Epub/Epub/parsers/ContentOpfParser.cpp index a62b2d0..ae964ce 100644 --- a/lib/Epub/Epub/parsers/ContentOpfParser.cpp +++ b/lib/Epub/Epub/parsers/ContentOpfParser.cpp @@ -35,8 +35,8 @@ ContentOpfParser::~ContentOpfParser() { if (tempItemStore) { tempItemStore.close(); } - if (SD.exists((cachePath + itemCacheFile).c_str())) { - SD.remove((cachePath + itemCacheFile).c_str()); + if (SdMan.exists((cachePath + itemCacheFile).c_str())) { + SdMan.remove((cachePath + itemCacheFile).c_str()); } } @@ -104,7 +104,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 (!FsHelpers::openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { + if (!SdMan.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()); @@ -114,7 +114,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 (!FsHelpers::openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { + if (!SdMan.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()); diff --git a/lib/Epub/Epub/parsers/ContentOpfParser.h b/lib/Epub/Epub/parsers/ContentOpfParser.h index 5415de6..2a7dd48 100644 --- a/lib/Epub/Epub/parsers/ContentOpfParser.h +++ b/lib/Epub/Epub/parsers/ContentOpfParser.h @@ -22,7 +22,7 @@ class ContentOpfParser final : public Print { XML_Parser parser = nullptr; ParserState state = START; BookMetadataCache* cache; - File tempItemStore; + FsFile tempItemStore; std::string coverItemId; static void startElement(void* userData, const XML_Char* name, const XML_Char** atts); diff --git a/lib/FsHelpers/FsHelpers.cpp b/lib/FsHelpers/FsHelpers.cpp index c8b59ce..4bd8fbf 100644 --- a/lib/FsHelpers/FsHelpers.cpp +++ b/lib/FsHelpers/FsHelpers.cpp @@ -1,81 +1,7 @@ #include "FsHelpers.h" -#include - #include -bool FsHelpers::openFileForRead(const char* moduleName, const char* path, File& file) { - if (!SD.exists(path)) { - Serial.printf("[%lu] [%s] File does not exist: %s\n", millis(), moduleName, path); - return false; - } - - file = SD.open(path, FILE_READ); - if (!file) { - Serial.printf("[%lu] [%s] Failed to open file for reading: %s\n", millis(), moduleName, path); - return false; - } - return true; -} - -bool FsHelpers::openFileForRead(const char* moduleName, const std::string& path, File& file) { - return openFileForRead(moduleName, path.c_str(), file); -} - -bool FsHelpers::openFileForRead(const char* moduleName, const String& path, File& file) { - return openFileForRead(moduleName, path.c_str(), file); -} - -bool FsHelpers::openFileForWrite(const char* moduleName, const char* path, File& file) { - file = SD.open(path, FILE_WRITE, true); - if (!file) { - Serial.printf("[%lu] [%s] Failed to open file for writing: %s\n", millis(), moduleName, path); - return false; - } - return true; -} - -bool FsHelpers::openFileForWrite(const char* moduleName, const std::string& path, File& file) { - return openFileForWrite(moduleName, path.c_str(), file); -} - -bool FsHelpers::openFileForWrite(const char* moduleName, const String& path, File& file) { - return openFileForWrite(moduleName, path.c_str(), file); -} - -bool FsHelpers::removeDir(const char* path) { - // 1. Open the directory - File dir = SD.open(path); - if (!dir) { - return false; - } - if (!dir.isDirectory()) { - return false; - } - - File file = dir.openNextFile(); - while (file) { - String filePath = path; - if (!filePath.endsWith("/")) { - filePath += "/"; - } - filePath += file.name(); - - if (file.isDirectory()) { - if (!removeDir(filePath.c_str())) { - return false; - } - } else { - if (!SD.remove(filePath.c_str())) { - return false; - } - } - file = dir.openNextFile(); - } - - return SD.rmdir(path); -} - std::string FsHelpers::normalisePath(const std::string& path) { std::vector components; std::string component; diff --git a/lib/FsHelpers/FsHelpers.h b/lib/FsHelpers/FsHelpers.h index 0dff145..5bb4218 100644 --- a/lib/FsHelpers/FsHelpers.h +++ b/lib/FsHelpers/FsHelpers.h @@ -1,14 +1,7 @@ #pragma once -#include +#include class FsHelpers { public: - static bool openFileForRead(const char* moduleName, const char* path, File& file); - static bool openFileForRead(const char* moduleName, const std::string& path, File& file); - static bool openFileForRead(const char* moduleName, const String& path, File& file); - static bool openFileForWrite(const char* moduleName, const char* path, File& file); - static bool openFileForWrite(const char* moduleName, const std::string& path, File& file); - static bool openFileForWrite(const char* moduleName, const String& path, File& file); - static bool removeDir(const char* path); static std::string normalisePath(const std::string& path); }; diff --git a/lib/GfxRenderer/Bitmap.cpp b/lib/GfxRenderer/Bitmap.cpp index a034c75..7c46df1 100644 --- a/lib/GfxRenderer/Bitmap.cpp +++ b/lib/GfxRenderer/Bitmap.cpp @@ -123,7 +123,7 @@ Bitmap::~Bitmap() { delete[] errorNextRow; } -uint16_t Bitmap::readLE16(File& f) { +uint16_t Bitmap::readLE16(FsFile& f) { const int c0 = f.read(); const int c1 = f.read(); const auto b0 = static_cast(c0 < 0 ? 0 : c0); @@ -131,7 +131,7 @@ uint16_t Bitmap::readLE16(File& f) { return static_cast(b0) | (static_cast(b1) << 8); } -uint32_t Bitmap::readLE32(File& f) { +uint32_t Bitmap::readLE32(FsFile& f) { const int c0 = f.read(); const int c1 = f.read(); const int c2 = f.read(); @@ -192,7 +192,7 @@ BmpReaderError Bitmap::parseHeaders() { const uint16_t bfType = readLE16(file); if (bfType != 0x4D42) return BmpReaderError::NotBMP; - file.seek(8, SeekCur); + file.seekCur(8); bfOffBits = readLE32(file); // --- DIB HEADER --- @@ -214,10 +214,10 @@ BmpReaderError Bitmap::parseHeaders() { // Allow BI_RGB (0) for all, and BI_BITFIELDS (3) for 32bpp which is common for BGRA masks. if (!(comp == 0 || (bpp == 32 && comp == 3))) return BmpReaderError::UnsupportedCompression; - file.seek(12, SeekCur); // biSizeImage, biXPelsPerMeter, biYPelsPerMeter + file.seekCur(12); // biSizeImage, biXPelsPerMeter, biYPelsPerMeter const uint32_t colorsUsed = readLE32(file); if (colorsUsed > 256u) return BmpReaderError::PaletteTooLarge; - file.seek(4, SeekCur); // biClrImportant + file.seekCur(4); // biClrImportant if (width <= 0 || height <= 0) return BmpReaderError::BadDimensions; diff --git a/lib/GfxRenderer/Bitmap.h b/lib/GfxRenderer/Bitmap.h index 744cb61..7e79964 100644 --- a/lib/GfxRenderer/Bitmap.h +++ b/lib/GfxRenderer/Bitmap.h @@ -1,6 +1,6 @@ #pragma once -#include +#include enum class BmpReaderError : uint8_t { Ok = 0, @@ -28,7 +28,7 @@ class Bitmap { public: static const char* errorToString(BmpReaderError err); - explicit Bitmap(File& file) : file(file) {} + explicit Bitmap(FsFile& file) : file(file) {} ~Bitmap(); BmpReaderError parseHeaders(); BmpReaderError readRow(uint8_t* data, uint8_t* rowBuffer, int rowY) const; @@ -40,10 +40,10 @@ class Bitmap { int getRowBytes() const { return rowBytes; } private: - static uint16_t readLE16(File& f); - static uint32_t readLE32(File& f); + static uint16_t readLE16(FsFile& f); + static uint32_t readLE32(FsFile& f); - File& file; + FsFile& file; int width = 0; int height = 0; bool topDown = false; diff --git a/lib/GfxRenderer/GfxRenderer.h b/lib/GfxRenderer/GfxRenderer.h index 241c76e..f6f5fe0 100644 --- a/lib/GfxRenderer/GfxRenderer.h +++ b/lib/GfxRenderer/GfxRenderer.h @@ -2,7 +2,6 @@ #include #include -#include #include diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp index 0a19701..9c61ef0 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp @@ -1,5 +1,7 @@ #include "JpegToBmpConverter.h" +#include +#include #include #include @@ -7,7 +9,7 @@ // Context structure for picojpeg callback struct JpegReadContext { - File& file; + FsFile& file; uint8_t buffer[512]; size_t bufferPos; size_t bufferFilled; @@ -426,7 +428,7 @@ unsigned char JpegToBmpConverter::jpegReadCallback(unsigned char* pBuf, const un } // Core function: Convert JPEG file to 2-bit BMP -bool JpegToBmpConverter::jpegFileToBmpStream(File& jpegFile, Print& bmpOut) { +bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut) { Serial.printf("[%lu] [JPG] Converting JPEG to BMP\n", millis()); // Setup context for picojpeg callback diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.h b/lib/JpegToBmpConverter/JpegToBmpConverter.h index 1cb76e5..f61bd8e 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.h +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.h @@ -1,7 +1,7 @@ #pragma once -#include - +class FsFile; +class Print; class ZipFile; class JpegToBmpConverter { @@ -11,5 +11,5 @@ class JpegToBmpConverter { unsigned char* pBytes_actually_read, void* pCallback_data); public: - static bool jpegFileToBmpStream(File& jpegFile, Print& bmpOut); + static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut); }; diff --git a/lib/Serialization/Serialization.h b/lib/Serialization/Serialization.h index e6bcbf2..afea564 100644 --- a/lib/Serialization/Serialization.h +++ b/lib/Serialization/Serialization.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include @@ -10,7 +10,7 @@ static void writePod(std::ostream& os, const T& value) { } template -static void writePod(File& file, const T& value) { +static void writePod(FsFile& file, const T& value) { file.write(reinterpret_cast(&value), sizeof(T)); } @@ -20,7 +20,7 @@ static void readPod(std::istream& is, T& value) { } template -static void readPod(File& file, T& value) { +static void readPod(FsFile& file, T& value) { file.read(reinterpret_cast(&value), sizeof(T)); } @@ -30,7 +30,7 @@ static void writeString(std::ostream& os, const std::string& s) { os.write(s.data(), len); } -static void writeString(File& file, const std::string& s) { +static void writeString(FsFile& file, const std::string& s) { const uint32_t len = s.size(); writePod(file, len); file.write(reinterpret_cast(s.data()), len); @@ -43,10 +43,10 @@ static void readString(std::istream& is, std::string& s) { is.read(&s[0], len); } -static void readString(File& file, std::string& s) { +static void readString(FsFile& file, std::string& s) { uint32_t len; readPod(file, len); s.resize(len); - file.read(reinterpret_cast(&s[0]), len); + file.read(&s[0], len); } } // namespace serialization diff --git a/lib/Xtc/Xtc.cpp b/lib/Xtc/Xtc.cpp index fe0b107..6ffbabb 100644 --- a/lib/Xtc/Xtc.cpp +++ b/lib/Xtc/Xtc.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include 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 (!SD.exists(cachePath.c_str())) { + if (!SdMan.exists(cachePath.c_str())) { Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis()); return true; } - if (!FsHelpers::removeDir(cachePath.c_str())) { + if (!SdMan.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 (SD.exists(cachePath.c_str())) { + if (SdMan.exists(cachePath.c_str())) { return; } // Create directories recursively for (size_t i = 1; i < cachePath.length(); i++) { if (cachePath[i] == '/') { - SD.mkdir(cachePath.substr(0, i).c_str()); + SdMan.mkdir(cachePath.substr(0, i).c_str()); } } - SD.mkdir(cachePath.c_str()); + SdMan.mkdir(cachePath.c_str()); } std::string Xtc::getTitle() const { @@ -91,7 +91,7 @@ std::string Xtc::getCoverBmpPath() const { return cachePath + "/cover.bmp"; } bool Xtc::generateCoverBmp() const { // Already generated - if (SD.exists(getCoverBmpPath().c_str())) { + if (SdMan.exists(getCoverBmpPath().c_str())) { return true; } @@ -142,8 +142,8 @@ bool Xtc::generateCoverBmp() const { } // Create BMP file - File coverBmp; - if (!FsHelpers::openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) { + FsFile coverBmp; + if (!SdMan.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) { Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis()); free(pageBuffer); return false; diff --git a/lib/Xtc/Xtc/XtcParser.cpp b/lib/Xtc/Xtc/XtcParser.cpp index a443f57..fbdbc55 100644 --- a/lib/Xtc/Xtc/XtcParser.cpp +++ b/lib/Xtc/Xtc/XtcParser.cpp @@ -9,6 +9,7 @@ #include #include +#include #include @@ -32,7 +33,7 @@ XtcError XtcParser::open(const char* filepath) { } // Open file - if (!FsHelpers::openFileForRead("XTC", filepath, m_file)) { + if (!SdMan.openFileForRead("XTC", filepath, m_file)) { m_lastError = XtcError::FILE_NOT_FOUND; return m_lastError; } @@ -297,8 +298,8 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex, } bool XtcParser::isValidXtcFile(const char* filepath) { - File file = SD.open(filepath, FILE_READ); - if (!file) { + FsFile file; + if (!SdMan.openFileForRead("XTC", filepath, file)) { return false; } diff --git a/lib/Xtc/Xtc/XtcParser.h b/lib/Xtc/Xtc/XtcParser.h index b0a402a..5d2340a 100644 --- a/lib/Xtc/Xtc/XtcParser.h +++ b/lib/Xtc/Xtc/XtcParser.h @@ -7,7 +7,7 @@ #pragma once -#include +#include #include #include @@ -77,7 +77,7 @@ class XtcParser { XtcError getLastError() const { return m_lastError; } private: - File m_file; + FsFile m_file; bool m_isOpen; XtcHeader m_header; std::vector m_pageTable; diff --git a/lib/ZipFile/ZipFile.cpp b/lib/ZipFile/ZipFile.cpp index 23cf0e8..2a97858 100644 --- a/lib/ZipFile/ZipFile.cpp +++ b/lib/ZipFile/ZipFile.cpp @@ -1,7 +1,7 @@ #include "ZipFile.h" -#include #include +#include #include bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) { @@ -49,29 +49,29 @@ bool ZipFile::loadAllFileStatSlims() { fileStatSlimCache.reserve(zipDetails.totalEntries); while (file.available()) { - file.read(reinterpret_cast(&sig), 4); + file.read(&sig, 4); if (sig != 0x02014b50) break; // End of list FileStatSlim fileStat = {}; - file.seek(6, SeekCur); - file.read(reinterpret_cast(&fileStat.method), 2); - file.seek(8, SeekCur); - file.read(reinterpret_cast(&fileStat.compressedSize), 4); - file.read(reinterpret_cast(&fileStat.uncompressedSize), 4); + file.seekCur(6); + file.read(&fileStat.method, 2); + file.seekCur(8); + file.read(&fileStat.compressedSize, 4); + file.read(&fileStat.uncompressedSize, 4); uint16_t nameLen, m, k; - file.read(reinterpret_cast(&nameLen), 2); - file.read(reinterpret_cast(&m), 2); - file.read(reinterpret_cast(&k), 2); - file.seek(8, SeekCur); - file.read(reinterpret_cast(&fileStat.localHeaderOffset), 4); - file.read(reinterpret_cast(itemName), nameLen); + file.read(&nameLen, 2); + file.read(&m, 2); + file.read(&k, 2); + file.seekCur(8); + file.read(&fileStat.localHeaderOffset, 4); + file.read(itemName, nameLen); itemName[nameLen] = '\0'; fileStatSlimCache.emplace(itemName, fileStat); // Skip the rest of this entry (extra field + comment) - file.seek(m + k, SeekCur); + file.seekCur(m + k); } if (!wasOpen) { @@ -109,21 +109,21 @@ bool ZipFile::loadFileStatSlim(const char* filename, FileStatSlim* fileStat) { bool found = false; while (file.available()) { - file.read(reinterpret_cast(&sig), 4); + file.read(&sig, 4); if (sig != 0x02014b50) break; // End of list - file.seek(6, SeekCur); - file.read(reinterpret_cast(&fileStat->method), 2); - file.seek(8, SeekCur); - file.read(reinterpret_cast(&fileStat->compressedSize), 4); - file.read(reinterpret_cast(&fileStat->uncompressedSize), 4); + file.seekCur(6); + file.read(&fileStat->method, 2); + file.seekCur(8); + file.read(&fileStat->compressedSize, 4); + file.read(&fileStat->uncompressedSize, 4); uint16_t nameLen, m, k; - file.read(reinterpret_cast(&nameLen), 2); - file.read(reinterpret_cast(&m), 2); - file.read(reinterpret_cast(&k), 2); - file.seek(8, SeekCur); - file.read(reinterpret_cast(&fileStat->localHeaderOffset), 4); - file.read(reinterpret_cast(itemName), nameLen); + file.read(&nameLen, 2); + file.read(&m, 2); + file.read(&k, 2); + file.seekCur(8); + file.read(&fileStat->localHeaderOffset, 4); + file.read(itemName, nameLen); itemName[nameLen] = '\0'; if (strcmp(itemName, filename) == 0) { @@ -132,7 +132,7 @@ bool ZipFile::loadFileStatSlim(const char* filename, FileStatSlim* fileStat) { } // Skip the rest of this entry (extra field + comment) - file.seek(m + k, SeekCur); + file.seekCur(m + k); } if (!wasOpen) { @@ -243,7 +243,7 @@ bool ZipFile::loadZipDetails() { } bool ZipFile::open() { - if (!FsHelpers::openFileForRead("ZIP", filePath, file)) { + if (!SdMan.openFileForRead("ZIP", filePath, file)) { return false; } return true; diff --git a/lib/ZipFile/ZipFile.h b/lib/ZipFile/ZipFile.h index 4758f16..0144ed4 100644 --- a/lib/ZipFile/ZipFile.h +++ b/lib/ZipFile/ZipFile.h @@ -1,5 +1,5 @@ #pragma once -#include +#include #include #include @@ -21,7 +21,7 @@ class ZipFile { private: const std::string& filePath; - File file; + FsFile file; ZipDetails zipDetails = {0, 0, false}; std::unordered_map fileStatSlimCache; diff --git a/open-x4-sdk b/open-x4-sdk index 98a5aa1..0d269fe 160000 --- a/open-x4-sdk +++ b/open-x4-sdk @@ -1 +1 @@ -Subproject commit 98a5aa1f8969ccd317c9b45bf0fa84b6c82e167f +Subproject commit 0d269feed2d6450a8a9149fd333c5336ca25daf2 diff --git a/platformio.ini b/platformio.ini index fb520e5..142307c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,6 +21,7 @@ build_flags = -DARDUINO_USB_CDC_ON_BOOT=1 -DMINIZ_NO_ZLIB_COMPATIBLE_NAMES=1 -DEINK_DISPLAY_SINGLE_BUFFER_MODE=1 + -DDISABLE_FS_H_WARNING=1 # https://libexpat.github.io/doc/api/latest/#XML_GE -DXML_GE=0 -DXML_CONTEXT_BYTES=1024 @@ -39,6 +40,7 @@ lib_deps = BatteryMonitor=symlink://open-x4-sdk/libs/hardware/BatteryMonitor InputManager=symlink://open-x4-sdk/libs/hardware/InputManager EInkDisplay=symlink://open-x4-sdk/libs/display/EInkDisplay + SDCardManager=symlink://open-x4-sdk/libs/hardware/SDCardManager ArduinoJson @ 7.4.2 QRCode @ 0.0.1 diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index 41c3322..0f2f13e 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -1,8 +1,7 @@ #include "CrossPointSettings.h" -#include #include -#include +#include #include // Initialize the static instance @@ -17,10 +16,10 @@ constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin"; bool CrossPointSettings::saveToFile() const { // Make sure the directory exists - SD.mkdir("/.crosspoint"); + SdMan.mkdir("/.crosspoint"); - File outputFile; - if (!FsHelpers::openFileForWrite("CPS", SETTINGS_FILE, outputFile)) { + FsFile outputFile; + if (!SdMan.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) { return false; } @@ -40,8 +39,8 @@ bool CrossPointSettings::saveToFile() const { } bool CrossPointSettings::loadFromFile() { - File inputFile; - if (!FsHelpers::openFileForRead("CPS", SETTINGS_FILE, inputFile)) { + FsFile inputFile; + if (!SdMan.openFileForRead("CPS", SETTINGS_FILE, inputFile)) { return false; } diff --git a/src/CrossPointState.cpp b/src/CrossPointState.cpp index 9010822..31cb2ac 100644 --- a/src/CrossPointState.cpp +++ b/src/CrossPointState.cpp @@ -1,7 +1,7 @@ #include "CrossPointState.h" -#include #include +#include #include namespace { @@ -12,8 +12,8 @@ constexpr char STATE_FILE[] = "/.crosspoint/state.bin"; CrossPointState CrossPointState::instance; bool CrossPointState::saveToFile() const { - File outputFile; - if (!FsHelpers::openFileForWrite("CPS", STATE_FILE, outputFile)) { + FsFile outputFile; + if (!SdMan.openFileForWrite("CPS", STATE_FILE, outputFile)) { return false; } @@ -24,8 +24,8 @@ bool CrossPointState::saveToFile() const { } bool CrossPointState::loadFromFile() { - File inputFile; - if (!FsHelpers::openFileForRead("CPS", STATE_FILE, inputFile)) { + FsFile inputFile; + if (!SdMan.openFileForRead("CPS", STATE_FILE, inputFile)) { return false; } diff --git a/src/WifiCredentialStore.cpp b/src/WifiCredentialStore.cpp index 856098f..be865b8 100644 --- a/src/WifiCredentialStore.cpp +++ b/src/WifiCredentialStore.cpp @@ -1,8 +1,7 @@ #include "WifiCredentialStore.h" -#include #include -#include +#include #include // Initialize the static instance @@ -30,10 +29,10 @@ void WifiCredentialStore::obfuscate(std::string& data) const { bool WifiCredentialStore::saveToFile() const { // Make sure the directory exists - SD.mkdir("/.crosspoint"); + SdMan.mkdir("/.crosspoint"); - File file; - if (!FsHelpers::openFileForWrite("WCS", WIFI_FILE, file)) { + FsFile file; + if (!SdMan.openFileForWrite("WCS", WIFI_FILE, file)) { return false; } @@ -60,8 +59,8 @@ bool WifiCredentialStore::saveToFile() const { } bool WifiCredentialStore::loadFromFile() { - File file; - if (!FsHelpers::openFileForRead("WCS", WIFI_FILE, file)) { + FsFile file; + if (!SdMan.openFileForRead("WCS", WIFI_FILE, file)) { return false; } diff --git a/src/activities/Activity.h b/src/activities/Activity.h index 66dfde1..aad5591 100644 --- a/src/activities/Activity.h +++ b/src/activities/Activity.h @@ -5,8 +5,7 @@ #include #include -#include "../MappedInputManager.h" - +class MappedInputManager; class GfxRenderer; class Activity { diff --git a/src/activities/boot_sleep/SleepActivity.cpp b/src/activities/boot_sleep/SleepActivity.cpp index fdf84b6..fa60523 100644 --- a/src/activities/boot_sleep/SleepActivity.cpp +++ b/src/activities/boot_sleep/SleepActivity.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include @@ -58,29 +58,31 @@ void SleepActivity::renderPopup(const char* message) const { void SleepActivity::renderCustomSleepScreen() const { // Check if we have a /sleep directory - auto dir = SD.open("/sleep"); + auto dir = SdMan.open("/sleep"); if (dir && dir.isDirectory()) { std::vector files; + char name[128]; // collect all valid BMP files - for (File file = dir.openNextFile(); file; file = dir.openNextFile()) { + for (auto file = dir.openNextFile(); file; file = dir.openNextFile()) { if (file.isDirectory()) { file.close(); continue; } - auto filename = std::string(file.name()); + file.getName(name, sizeof(name)); + auto filename = std::string(name); if (filename[0] == '.') { file.close(); continue; } if (filename.substr(filename.length() - 4) != ".bmp") { - Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), file.name()); + Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), name); file.close(); continue; } Bitmap bitmap(file); if (bitmap.parseHeaders() != BmpReaderError::Ok) { - Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), file.name()); + Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), name); file.close(); continue; } @@ -92,8 +94,8 @@ void SleepActivity::renderCustomSleepScreen() const { // Generate a random number between 1 and numFiles const auto randomFileIndex = random(numFiles); const auto filename = "/sleep/" + files[randomFileIndex]; - File file; - if (FsHelpers::openFileForRead("SLP", filename, file)) { + FsFile file; + if (SdMan.openFileForRead("SLP", filename, file)) { Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str()); delay(100); Bitmap bitmap(file); @@ -109,8 +111,8 @@ 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. - File file; - if (FsHelpers::openFileForRead("SLP", "/sleep.bmp", file)) { + FsFile file; + if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) { Bitmap bitmap(file); if (bitmap.parseHeaders() == BmpReaderError::Ok) { Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis()); @@ -224,8 +226,8 @@ void SleepActivity::renderCoverSleepScreen() const { coverBmpPath = lastEpub.getCoverBmpPath(); } - File file; - if (FsHelpers::openFileForRead("SLP", coverBmpPath, file)) { + FsFile file; + if (SdMan.openFileForRead("SLP", coverBmpPath, file)) { Bitmap bitmap(file); if (bitmap.parseHeaders() == BmpReaderError::Ok) { renderBitmapSleepScreen(bitmap); diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index f62b393..fa4772b 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -1,10 +1,10 @@ #include "HomeActivity.h" #include -#include -#include +#include #include "CrossPointState.h" +#include "MappedInputManager.h" #include "config.h" void HomeActivity::taskTrampoline(void* param) { @@ -20,7 +20,7 @@ void HomeActivity::onEnter() { renderingMutex = xSemaphoreCreateMutex(); // Check if we have a book to continue reading - hasContinueReading = !APP_STATE.openEpubPath.empty() && SD.exists(APP_STATE.openEpubPath.c_str()); + hasContinueReading = !APP_STATE.openEpubPath.empty() && SdMan.exists(APP_STATE.openEpubPath.c_str()); selectorIndex = 0; diff --git a/src/activities/network/CrossPointWebServerActivity.cpp b/src/activities/network/CrossPointWebServerActivity.cpp index eda20a8..a0db3c3 100644 --- a/src/activities/network/CrossPointWebServerActivity.cpp +++ b/src/activities/network/CrossPointWebServerActivity.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include +#include "MappedInputManager.h" #include "NetworkModeSelectionActivity.h" #include "WifiSelectionActivity.h" #include "config.h" diff --git a/src/activities/network/NetworkModeSelectionActivity.cpp b/src/activities/network/NetworkModeSelectionActivity.cpp index 0cc3594..57afc6e 100644 --- a/src/activities/network/NetworkModeSelectionActivity.cpp +++ b/src/activities/network/NetworkModeSelectionActivity.cpp @@ -1,8 +1,8 @@ #include "NetworkModeSelectionActivity.h" #include -#include +#include "MappedInputManager.h" #include "config.h" namespace { diff --git a/src/activities/network/WifiSelectionActivity.cpp b/src/activities/network/WifiSelectionActivity.cpp index 9f0e502..8977a78 100644 --- a/src/activities/network/WifiSelectionActivity.cpp +++ b/src/activities/network/WifiSelectionActivity.cpp @@ -5,6 +5,7 @@ #include +#include "MappedInputManager.h" #include "WifiCredentialStore.h" #include "activities/util/KeyboardEntryActivity.h" #include "config.h" diff --git a/src/activities/reader/EpubReaderActivity.cpp b/src/activities/reader/EpubReaderActivity.cpp index 6864a56..ab03550 100644 --- a/src/activities/reader/EpubReaderActivity.cpp +++ b/src/activities/reader/EpubReaderActivity.cpp @@ -3,12 +3,13 @@ #include #include #include -#include +#include #include "Battery.h" #include "CrossPointSettings.h" #include "CrossPointState.h" #include "EpubReaderChapterSelectionActivity.h" +#include "MappedInputManager.h" #include "config.h" namespace { @@ -54,8 +55,8 @@ void EpubReaderActivity::onEnter() { epub->setupCacheDir(); - File f; - if (FsHelpers::openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) { + FsFile f; + if (SdMan.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) { uint8_t data[4]; if (f.read(data, 4) == 4) { currentSpineIndex = data[0] + (data[1] << 8); @@ -346,8 +347,8 @@ void EpubReaderActivity::renderScreen() { Serial.printf("[%lu] [ERS] Rendered page in %dms\n", millis(), millis() - start); } - File f; - if (FsHelpers::openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) { + FsFile f; + if (SdMan.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) { uint8_t data[4]; data[0] = currentSpineIndex & 0xFF; data[1] = (currentSpineIndex >> 8) & 0xFF; diff --git a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp index dc0bee5..8245ed2 100644 --- a/src/activities/reader/EpubReaderChapterSelectionActivity.cpp +++ b/src/activities/reader/EpubReaderChapterSelectionActivity.cpp @@ -1,9 +1,8 @@ #include "EpubReaderChapterSelectionActivity.h" #include -#include -#include +#include "MappedInputManager.h" #include "config.h" namespace { diff --git a/src/activities/reader/FileSelectionActivity.cpp b/src/activities/reader/FileSelectionActivity.cpp index 447db6d..45ef6ef 100644 --- a/src/activities/reader/FileSelectionActivity.cpp +++ b/src/activities/reader/FileSelectionActivity.cpp @@ -1,9 +1,9 @@ #include "FileSelectionActivity.h" #include -#include -#include +#include +#include "MappedInputManager.h" #include "config.h" namespace { @@ -30,17 +30,19 @@ void FileSelectionActivity::taskTrampoline(void* param) { void FileSelectionActivity::loadFiles() { files.clear(); selectorIndex = 0; - auto root = SD.open(basepath.c_str()); - for (File file = root.openNextFile(); file; file = root.openNextFile()) { - auto filename = std::string(file.name()); - if (filename[0] == '.') { + auto root = SdMan.open(basepath.c_str()); + char name[128]; + for (auto file = root.openNextFile(); file; file = root.openNextFile()) { + file.getName(name, sizeof(name)); + if (name[0] == '.') { file.close(); continue; } if (file.isDirectory()) { - files.emplace_back(filename + "/"); + files.emplace_back(std::string(name) + "/"); } else { + auto filename = std::string(name); std::string ext4 = filename.length() >= 4 ? filename.substr(filename.length() - 4) : ""; std::string ext5 = filename.length() >= 5 ? filename.substr(filename.length() - 5) : ""; if (ext5 == ".epub" || ext5 == ".xtch" || ext4 == ".xtc") { diff --git a/src/activities/reader/ReaderActivity.cpp b/src/activities/reader/ReaderActivity.cpp index d98e167..d6a3aa6 100644 --- a/src/activities/reader/ReaderActivity.cpp +++ b/src/activities/reader/ReaderActivity.cpp @@ -1,7 +1,5 @@ #include "ReaderActivity.h" -#include - #include "Epub.h" #include "EpubReaderActivity.h" #include "FileSelectionActivity.h" @@ -29,7 +27,7 @@ bool ReaderActivity::isXtcFile(const std::string& path) { } std::unique_ptr ReaderActivity::loadEpub(const std::string& path) { - if (!SD.exists(path.c_str())) { + if (!SdMan.exists(path.c_str())) { Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); return nullptr; } @@ -44,7 +42,7 @@ std::unique_ptr ReaderActivity::loadEpub(const std::string& path) { } std::unique_ptr ReaderActivity::loadXtc(const std::string& path) { - if (!SD.exists(path.c_str())) { + if (!SdMan.exists(path.c_str())) { Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); return nullptr; } diff --git a/src/activities/reader/XtcReaderActivity.cpp b/src/activities/reader/XtcReaderActivity.cpp index 8933606..3f5645c 100644 --- a/src/activities/reader/XtcReaderActivity.cpp +++ b/src/activities/reader/XtcReaderActivity.cpp @@ -9,10 +9,10 @@ #include #include -#include +#include -#include "CrossPointSettings.h" #include "CrossPointState.h" +#include "MappedInputManager.h" #include "config.h" namespace { @@ -330,8 +330,8 @@ void XtcReaderActivity::renderPage() { } void XtcReaderActivity::saveProgress() const { - File f; - if (FsHelpers::openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) { + FsFile f; + if (SdMan.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) { uint8_t data[4]; data[0] = currentPage & 0xFF; data[1] = (currentPage >> 8) & 0xFF; @@ -343,8 +343,8 @@ void XtcReaderActivity::saveProgress() const { } void XtcReaderActivity::loadProgress() { - File f; - if (FsHelpers::openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) { + FsFile f; + if (SdMan.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); diff --git a/src/activities/settings/OtaUpdateActivity.cpp b/src/activities/settings/OtaUpdateActivity.cpp index 846438b..8a04578 100644 --- a/src/activities/settings/OtaUpdateActivity.cpp +++ b/src/activities/settings/OtaUpdateActivity.cpp @@ -1,9 +1,9 @@ #include "OtaUpdateActivity.h" #include -#include #include +#include "MappedInputManager.h" #include "activities/network/WifiSelectionActivity.h" #include "config.h" #include "network/OtaUpdater.h" diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index 409ee39..a03b88a 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -1,9 +1,9 @@ #include "SettingsActivity.h" #include -#include #include "CrossPointSettings.h" +#include "MappedInputManager.h" #include "OtaUpdateActivity.h" #include "config.h" diff --git a/src/activities/util/KeyboardEntryActivity.cpp b/src/activities/util/KeyboardEntryActivity.cpp index 7a13aab..dbfd109 100644 --- a/src/activities/util/KeyboardEntryActivity.cpp +++ b/src/activities/util/KeyboardEntryActivity.cpp @@ -1,6 +1,7 @@ #include "KeyboardEntryActivity.h" #include "../../config.h" +#include "MappedInputManager.h" // Keyboard layouts - lowercase const char* const KeyboardEntryActivity::keyboard[NUM_ROWS] = { diff --git a/src/main.cpp b/src/main.cpp index 877d1c6..63928e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include #include #include @@ -37,7 +37,6 @@ #define UART0_RXD 20 // Used for USB connection detection -#define SD_SPI_CS 12 #define SD_SPI_MISO 7 EInkDisplay einkDisplay(EPD_SCLK, EPD_MOSI, EPD_CS, EPD_DC, EPD_RST, EPD_BUSY); @@ -191,7 +190,7 @@ void setup() { // SD Card Initialization // We need 6 open files concurrently when parsing a new chapter - if (!SD.begin(SD_SPI_CS, SPI, SPI_FQ, "/sd", 6)) { + if (!SdMan.begin()) { Serial.printf("[%lu] [ ] SD card initialization failed\n", millis()); setupDisplayAndFonts(); exitActivity(); diff --git a/src/network/CrossPointWebServer.cpp b/src/network/CrossPointWebServer.cpp index 041273f..916f6a2 100644 --- a/src/network/CrossPointWebServer.cpp +++ b/src/network/CrossPointWebServer.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -170,7 +170,7 @@ void CrossPointWebServer::handleStatus() const { } void CrossPointWebServer::scanFiles(const char* path, const std::function& callback) const { - File root = SD.open(path); + FsFile root = SdMan.open(path); if (!root) { Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path); return; @@ -184,9 +184,11 @@ void CrossPointWebServer::scanFiles(const char* path, const std::function