A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add HalStorage (#656)

## Summary

Continue my changes to introduce the HAL infrastructure from
https://github.com/crosspoint-reader/crosspoint-reader/pull/522

This PR touches quite a lot of files, but most of them are just name
changing. It should not have any impacts to the end behavior.

## Additional Context

My plan is to firstly add this small shim layer, which sounds useless at
first, but then I'll implement an emulated driver which can be helpful
for testing and for development.

Currently, on my fork, I'm using a FS driver that allow "mounting" a
local directory from my computer to the device, much like the `-v` mount
option on docker. This allows me to quickly reset `.crosspoint`
directory if anything goes wrong. I plan to upstream this feature when
this PR get merged.

---

### AI Usage

While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.

Did you use AI tools to help write this code? NO

authored by

Xuan-Son Nguyen and committed by
GitHub
7f40c3f4 a87eacc6

+318 -197
+31 -31
lib/Epub/Epub.cpp
··· 1 1 #include "Epub.h" 2 2 3 3 #include <FsHelpers.h> 4 + #include <HalStorage.h> 4 5 #include <HardwareSerial.h> 5 6 #include <JpegToBmpConverter.h> 6 - #include <SDCardManager.h> 7 7 #include <ZipFile.h> 8 8 9 9 #include "Epub/parsers/ContainerParser.h" ··· 105 105 106 106 const auto tmpNcxPath = getCachePath() + "/toc.ncx"; 107 107 FsFile tempNcxFile; 108 - if (!SdMan.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) { 108 + if (!Storage.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) { 109 109 return false; 110 110 } 111 111 readItemContentsToStream(tocNcxItem, tempNcxFile, 1024); 112 112 tempNcxFile.close(); 113 - if (!SdMan.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) { 113 + if (!Storage.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) { 114 114 return false; 115 115 } 116 116 const auto ncxSize = tempNcxFile.size(); ··· 145 145 146 146 free(ncxBuffer); 147 147 tempNcxFile.close(); 148 - SdMan.remove(tmpNcxPath.c_str()); 148 + Storage.remove(tmpNcxPath.c_str()); 149 149 150 150 Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis()); 151 151 return true; ··· 162 162 163 163 const auto tmpNavPath = getCachePath() + "/toc.nav"; 164 164 FsFile tempNavFile; 165 - if (!SdMan.openFileForWrite("EBP", tmpNavPath, tempNavFile)) { 165 + if (!Storage.openFileForWrite("EBP", tmpNavPath, tempNavFile)) { 166 166 return false; 167 167 } 168 168 readItemContentsToStream(tocNavItem, tempNavFile, 1024); 169 169 tempNavFile.close(); 170 - if (!SdMan.openFileForRead("EBP", tmpNavPath, tempNavFile)) { 170 + if (!Storage.openFileForRead("EBP", tmpNavPath, tempNavFile)) { 171 171 return false; 172 172 } 173 173 const auto navSize = tempNavFile.size(); ··· 202 202 203 203 free(navBuffer); 204 204 tempNavFile.close(); 205 - SdMan.remove(tmpNavPath.c_str()); 205 + Storage.remove(tmpNavPath.c_str()); 206 206 207 207 Serial.printf("[%lu] [EBP] Parsed TOC nav items\n", millis()); 208 208 return true; ··· 212 212 213 213 bool Epub::loadCssRulesFromCache() const { 214 214 FsFile cssCacheFile; 215 - if (SdMan.openFileForRead("EBP", getCssRulesCache(), cssCacheFile)) { 215 + if (Storage.openFileForRead("EBP", getCssRulesCache(), cssCacheFile)) { 216 216 if (cssParser->loadFromCache(cssCacheFile)) { 217 217 cssCacheFile.close(); 218 218 Serial.printf("[%lu] [EBP] Loaded CSS rules from cache\n", millis()); ··· 238 238 // Extract CSS file to temp location 239 239 const auto tmpCssPath = getCachePath() + "/.tmp.css"; 240 240 FsFile tempCssFile; 241 - if (!SdMan.openFileForWrite("EBP", tmpCssPath, tempCssFile)) { 241 + if (!Storage.openFileForWrite("EBP", tmpCssPath, tempCssFile)) { 242 242 Serial.printf("[%lu] [EBP] Could not create temp CSS file\n", millis()); 243 243 continue; 244 244 } 245 245 if (!readItemContentsToStream(cssPath, tempCssFile, 1024)) { 246 246 Serial.printf("[%lu] [EBP] Could not read CSS file: %s\n", millis(), cssPath.c_str()); 247 247 tempCssFile.close(); 248 - SdMan.remove(tmpCssPath.c_str()); 248 + Storage.remove(tmpCssPath.c_str()); 249 249 continue; 250 250 } 251 251 tempCssFile.close(); 252 252 253 253 // Parse the CSS file 254 - if (!SdMan.openFileForRead("EBP", tmpCssPath, tempCssFile)) { 254 + if (!Storage.openFileForRead("EBP", tmpCssPath, tempCssFile)) { 255 255 Serial.printf("[%lu] [EBP] Could not open temp CSS file for reading\n", millis()); 256 - SdMan.remove(tmpCssPath.c_str()); 256 + Storage.remove(tmpCssPath.c_str()); 257 257 continue; 258 258 } 259 259 cssParser->loadFromStream(tempCssFile); 260 260 tempCssFile.close(); 261 - SdMan.remove(tmpCssPath.c_str()); 261 + Storage.remove(tmpCssPath.c_str()); 262 262 } 263 263 264 264 // Save to cache for next time 265 265 FsFile cssCacheFile; 266 - if (SdMan.openFileForWrite("EBP", getCssRulesCache(), cssCacheFile)) { 266 + if (Storage.openFileForWrite("EBP", getCssRulesCache(), cssCacheFile)) { 267 267 cssParser->saveToCache(cssCacheFile); 268 268 cssCacheFile.close(); 269 269 } ··· 399 399 } 400 400 401 401 bool Epub::clearCache() const { 402 - if (!SdMan.exists(cachePath.c_str())) { 402 + if (!Storage.exists(cachePath.c_str())) { 403 403 Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis()); 404 404 return true; 405 405 } 406 406 407 - if (!SdMan.removeDir(cachePath.c_str())) { 407 + if (!Storage.removeDir(cachePath.c_str())) { 408 408 Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis()); 409 409 return false; 410 410 } ··· 414 414 } 415 415 416 416 void Epub::setupCacheDir() const { 417 - if (SdMan.exists(cachePath.c_str())) { 417 + if (Storage.exists(cachePath.c_str())) { 418 418 return; 419 419 } 420 420 421 - SdMan.mkdir(cachePath.c_str()); 421 + Storage.mkdir(cachePath.c_str()); 422 422 } 423 423 424 424 const std::string& Epub::getCachePath() const { return cachePath; } ··· 459 459 460 460 bool Epub::generateCoverBmp(bool cropped) const { 461 461 // Already generated, return true 462 - if (SdMan.exists(getCoverBmpPath(cropped).c_str())) { 462 + if (Storage.exists(getCoverBmpPath(cropped).c_str())) { 463 463 return true; 464 464 } 465 465 ··· 480 480 const auto coverJpgTempPath = getCachePath() + "/.cover.jpg"; 481 481 482 482 FsFile coverJpg; 483 - if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { 483 + if (!Storage.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { 484 484 return false; 485 485 } 486 486 readItemContentsToStream(coverImageHref, coverJpg, 1024); 487 487 coverJpg.close(); 488 488 489 - if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { 489 + if (!Storage.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { 490 490 return false; 491 491 } 492 492 493 493 FsFile coverBmp; 494 - if (!SdMan.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) { 494 + if (!Storage.openFileForWrite("EBP", getCoverBmpPath(cropped), coverBmp)) { 495 495 coverJpg.close(); 496 496 return false; 497 497 } 498 498 const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp, cropped); 499 499 coverJpg.close(); 500 500 coverBmp.close(); 501 - SdMan.remove(coverJpgTempPath.c_str()); 501 + Storage.remove(coverJpgTempPath.c_str()); 502 502 503 503 if (!success) { 504 504 Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis()); 505 - SdMan.remove(getCoverBmpPath(cropped).c_str()); 505 + Storage.remove(getCoverBmpPath(cropped).c_str()); 506 506 } 507 507 Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no"); 508 508 return success; ··· 518 518 519 519 bool Epub::generateThumbBmp(int height) const { 520 520 // Already generated, return true 521 - if (SdMan.exists(getThumbBmpPath(height).c_str())) { 521 + if (Storage.exists(getThumbBmpPath(height).c_str())) { 522 522 return true; 523 523 } 524 524 ··· 536 536 const auto coverJpgTempPath = getCachePath() + "/.cover.jpg"; 537 537 538 538 FsFile coverJpg; 539 - if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { 539 + if (!Storage.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) { 540 540 return false; 541 541 } 542 542 readItemContentsToStream(coverImageHref, coverJpg, 1024); 543 543 coverJpg.close(); 544 544 545 - if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { 545 + if (!Storage.openFileForRead("EBP", coverJpgTempPath, coverJpg)) { 546 546 return false; 547 547 } 548 548 549 549 FsFile thumbBmp; 550 - if (!SdMan.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp)) { 550 + if (!Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp)) { 551 551 coverJpg.close(); 552 552 return false; 553 553 } ··· 559 559 THUMB_TARGET_HEIGHT); 560 560 coverJpg.close(); 561 561 thumbBmp.close(); 562 - SdMan.remove(coverJpgTempPath.c_str()); 562 + Storage.remove(coverJpgTempPath.c_str()); 563 563 564 564 if (!success) { 565 565 Serial.printf("[%lu] [EBP] Failed to generate thumb BMP from JPG cover image\n", millis()); 566 - SdMan.remove(getThumbBmpPath(height).c_str()); 566 + Storage.remove(getThumbBmpPath(height).c_str()); 567 567 } 568 568 Serial.printf("[%lu] [EBP] Generated thumb BMP from JPG cover image, success: %s\n", millis(), 569 569 success ? "yes" : "no"); ··· 574 574 575 575 // Write an empty bmp file to avoid generation attempts in the future 576 576 FsFile thumbBmp; 577 - SdMan.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp); 577 + Storage.openFileForWrite("EBP", getThumbBmpPath(height), thumbBmp); 578 578 thumbBmp.close(); 579 579 return false; 580 580 }
+11 -11
lib/Epub/Epub/BookMetadataCache.cpp
··· 29 29 Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis()); 30 30 31 31 // Open spine file for writing 32 - return SdMan.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile); 32 + return Storage.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile); 33 33 } 34 34 35 35 bool BookMetadataCache::endContentOpfPass() { ··· 40 40 bool BookMetadataCache::beginTocPass() { 41 41 Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis()); 42 42 43 - if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { 43 + if (!Storage.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { 44 44 return false; 45 45 } 46 - if (!SdMan.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) { 46 + if (!Storage.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) { 47 47 spineFile.close(); 48 48 return false; 49 49 } ··· 98 98 99 99 bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMetadata& metadata) { 100 100 // Open all three files, writing to meta, reading from spine and toc 101 - if (!SdMan.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) { 101 + if (!Storage.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) { 102 102 return false; 103 103 } 104 104 105 - if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { 105 + if (!Storage.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { 106 106 bookFile.close(); 107 107 return false; 108 108 } 109 109 110 - if (!SdMan.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) { 110 + if (!Storage.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) { 111 111 bookFile.close(); 112 112 spineFile.close(); 113 113 return false; ··· 275 275 } 276 276 277 277 bool BookMetadataCache::cleanupTmpFiles() const { 278 - if (SdMan.exists((cachePath + tmpSpineBinFile).c_str())) { 279 - SdMan.remove((cachePath + tmpSpineBinFile).c_str()); 278 + if (Storage.exists((cachePath + tmpSpineBinFile).c_str())) { 279 + Storage.remove((cachePath + tmpSpineBinFile).c_str()); 280 280 } 281 - if (SdMan.exists((cachePath + tmpTocBinFile).c_str())) { 282 - SdMan.remove((cachePath + tmpTocBinFile).c_str()); 281 + if (Storage.exists((cachePath + tmpTocBinFile).c_str())) { 282 + Storage.remove((cachePath + tmpTocBinFile).c_str()); 283 283 } 284 284 return true; 285 285 } ··· 364 364 /* ============= READING / LOADING FUNCTIONS ================ */ 365 365 366 366 bool BookMetadataCache::load() { 367 - if (!SdMan.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) { 367 + if (!Storage.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) { 368 368 return false; 369 369 } 370 370
+1 -1
lib/Epub/Epub/BookMetadataCache.h
··· 1 1 #pragma once 2 2 3 - #include <SDCardManager.h> 3 + #include <HalStorage.h> 4 4 5 5 #include <algorithm> 6 6 #include <string>
+1 -1
lib/Epub/Epub/Page.h
··· 1 1 #pragma once 2 - #include <SdFat.h> 2 + #include <HalStorage.h> 3 3 4 4 #include <utility> 5 5 #include <vector>
+15 -15
lib/Epub/Epub/Section.cpp
··· 1 1 #include "Section.h" 2 2 3 - #include <SDCardManager.h> 3 + #include <HalStorage.h> 4 4 #include <Serialization.h> 5 5 6 6 #include "Page.h" ··· 60 60 bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing, 61 61 const uint8_t paragraphAlignment, const uint16_t viewportWidth, 62 62 const uint16_t viewportHeight, const bool hyphenationEnabled, const bool embeddedStyle) { 63 - if (!SdMan.openFileForRead("SCT", filePath, file)) { 63 + if (!Storage.openFileForRead("SCT", filePath, file)) { 64 64 return false; 65 65 } 66 66 ··· 110 110 111 111 // Your updated class method (assuming you are using the 'SD' object, which is a wrapper for a specific filesystem) 112 112 bool Section::clearCache() const { 113 - if (!SdMan.exists(filePath.c_str())) { 113 + if (!Storage.exists(filePath.c_str())) { 114 114 Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis()); 115 115 return true; 116 116 } 117 117 118 - if (!SdMan.remove(filePath.c_str())) { 118 + if (!Storage.remove(filePath.c_str())) { 119 119 Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis()); 120 120 return false; 121 121 } ··· 134 134 // Create cache directory if it doesn't exist 135 135 { 136 136 const auto sectionsDir = epub->getCachePath() + "/sections"; 137 - SdMan.mkdir(sectionsDir.c_str()); 137 + Storage.mkdir(sectionsDir.c_str()); 138 138 } 139 139 140 140 // Retry logic for SD card timing issues ··· 147 147 } 148 148 149 149 // Remove any incomplete file from previous attempt before retrying 150 - if (SdMan.exists(tmpHtmlPath.c_str())) { 151 - SdMan.remove(tmpHtmlPath.c_str()); 150 + if (Storage.exists(tmpHtmlPath.c_str())) { 151 + Storage.remove(tmpHtmlPath.c_str()); 152 152 } 153 153 154 154 FsFile tmpHtml; 155 - if (!SdMan.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { 155 + if (!Storage.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) { 156 156 continue; 157 157 } 158 158 success = epub->readItemContentsToStream(localPath, tmpHtml, 1024); ··· 160 160 tmpHtml.close(); 161 161 162 162 // If streaming failed, remove the incomplete file immediately 163 - if (!success && SdMan.exists(tmpHtmlPath.c_str())) { 164 - SdMan.remove(tmpHtmlPath.c_str()); 163 + if (!success && Storage.exists(tmpHtmlPath.c_str())) { 164 + Storage.remove(tmpHtmlPath.c_str()); 165 165 Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis()); 166 166 } 167 167 } ··· 173 173 174 174 Serial.printf("[%lu] [SCT] Streamed temp HTML to %s (%d bytes)\n", millis(), tmpHtmlPath.c_str(), fileSize); 175 175 176 - if (!SdMan.openFileForWrite("SCT", filePath, file)) { 176 + if (!Storage.openFileForWrite("SCT", filePath, file)) { 177 177 return false; 178 178 } 179 179 writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, paragraphAlignment, viewportWidth, ··· 188 188 Hyphenator::setPreferredLanguage(epub->getLanguage()); 189 189 success = visitor.parseAndBuildPages(); 190 190 191 - SdMan.remove(tmpHtmlPath.c_str()); 191 + Storage.remove(tmpHtmlPath.c_str()); 192 192 if (!success) { 193 193 Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis()); 194 194 file.close(); 195 - SdMan.remove(filePath.c_str()); 195 + Storage.remove(filePath.c_str()); 196 196 return false; 197 197 } 198 198 ··· 210 210 if (hasFailedLutRecords) { 211 211 Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis()); 212 212 file.close(); 213 - SdMan.remove(filePath.c_str()); 213 + Storage.remove(filePath.c_str()); 214 214 return false; 215 215 } 216 216 ··· 223 223 } 224 224 225 225 std::unique_ptr<Page> Section::loadPageFromSectionFile() { 226 - if (!SdMan.openFileForRead("SCT", filePath, file)) { 226 + if (!Storage.openFileForRead("SCT", filePath, file)) { 227 227 return nullptr; 228 228 } 229 229
+1 -1
lib/Epub/Epub/blocks/TextBlock.h
··· 1 1 #pragma once 2 2 #include <EpdFontFamily.h> 3 - #include <SdFat.h> 3 + #include <HalStorage.h> 4 4 5 5 #include <list> 6 6 #include <memory>
+1 -1
lib/Epub/Epub/css/CssParser.h
··· 1 1 #pragma once 2 2 3 - #include <SdFat.h> 3 + #include <HalStorage.h> 4 4 5 5 #include <string> 6 6 #include <unordered_map>
+2 -2
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp
··· 1 1 #include "ChapterHtmlSlimParser.h" 2 2 3 3 #include <GfxRenderer.h> 4 + #include <HalStorage.h> 4 5 #include <HardwareSerial.h> 5 - #include <SDCardManager.h> 6 6 #include <expat.h> 7 7 8 8 #include "../Page.h" ··· 482 482 } 483 483 484 484 FsFile file; 485 - if (!SdMan.openFileForRead("EHP", filepath, file)) { 485 + if (!Storage.openFileForRead("EHP", filepath, file)) { 486 486 XML_ParserFree(parser); 487 487 return false; 488 488 }
+5 -5
lib/Epub/Epub/parsers/ContentOpfParser.cpp
··· 36 36 if (tempItemStore) { 37 37 tempItemStore.close(); 38 38 } 39 - if (SdMan.exists((cachePath + itemCacheFile).c_str())) { 40 - SdMan.remove((cachePath + itemCacheFile).c_str()); 39 + if (Storage.exists((cachePath + itemCacheFile).c_str())) { 40 + Storage.remove((cachePath + itemCacheFile).c_str()); 41 41 } 42 42 itemIndex.clear(); 43 43 itemIndex.shrink_to_fit(); ··· 118 118 119 119 if (self->state == IN_PACKAGE && (strcmp(name, "manifest") == 0 || strcmp(name, "opf:manifest") == 0)) { 120 120 self->state = IN_MANIFEST; 121 - if (!SdMan.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 121 + if (!Storage.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 122 122 Serial.printf( 123 123 "[%lu] [COF] Couldn't open temp items file for writing. This is probably going to be a fatal error.\n", 124 124 millis()); ··· 128 128 129 129 if (self->state == IN_PACKAGE && (strcmp(name, "spine") == 0 || strcmp(name, "opf:spine") == 0)) { 130 130 self->state = IN_SPINE; 131 - if (!SdMan.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 131 + if (!Storage.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 132 132 Serial.printf( 133 133 "[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n", 134 134 millis()); ··· 149 149 self->state = IN_GUIDE; 150 150 // TODO Remove print 151 151 Serial.printf("[%lu] [COF] Entering guide state.\n", millis()); 152 - if (!SdMan.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 152 + if (!Storage.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 153 153 Serial.printf( 154 154 "[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n", 155 155 millis());
+1 -1
lib/GfxRenderer/Bitmap.h
··· 1 1 #pragma once 2 2 3 - #include <SdFat.h> 3 + #include <HalStorage.h> 4 4 5 5 #include <cstdint> 6 6
+1 -1
lib/JpegToBmpConverter/JpegToBmpConverter.cpp
··· 1 1 #include "JpegToBmpConverter.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 - #include <SdFat.h> 5 5 #include <picojpeg.h> 6 6 7 7 #include <cstdio>
+4 -4
lib/KOReaderSync/KOReaderCredentialStore.cpp
··· 1 1 #include "KOReaderCredentialStore.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 5 #include <MD5Builder.h> 5 - #include <SDCardManager.h> 6 6 #include <Serialization.h> 7 7 8 8 // Initialize the static instance ··· 32 32 33 33 bool KOReaderCredentialStore::saveToFile() const { 34 34 // Make sure the directory exists 35 - SdMan.mkdir("/.crosspoint"); 35 + Storage.mkdir("/.crosspoint"); 36 36 37 37 FsFile file; 38 - if (!SdMan.openFileForWrite("KRS", KOREADER_FILE, file)) { 38 + if (!Storage.openFileForWrite("KRS", KOREADER_FILE, file)) { 39 39 return false; 40 40 } 41 41 ··· 64 64 65 65 bool KOReaderCredentialStore::loadFromFile() { 66 66 FsFile file; 67 - if (!SdMan.openFileForRead("KRS", KOREADER_FILE, file)) { 67 + if (!Storage.openFileForRead("KRS", KOREADER_FILE, file)) { 68 68 Serial.printf("[%lu] [KRS] No credentials file found\n", millis()); 69 69 return false; 70 70 }
+2 -2
lib/KOReaderSync/KOReaderDocumentId.cpp
··· 1 1 #include "KOReaderDocumentId.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 5 #include <MD5Builder.h> 5 - #include <SDCardManager.h> 6 6 7 7 namespace { 8 8 // Extract filename from path (everything after last '/') ··· 43 43 44 44 std::string KOReaderDocumentId::calculate(const std::string& filePath) { 45 45 FsFile file; 46 - if (!SdMan.openFileForRead("KODoc", filePath, file)) { 46 + if (!Storage.openFileForRead("KODoc", filePath, file)) { 47 47 Serial.printf("[%lu] [KODoc] Failed to open file: %s\n", millis(), filePath.c_str()); 48 48 return ""; 49 49 }
+1 -1
lib/Serialization/Serialization.h
··· 1 1 #pragma once 2 - #include <SdFat.h> 2 + #include <HalStorage.h> 3 3 4 4 #include <iostream> 5 5
+15 -15
lib/Txt/Txt.cpp
··· 15 15 return true; 16 16 } 17 17 18 - if (!SdMan.exists(filepath.c_str())) { 18 + if (!Storage.exists(filepath.c_str())) { 19 19 Serial.printf("[%lu] [TXT] File does not exist: %s\n", millis(), filepath.c_str()); 20 20 return false; 21 21 } 22 22 23 23 FsFile file; 24 - if (!SdMan.openFileForRead("TXT", filepath, file)) { 24 + if (!Storage.openFileForRead("TXT", filepath, file)) { 25 25 Serial.printf("[%lu] [TXT] Failed to open file: %s\n", millis(), filepath.c_str()); 26 26 return false; 27 27 } ··· 48 48 } 49 49 50 50 void Txt::setupCacheDir() const { 51 - if (!SdMan.exists(cacheBasePath.c_str())) { 52 - SdMan.mkdir(cacheBasePath.c_str()); 51 + if (!Storage.exists(cacheBasePath.c_str())) { 52 + Storage.mkdir(cacheBasePath.c_str()); 53 53 } 54 - if (!SdMan.exists(cachePath.c_str())) { 55 - SdMan.mkdir(cachePath.c_str()); 54 + if (!Storage.exists(cachePath.c_str())) { 55 + Storage.mkdir(cachePath.c_str()); 56 56 } 57 57 } 58 58 ··· 73 73 // First priority: look for image with same name as txt file (e.g., mybook.jpg) 74 74 for (const auto& ext : extensions) { 75 75 std::string coverPath = folder + "/" + baseName + ext; 76 - if (SdMan.exists(coverPath.c_str())) { 76 + if (Storage.exists(coverPath.c_str())) { 77 77 Serial.printf("[%lu] [TXT] Found matching cover image: %s\n", millis(), coverPath.c_str()); 78 78 return coverPath; 79 79 } ··· 84 84 for (const auto& name : coverNames) { 85 85 for (const auto& ext : extensions) { 86 86 std::string coverPath = folder + "/" + std::string(name) + ext; 87 - if (SdMan.exists(coverPath.c_str())) { 87 + if (Storage.exists(coverPath.c_str())) { 88 88 Serial.printf("[%lu] [TXT] Found fallback cover image: %s\n", millis(), coverPath.c_str()); 89 89 return coverPath; 90 90 } ··· 98 98 99 99 bool Txt::generateCoverBmp() const { 100 100 // Already generated, return true 101 - if (SdMan.exists(getCoverBmpPath().c_str())) { 101 + if (Storage.exists(getCoverBmpPath().c_str())) { 102 102 return true; 103 103 } 104 104 ··· 122 122 // Copy BMP file to cache 123 123 Serial.printf("[%lu] [TXT] Copying BMP cover image to cache\n", millis()); 124 124 FsFile src, dst; 125 - if (!SdMan.openFileForRead("TXT", coverImagePath, src)) { 125 + if (!Storage.openFileForRead("TXT", coverImagePath, src)) { 126 126 return false; 127 127 } 128 - if (!SdMan.openFileForWrite("TXT", getCoverBmpPath(), dst)) { 128 + if (!Storage.openFileForWrite("TXT", getCoverBmpPath(), dst)) { 129 129 src.close(); 130 130 return false; 131 131 } ··· 144 144 // Convert JPG/JPEG to BMP (same approach as Epub) 145 145 Serial.printf("[%lu] [TXT] Generating BMP from JPG cover image\n", millis()); 146 146 FsFile coverJpg, coverBmp; 147 - if (!SdMan.openFileForRead("TXT", coverImagePath, coverJpg)) { 147 + if (!Storage.openFileForRead("TXT", coverImagePath, coverJpg)) { 148 148 return false; 149 149 } 150 - if (!SdMan.openFileForWrite("TXT", getCoverBmpPath(), coverBmp)) { 150 + if (!Storage.openFileForWrite("TXT", getCoverBmpPath(), coverBmp)) { 151 151 coverJpg.close(); 152 152 return false; 153 153 } ··· 157 157 158 158 if (!success) { 159 159 Serial.printf("[%lu] [TXT] Failed to generate BMP from JPG cover image\n", millis()); 160 - SdMan.remove(getCoverBmpPath().c_str()); 160 + Storage.remove(getCoverBmpPath().c_str()); 161 161 } else { 162 162 Serial.printf("[%lu] [TXT] Generated BMP from JPG cover image\n", millis()); 163 163 } ··· 175 175 } 176 176 177 177 FsFile file; 178 - if (!SdMan.openFileForRead("TXT", filepath, file)) { 178 + if (!Storage.openFileForRead("TXT", filepath, file)) { 179 179 return false; 180 180 } 181 181
+1 -1
lib/Txt/Txt.h
··· 1 1 #pragma once 2 2 3 - #include <SDCardManager.h> 3 + #include <HalStorage.h> 4 4 5 5 #include <memory> 6 6 #include <string>
+13 -13
lib/Xtc/Xtc.cpp
··· 7 7 8 8 #include "Xtc.h" 9 9 10 + #include <HalStorage.h> 10 11 #include <HardwareSerial.h> 11 - #include <SDCardManager.h> 12 12 13 13 bool Xtc::load() { 14 14 Serial.printf("[%lu] [XTC] Loading XTC: %s\n", millis(), filepath.c_str()); ··· 30 30 } 31 31 32 32 bool Xtc::clearCache() const { 33 - if (!SdMan.exists(cachePath.c_str())) { 33 + if (!Storage.exists(cachePath.c_str())) { 34 34 Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis()); 35 35 return true; 36 36 } 37 37 38 - if (!SdMan.removeDir(cachePath.c_str())) { 38 + if (!Storage.removeDir(cachePath.c_str())) { 39 39 Serial.printf("[%lu] [XTC] Failed to clear cache\n", millis()); 40 40 return false; 41 41 } ··· 45 45 } 46 46 47 47 void Xtc::setupCacheDir() const { 48 - if (SdMan.exists(cachePath.c_str())) { 48 + if (Storage.exists(cachePath.c_str())) { 49 49 return; 50 50 } 51 51 52 52 // Create directories recursively 53 53 for (size_t i = 1; i < cachePath.length(); i++) { 54 54 if (cachePath[i] == '/') { 55 - SdMan.mkdir(cachePath.substr(0, i).c_str()); 55 + Storage.mkdir(cachePath.substr(0, i).c_str()); 56 56 } 57 57 } 58 - SdMan.mkdir(cachePath.c_str()); 58 + Storage.mkdir(cachePath.c_str()); 59 59 } 60 60 61 61 std::string Xtc::getTitle() const { ··· 114 114 115 115 bool Xtc::generateCoverBmp() const { 116 116 // Already generated 117 - if (SdMan.exists(getCoverBmpPath().c_str())) { 117 + if (Storage.exists(getCoverBmpPath().c_str())) { 118 118 return true; 119 119 } 120 120 ··· 166 166 167 167 // Create BMP file 168 168 FsFile coverBmp; 169 - if (!SdMan.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) { 169 + if (!Storage.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) { 170 170 Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis()); 171 171 free(pageBuffer); 172 172 return false; ··· 306 306 307 307 bool Xtc::generateThumbBmp(int height) const { 308 308 // Already generated 309 - if (SdMan.exists(getThumbBmpPath(height).c_str())) { 309 + if (Storage.exists(getThumbBmpPath(height).c_str())) { 310 310 return true; 311 311 } 312 312 ··· 348 348 // Copy cover.bmp to thumb.bmp 349 349 if (generateCoverBmp()) { 350 350 FsFile src, dst; 351 - if (SdMan.openFileForRead("XTC", getCoverBmpPath(), src)) { 352 - if (SdMan.openFileForWrite("XTC", getThumbBmpPath(height), dst)) { 351 + if (Storage.openFileForRead("XTC", getCoverBmpPath(), src)) { 352 + if (Storage.openFileForWrite("XTC", getThumbBmpPath(height), dst)) { 353 353 uint8_t buffer[512]; 354 354 while (src.available()) { 355 355 size_t bytesRead = src.read(buffer, sizeof(buffer)); ··· 360 360 src.close(); 361 361 } 362 362 Serial.printf("[%lu] [XTC] Copied cover to thumb (no scaling needed)\n", millis()); 363 - return SdMan.exists(getThumbBmpPath(height).c_str()); 363 + return Storage.exists(getThumbBmpPath(height).c_str()); 364 364 } 365 365 return false; 366 366 } ··· 394 394 395 395 // Create thumbnail BMP file - use 1-bit format for fast home screen rendering (no gray passes) 396 396 FsFile thumbBmp; 397 - if (!SdMan.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) { 397 + if (!Storage.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) { 398 398 Serial.printf("[%lu] [XTC] Failed to create thumb BMP file\n", millis()); 399 399 free(pageBuffer); 400 400 return false;
+3 -3
lib/Xtc/Xtc/XtcParser.cpp
··· 8 8 #include "XtcParser.h" 9 9 10 10 #include <FsHelpers.h> 11 + #include <HalStorage.h> 11 12 #include <HardwareSerial.h> 12 - #include <SDCardManager.h> 13 13 14 14 #include <cstring> 15 15 ··· 34 34 } 35 35 36 36 // Open file 37 - if (!SdMan.openFileForRead("XTC", filepath, m_file)) { 37 + if (!Storage.openFileForRead("XTC", filepath, m_file)) { 38 38 m_lastError = XtcError::FILE_NOT_FOUND; 39 39 return m_lastError; 40 40 } ··· 444 444 445 445 bool XtcParser::isValidXtcFile(const char* filepath) { 446 446 FsFile file; 447 - if (!SdMan.openFileForRead("XTC", filepath, file)) { 447 + if (!Storage.openFileForRead("XTC", filepath, file)) { 448 448 return false; 449 449 } 450 450
+1 -1
lib/Xtc/Xtc/XtcParser.h
··· 7 7 8 8 #pragma once 9 9 10 - #include <SdFat.h> 10 + #include <HalStorage.h> 11 11 12 12 #include <functional> 13 13 #include <memory>
+2 -2
lib/ZipFile/ZipFile.cpp
··· 1 1 #include "ZipFile.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 - #include <SDCardManager.h> 5 5 #include <miniz.h> 6 6 7 7 #include <algorithm> ··· 279 279 } 280 280 281 281 bool ZipFile::open() { 282 - if (!SdMan.openFileForRead("ZIP", filePath, file)) { 282 + if (!Storage.openFileForRead("ZIP", filePath, file)) { 283 283 return false; 284 284 } 285 285 return true;
+1 -1
lib/ZipFile/ZipFile.h
··· 1 1 #pragma once 2 - #include <SdFat.h> 2 + #include <HalStorage.h> 3 3 4 4 #include <string> 5 5 #include <unordered_map>
+65
lib/hal/HalStorage.cpp
··· 1 + #include "HalStorage.h" 2 + 3 + #include <SDCardManager.h> 4 + 5 + #define SDCard SDCardManager::getInstance() 6 + 7 + HalStorage HalStorage::instance; 8 + 9 + HalStorage::HalStorage() {} 10 + 11 + bool HalStorage::begin() { return SDCard.begin(); } 12 + 13 + bool HalStorage::ready() const { return SDCard.ready(); } 14 + 15 + std::vector<String> HalStorage::listFiles(const char* path, int maxFiles) { return SDCard.listFiles(path, maxFiles); } 16 + 17 + String HalStorage::readFile(const char* path) { return SDCard.readFile(path); } 18 + 19 + bool HalStorage::readFileToStream(const char* path, Print& out, size_t chunkSize) { 20 + return SDCard.readFileToStream(path, out, chunkSize); 21 + } 22 + 23 + size_t HalStorage::readFileToBuffer(const char* path, char* buffer, size_t bufferSize, size_t maxBytes) { 24 + return SDCard.readFileToBuffer(path, buffer, bufferSize, maxBytes); 25 + } 26 + 27 + bool HalStorage::writeFile(const char* path, const String& content) { return SDCard.writeFile(path, content); } 28 + 29 + bool HalStorage::ensureDirectoryExists(const char* path) { return SDCard.ensureDirectoryExists(path); } 30 + 31 + FsFile HalStorage::open(const char* path, const oflag_t oflag) { return SDCard.open(path, oflag); } 32 + 33 + bool HalStorage::mkdir(const char* path, const bool pFlag) { return SDCard.mkdir(path, pFlag); } 34 + 35 + bool HalStorage::exists(const char* path) { return SDCard.exists(path); } 36 + 37 + bool HalStorage::remove(const char* path) { return SDCard.remove(path); } 38 + 39 + bool HalStorage::rmdir(const char* path) { return SDCard.rmdir(path); } 40 + 41 + bool HalStorage::openFileForRead(const char* moduleName, const char* path, FsFile& file) { 42 + return SDCard.openFileForRead(moduleName, path, file); 43 + } 44 + 45 + bool HalStorage::openFileForRead(const char* moduleName, const std::string& path, FsFile& file) { 46 + return openFileForRead(moduleName, path.c_str(), file); 47 + } 48 + 49 + bool HalStorage::openFileForRead(const char* moduleName, const String& path, FsFile& file) { 50 + return openFileForRead(moduleName, path.c_str(), file); 51 + } 52 + 53 + bool HalStorage::openFileForWrite(const char* moduleName, const char* path, FsFile& file) { 54 + return SDCard.openFileForWrite(moduleName, path, file); 55 + } 56 + 57 + bool HalStorage::openFileForWrite(const char* moduleName, const std::string& path, FsFile& file) { 58 + return openFileForWrite(moduleName, path.c_str(), file); 59 + } 60 + 61 + bool HalStorage::openFileForWrite(const char* moduleName, const String& path, FsFile& file) { 62 + return openFileForWrite(moduleName, path.c_str(), file); 63 + } 64 + 65 + bool HalStorage::removeDir(const char* path) { return SDCard.removeDir(path); }
+54
lib/hal/HalStorage.h
··· 1 + #pragma once 2 + 3 + #include <SDCardManager.h> 4 + 5 + #include <vector> 6 + 7 + class HalStorage { 8 + public: 9 + HalStorage(); 10 + bool begin(); 11 + bool ready() const; 12 + std::vector<String> listFiles(const char* path = "/", int maxFiles = 200); 13 + // Read the entire file at `path` into a String. Returns empty string on failure. 14 + String readFile(const char* path); 15 + // Low-memory helpers: 16 + // Stream the file contents to a `Print` (e.g. `Serial`, or any `Print`-derived object). 17 + // Returns true on success, false on failure. 18 + bool readFileToStream(const char* path, Print& out, size_t chunkSize = 256); 19 + // Read up to `bufferSize-1` bytes into `buffer`, null-terminating it. Returns bytes read. 20 + size_t readFileToBuffer(const char* path, char* buffer, size_t bufferSize, size_t maxBytes = 0); 21 + // Write a string to `path` on the SD card. Overwrites existing file. 22 + // Returns true on success. 23 + bool writeFile(const char* path, const String& content); 24 + // Ensure a directory exists, creating it if necessary. Returns true on success. 25 + bool ensureDirectoryExists(const char* path); 26 + 27 + FsFile open(const char* path, const oflag_t oflag = O_RDONLY); 28 + bool mkdir(const char* path, const bool pFlag = true); 29 + bool exists(const char* path); 30 + bool remove(const char* path); 31 + bool rmdir(const char* path); 32 + 33 + bool openFileForRead(const char* moduleName, const char* path, FsFile& file); 34 + bool openFileForRead(const char* moduleName, const std::string& path, FsFile& file); 35 + bool openFileForRead(const char* moduleName, const String& path, FsFile& file); 36 + bool openFileForWrite(const char* moduleName, const char* path, FsFile& file); 37 + bool openFileForWrite(const char* moduleName, const std::string& path, FsFile& file); 38 + bool openFileForWrite(const char* moduleName, const String& path, FsFile& file); 39 + bool removeDir(const char* path); 40 + 41 + static HalStorage& getInstance() { return instance; } 42 + 43 + private: 44 + static HalStorage instance; 45 + 46 + bool initialized = false; 47 + }; 48 + 49 + #define Storage HalStorage::getInstance() 50 + 51 + // Downstream code must use Storage instead of SdMan 52 + #ifdef SdMan 53 + #undef SdMan 54 + #endif
+4 -4
src/CrossPointSettings.cpp
··· 1 1 #include "CrossPointSettings.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 - #include <SDCardManager.h> 5 5 #include <Serialization.h> 6 6 7 7 #include <cstring> ··· 79 79 80 80 bool CrossPointSettings::saveToFile() const { 81 81 // Make sure the directory exists 82 - SdMan.mkdir("/.crosspoint"); 82 + Storage.mkdir("/.crosspoint"); 83 83 84 84 FsFile outputFile; 85 - if (!SdMan.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) { 85 + if (!Storage.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) { 86 86 return false; 87 87 } 88 88 ··· 127 127 128 128 bool CrossPointSettings::loadFromFile() { 129 129 FsFile inputFile; 130 - if (!SdMan.openFileForRead("CPS", SETTINGS_FILE, inputFile)) { 130 + if (!Storage.openFileForRead("CPS", SETTINGS_FILE, inputFile)) { 131 131 return false; 132 132 } 133 133
+3 -3
src/CrossPointState.cpp
··· 1 1 #include "CrossPointState.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 - #include <SDCardManager.h> 5 5 #include <Serialization.h> 6 6 7 7 namespace { ··· 13 13 14 14 bool CrossPointState::saveToFile() const { 15 15 FsFile outputFile; 16 - if (!SdMan.openFileForWrite("CPS", STATE_FILE, outputFile)) { 16 + if (!Storage.openFileForWrite("CPS", STATE_FILE, outputFile)) { 17 17 return false; 18 18 } 19 19 ··· 28 28 29 29 bool CrossPointState::loadFromFile() { 30 30 FsFile inputFile; 31 - if (!SdMan.openFileForRead("CPS", STATE_FILE, inputFile)) { 31 + if (!Storage.openFileForRead("CPS", STATE_FILE, inputFile)) { 32 32 return false; 33 33 } 34 34
+4 -4
src/RecentBooksStore.cpp
··· 1 1 #include "RecentBooksStore.h" 2 2 3 3 #include <Epub.h> 4 + #include <HalStorage.h> 4 5 #include <HardwareSerial.h> 5 - #include <SDCardManager.h> 6 6 #include <Serialization.h> 7 7 #include <Xtc.h> 8 8 ··· 53 53 54 54 bool RecentBooksStore::saveToFile() const { 55 55 // Make sure the directory exists 56 - SdMan.mkdir("/.crosspoint"); 56 + Storage.mkdir("/.crosspoint"); 57 57 58 58 FsFile outputFile; 59 - if (!SdMan.openFileForWrite("RBS", RECENT_BOOKS_FILE, outputFile)) { 59 + if (!Storage.openFileForWrite("RBS", RECENT_BOOKS_FILE, outputFile)) { 60 60 return false; 61 61 } 62 62 ··· 106 106 107 107 bool RecentBooksStore::loadFromFile() { 108 108 FsFile inputFile; 109 - if (!SdMan.openFileForRead("RBS", RECENT_BOOKS_FILE, inputFile)) { 109 + if (!Storage.openFileForRead("RBS", RECENT_BOOKS_FILE, inputFile)) { 110 110 return false; 111 111 } 112 112
+4 -4
src/WifiCredentialStore.cpp
··· 1 1 #include "WifiCredentialStore.h" 2 2 3 + #include <HalStorage.h> 3 4 #include <HardwareSerial.h> 4 - #include <SDCardManager.h> 5 5 #include <Serialization.h> 6 6 7 7 // Initialize the static instance ··· 29 29 30 30 bool WifiCredentialStore::saveToFile() const { 31 31 // Make sure the directory exists 32 - SdMan.mkdir("/.crosspoint"); 32 + Storage.mkdir("/.crosspoint"); 33 33 34 34 FsFile file; 35 - if (!SdMan.openFileForWrite("WCS", WIFI_FILE, file)) { 35 + if (!Storage.openFileForWrite("WCS", WIFI_FILE, file)) { 36 36 return false; 37 37 } 38 38 ··· 60 60 61 61 bool WifiCredentialStore::loadFromFile() { 62 62 FsFile file; 63 - if (!SdMan.openFileForRead("WCS", WIFI_FILE, file)) { 63 + if (!Storage.openFileForRead("WCS", WIFI_FILE, file)) { 64 64 return false; 65 65 } 66 66
+5 -5
src/activities/boot_sleep/SleepActivity.cpp
··· 2 2 3 3 #include <Epub.h> 4 4 #include <GfxRenderer.h> 5 - #include <SDCardManager.h> 5 + #include <HalStorage.h> 6 6 #include <Txt.h> 7 7 #include <Xtc.h> 8 8 ··· 32 32 33 33 void SleepActivity::renderCustomSleepScreen() const { 34 34 // Check if we have a /sleep directory 35 - auto dir = SdMan.open("/sleep"); 35 + auto dir = Storage.open("/sleep"); 36 36 if (dir && dir.isDirectory()) { 37 37 std::vector<std::string> files; 38 38 char name[500]; ··· 75 75 APP_STATE.saveToFile(); 76 76 const auto filename = "/sleep/" + files[randomFileIndex]; 77 77 FsFile file; 78 - if (SdMan.openFileForRead("SLP", filename, file)) { 78 + if (Storage.openFileForRead("SLP", filename, file)) { 79 79 Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str()); 80 80 delay(100); 81 81 Bitmap bitmap(file, true); ··· 92 92 // Look for sleep.bmp on the root of the sd card to determine if we should 93 93 // render a custom sleep screen instead of the default. 94 94 FsFile file; 95 - if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) { 95 + if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) { 96 96 Bitmap bitmap(file, true); 97 97 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 98 98 Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis()); ··· 262 262 } 263 263 264 264 FsFile file; 265 - if (SdMan.openFileForRead("SLP", coverBmpPath, file)) { 265 + if (Storage.openFileForRead("SLP", coverBmpPath, file)) { 266 266 Bitmap bitmap(file); 267 267 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 268 268 Serial.printf("[SLP] Rendering sleep cover: %s\n", coverBmpPath.c_str());
+3 -3
src/activities/home/HomeActivity.cpp
··· 3 3 #include <Bitmap.h> 4 4 #include <Epub.h> 5 5 #include <GfxRenderer.h> 6 - #include <SDCardManager.h> 6 + #include <HalStorage.h> 7 7 #include <Utf8.h> 8 8 #include <Xtc.h> 9 9 ··· 47 47 } 48 48 49 49 // Skip if file no longer exists 50 - if (!SdMan.exists(book.path.c_str())) { 50 + if (!Storage.exists(book.path.c_str())) { 51 51 continue; 52 52 } 53 53 ··· 64 64 for (RecentBook& book : recentBooks) { 65 65 if (!book.coverBmpPath.empty()) { 66 66 std::string coverPath = UITheme::getCoverThumbPath(book.coverBmpPath, coverHeight); 67 - if (!SdMan.exists(coverPath.c_str())) { 67 + if (!Storage.exists(coverPath.c_str())) { 68 68 // If epub, try to load the metadata for title/author and cover 69 69 if (StringUtils::checkFileExtension(book.path, ".epub")) { 70 70 Epub epub(book.path, "/.crosspoint");
+2 -2
src/activities/home/MyLibraryActivity.cpp
··· 1 1 #include "MyLibraryActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 - #include <SDCardManager.h> 4 + #include <HalStorage.h> 5 5 6 6 #include <algorithm> 7 7 ··· 33 33 void MyLibraryActivity::loadFiles() { 34 34 files.clear(); 35 35 36 - auto root = SdMan.open(basepath.c_str()); 36 + auto root = Storage.open(basepath.c_str()); 37 37 if (!root || !root.isDirectory()) { 38 38 if (root) root.close(); 39 39 return;
+2 -2
src/activities/home/RecentBooksActivity.cpp
··· 1 1 #include "RecentBooksActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 - #include <SDCardManager.h> 4 + #include <HalStorage.h> 5 5 6 6 #include <algorithm> 7 7 ··· 28 28 29 29 for (const auto& book : books) { 30 30 // Skip if file no longer exists 31 - if (!SdMan.exists(book.path.c_str())) { 31 + if (!Storage.exists(book.path.c_str())) { 32 32 continue; 33 33 } 34 34 recentBooks.push_back(book);
+3 -3
src/activities/reader/EpubReaderActivity.cpp
··· 3 3 #include <Epub/Page.h> 4 4 #include <FsHelpers.h> 5 5 #include <GfxRenderer.h> 6 - #include <SDCardManager.h> 6 + #include <HalStorage.h> 7 7 8 8 #include "CrossPointSettings.h" 9 9 #include "CrossPointState.h" ··· 77 77 epub->setupCacheDir(); 78 78 79 79 FsFile f; 80 - if (SdMan.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) { 80 + if (Storage.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) { 81 81 uint8_t data[6]; 82 82 int dataSize = f.read(data, 6); 83 83 if (dataSize == 4 || dataSize == 6) { ··· 654 654 655 655 void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageCount) { 656 656 FsFile f; 657 - if (SdMan.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) { 657 + if (Storage.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) { 658 658 uint8_t data[6]; 659 659 data[0] = currentSpineIndex & 0xFF; 660 660 data[1] = (currentSpineIndex >> 8) & 0xFF;
+5 -3
src/activities/reader/ReaderActivity.cpp
··· 1 1 #include "ReaderActivity.h" 2 2 3 + #include <HalStorage.h> 4 + 3 5 #include "Epub.h" 4 6 #include "EpubReaderActivity.h" 5 7 #include "Txt.h" ··· 27 29 } 28 30 29 31 std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) { 30 - if (!SdMan.exists(path.c_str())) { 32 + if (!Storage.exists(path.c_str())) { 31 33 Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); 32 34 return nullptr; 33 35 } ··· 42 44 } 43 45 44 46 std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) { 45 - if (!SdMan.exists(path.c_str())) { 47 + if (!Storage.exists(path.c_str())) { 46 48 Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); 47 49 return nullptr; 48 50 } ··· 57 59 } 58 60 59 61 std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) { 60 - if (!SdMan.exists(path.c_str())) { 62 + if (!Storage.exists(path.c_str())) { 61 63 Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); 62 64 return nullptr; 63 65 }
+5 -5
src/activities/reader/TxtReaderActivity.cpp
··· 1 1 #include "TxtReaderActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 - #include <SDCardManager.h> 4 + #include <HalStorage.h> 5 5 #include <Serialization.h> 6 6 #include <Utf8.h> 7 7 ··· 565 565 566 566 void TxtReaderActivity::saveProgress() const { 567 567 FsFile f; 568 - if (SdMan.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) { 568 + if (Storage.openFileForWrite("TRS", txt->getCachePath() + "/progress.bin", f)) { 569 569 uint8_t data[4]; 570 570 data[0] = currentPage & 0xFF; 571 571 data[1] = (currentPage >> 8) & 0xFF; ··· 578 578 579 579 void TxtReaderActivity::loadProgress() { 580 580 FsFile f; 581 - if (SdMan.openFileForRead("TRS", txt->getCachePath() + "/progress.bin", f)) { 581 + if (Storage.openFileForRead("TRS", txt->getCachePath() + "/progress.bin", f)) { 582 582 uint8_t data[4]; 583 583 if (f.read(data, 4) == 4) { 584 584 currentPage = data[0] + (data[1] << 8); ··· 609 609 610 610 std::string cachePath = txt->getCachePath() + "/index.bin"; 611 611 FsFile f; 612 - if (!SdMan.openFileForRead("TRS", cachePath, f)) { 612 + if (!Storage.openFileForRead("TRS", cachePath, f)) { 613 613 Serial.printf("[%lu] [TRS] No page index cache found\n", millis()); 614 614 return false; 615 615 } ··· 701 701 void TxtReaderActivity::savePageIndexCache() const { 702 702 std::string cachePath = txt->getCachePath() + "/index.bin"; 703 703 FsFile f; 704 - if (!SdMan.openFileForWrite("TRS", cachePath, f)) { 704 + if (!Storage.openFileForWrite("TRS", cachePath, f)) { 705 705 Serial.printf("[%lu] [TRS] Failed to save page index cache\n", millis()); 706 706 return; 707 707 }
+3 -3
src/activities/reader/XtcReaderActivity.cpp
··· 9 9 10 10 #include <FsHelpers.h> 11 11 #include <GfxRenderer.h> 12 - #include <SDCardManager.h> 12 + #include <HalStorage.h> 13 13 14 14 #include "CrossPointSettings.h" 15 15 #include "CrossPointState.h" ··· 372 372 373 373 void XtcReaderActivity::saveProgress() const { 374 374 FsFile f; 375 - if (SdMan.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) { 375 + if (Storage.openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) { 376 376 uint8_t data[4]; 377 377 data[0] = currentPage & 0xFF; 378 378 data[1] = (currentPage >> 8) & 0xFF; ··· 385 385 386 386 void XtcReaderActivity::loadProgress() { 387 387 FsFile f; 388 - if (SdMan.openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) { 388 + if (Storage.openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) { 389 389 uint8_t data[4]; 390 390 if (f.read(data, 4) == 4) { 391 391 currentPage = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+3 -3
src/activities/settings/ClearCacheActivity.cpp
··· 1 1 #include "ClearCacheActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 + #include <HalStorage.h> 4 5 #include <HardwareSerial.h> 5 - #include <SDCardManager.h> 6 6 7 7 #include "MappedInputManager.h" 8 8 #include "components/UITheme.h" ··· 107 107 Serial.printf("[%lu] [CLEAR_CACHE] Clearing cache...\n", millis()); 108 108 109 109 // Open .crosspoint directory 110 - auto root = SdMan.open("/.crosspoint"); 110 + auto root = Storage.open("/.crosspoint"); 111 111 if (!root || !root.isDirectory()) { 112 112 Serial.printf("[%lu] [CLEAR_CACHE] Failed to open cache directory\n", millis()); 113 113 if (root) root.close(); ··· 132 132 133 133 file.close(); // Close before attempting to delete 134 134 135 - if (SdMan.removeDir(fullPath.c_str())) { 135 + if (Storage.removeDir(fullPath.c_str())) { 136 136 clearedCount++; 137 137 } else { 138 138 Serial.printf("[%lu] [CLEAR_CACHE] Failed to remove: %s\n", millis(), fullPath.c_str());
+2 -2
src/components/themes/BaseTheme.cpp
··· 1 1 #include "BaseTheme.h" 2 2 3 3 #include <GfxRenderer.h> 4 - #include <SDCardManager.h> 4 + #include <HalStorage.h> 5 5 #include <Utf8.h> 6 6 7 7 #include <cstdint> ··· 308 308 309 309 // First time: load cover from SD and render 310 310 FsFile file; 311 - if (SdMan.openFileForRead("HOME", coverBmpPath, file)) { 311 + if (Storage.openFileForRead("HOME", coverBmpPath, file)) { 312 312 Bitmap bitmap(file); 313 313 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 314 314 Serial.printf("Rendering bmp\n");
+2 -2
src/components/themes/lyra/LyraTheme.cpp
··· 1 1 #include "LyraTheme.h" 2 2 3 3 #include <GfxRenderer.h> 4 - #include <SDCardManager.h> 4 + #include <HalStorage.h> 5 5 6 6 #include <cstdint> 7 7 #include <string> ··· 283 283 284 284 // First time: load cover from SD and render 285 285 FsFile file; 286 - if (SdMan.openFileForRead("HOME", coverBmpPath, file)) { 286 + if (Storage.openFileForRead("HOME", coverBmpPath, file)) { 287 287 Bitmap bitmap(file); 288 288 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 289 289 float coverHeight = static_cast<float>(bitmap.getHeight());
+2 -2
src/main.cpp
··· 3 3 #include <GfxRenderer.h> 4 4 #include <HalDisplay.h> 5 5 #include <HalGPIO.h> 6 - #include <SDCardManager.h> 6 + #include <HalStorage.h> 7 7 #include <SPI.h> 8 8 #include <builtinFonts/all.h> 9 9 ··· 293 293 294 294 // SD Card Initialization 295 295 // We need 6 open files concurrently when parsing a new chapter 296 - if (!SdMan.begin()) { 296 + if (!Storage.begin()) { 297 297 Serial.printf("[%lu] [ ] SD card initialization failed\n", millis()); 298 298 setupDisplayAndFonts(); 299 299 exitActivity();
+26 -26
src/network/CrossPointWebServer.cpp
··· 3 3 #include <ArduinoJson.h> 4 4 #include <Epub.h> 5 5 #include <FsHelpers.h> 6 - #include <SDCardManager.h> 6 + #include <HalStorage.h> 7 7 #include <WiFi.h> 8 8 #include <esp_task_wdt.h> 9 9 ··· 316 316 } 317 317 318 318 void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const { 319 - FsFile root = SdMan.open(path); 319 + FsFile root = Storage.open(path); 320 320 if (!root) { 321 321 Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path); 322 322 return; ··· 458 458 } 459 459 } 460 460 461 - if (!SdMan.exists(itemPath.c_str())) { 461 + if (!Storage.exists(itemPath.c_str())) { 462 462 server->send(404, "text/plain", "Item not found"); 463 463 return; 464 464 } 465 465 466 - FsFile file = SdMan.open(itemPath.c_str()); 466 + FsFile file = Storage.open(itemPath.c_str()); 467 467 if (!file) { 468 468 server->send(500, "text/plain", "Failed to open file"); 469 469 return; ··· 574 574 575 575 // Check if file already exists - SD operations can be slow 576 576 esp_task_wdt_reset(); 577 - if (SdMan.exists(filePath.c_str())) { 577 + if (Storage.exists(filePath.c_str())) { 578 578 Serial.printf("[%lu] [WEB] [UPLOAD] Overwriting existing file: %s\n", millis(), filePath.c_str()); 579 579 esp_task_wdt_reset(); 580 - SdMan.remove(filePath.c_str()); 580 + Storage.remove(filePath.c_str()); 581 581 } 582 582 583 583 // Open file for writing - this can be slow due to FAT cluster allocation 584 584 esp_task_wdt_reset(); 585 - if (!SdMan.openFileForWrite("WEB", filePath, state.file)) { 585 + if (!Storage.openFileForWrite("WEB", filePath, state.file)) { 586 586 state.error = "Failed to create file on SD card"; 587 587 Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str()); 588 588 return; ··· 660 660 String filePath = state.path; 661 661 if (!filePath.endsWith("/")) filePath += "/"; 662 662 filePath += state.fileName; 663 - SdMan.remove(filePath.c_str()); 663 + Storage.remove(filePath.c_str()); 664 664 } 665 665 state.error = "Upload aborted"; 666 666 Serial.printf("[%lu] [WEB] Upload aborted\n", millis()); ··· 711 711 Serial.printf("[%lu] [WEB] Creating folder: %s\n", millis(), folderPath.c_str()); 712 712 713 713 // Check if already exists 714 - if (SdMan.exists(folderPath.c_str())) { 714 + if (Storage.exists(folderPath.c_str())) { 715 715 server->send(400, "text/plain", "Folder already exists"); 716 716 return; 717 717 } 718 718 719 719 // Create the folder 720 - if (SdMan.mkdir(folderPath.c_str())) { 720 + if (Storage.mkdir(folderPath.c_str())) { 721 721 Serial.printf("[%lu] [WEB] Folder created successfully: %s\n", millis(), folderPath.c_str()); 722 722 server->send(200, "text/plain", "Folder created: " + folderName); 723 723 } else { ··· 763 763 return; 764 764 } 765 765 766 - if (!SdMan.exists(itemPath.c_str())) { 766 + if (!Storage.exists(itemPath.c_str())) { 767 767 server->send(404, "text/plain", "Item not found"); 768 768 return; 769 769 } 770 770 771 - FsFile file = SdMan.open(itemPath.c_str()); 771 + FsFile file = Storage.open(itemPath.c_str()); 772 772 if (!file) { 773 773 server->send(500, "text/plain", "Failed to open file"); 774 774 return; ··· 789 789 } 790 790 newPath += newName; 791 791 792 - if (SdMan.exists(newPath.c_str())) { 792 + if (Storage.exists(newPath.c_str())) { 793 793 file.close(); 794 794 server->send(409, "text/plain", "Target already exists"); 795 795 return; ··· 839 839 } 840 840 } 841 841 842 - if (!SdMan.exists(itemPath.c_str())) { 842 + if (!Storage.exists(itemPath.c_str())) { 843 843 server->send(404, "text/plain", "Item not found"); 844 844 return; 845 845 } 846 846 847 - FsFile file = SdMan.open(itemPath.c_str()); 847 + FsFile file = Storage.open(itemPath.c_str()); 848 848 if (!file) { 849 849 server->send(500, "text/plain", "Failed to open file"); 850 850 return; ··· 855 855 return; 856 856 } 857 857 858 - if (!SdMan.exists(destPath.c_str())) { 858 + if (!Storage.exists(destPath.c_str())) { 859 859 file.close(); 860 860 server->send(404, "text/plain", "Destination not found"); 861 861 return; 862 862 } 863 - FsFile destDir = SdMan.open(destPath.c_str()); 863 + FsFile destDir = Storage.open(destPath.c_str()); 864 864 if (!destDir || !destDir.isDirectory()) { 865 865 if (destDir) { 866 866 destDir.close(); ··· 882 882 server->send(200, "text/plain", "Already in destination"); 883 883 return; 884 884 } 885 - if (SdMan.exists(newPath.c_str())) { 885 + if (Storage.exists(newPath.c_str())) { 886 886 file.close(); 887 887 server->send(409, "text/plain", "Target already exists"); 888 888 return; ··· 942 942 } 943 943 944 944 // Check if item exists 945 - if (!SdMan.exists(itemPath.c_str())) { 945 + if (!Storage.exists(itemPath.c_str())) { 946 946 Serial.printf("[%lu] [WEB] Delete failed - item not found: %s\n", millis(), itemPath.c_str()); 947 947 server->send(404, "text/plain", "Item not found"); 948 948 return; ··· 954 954 955 955 if (itemType == "folder") { 956 956 // For folders, try to remove (will fail if not empty) 957 - FsFile dir = SdMan.open(itemPath.c_str()); 957 + FsFile dir = Storage.open(itemPath.c_str()); 958 958 if (dir && dir.isDirectory()) { 959 959 // Check if folder is empty 960 960 FsFile entry = dir.openNextFile(); ··· 968 968 } 969 969 dir.close(); 970 970 } 971 - success = SdMan.rmdir(itemPath.c_str()); 971 + success = Storage.rmdir(itemPath.c_str()); 972 972 } else { 973 973 // For files, use remove 974 - success = SdMan.remove(itemPath.c_str()); 974 + success = Storage.remove(itemPath.c_str()); 975 975 } 976 976 977 977 if (success) { ··· 1007 1007 String filePath = wsUploadPath; 1008 1008 if (!filePath.endsWith("/")) filePath += "/"; 1009 1009 filePath += wsUploadFileName; 1010 - SdMan.remove(filePath.c_str()); 1010 + Storage.remove(filePath.c_str()); 1011 1011 Serial.printf("[%lu] [WS] Deleted incomplete upload: %s\n", millis(), filePath.c_str()); 1012 1012 } 1013 1013 wsUploadInProgress = false; ··· 1051 1051 1052 1052 // Check if file exists and remove it 1053 1053 esp_task_wdt_reset(); 1054 - if (SdMan.exists(filePath.c_str())) { 1055 - SdMan.remove(filePath.c_str()); 1054 + if (Storage.exists(filePath.c_str())) { 1055 + Storage.remove(filePath.c_str()); 1056 1056 } 1057 1057 1058 1058 // Open file for writing 1059 1059 esp_task_wdt_reset(); 1060 - if (!SdMan.openFileForWrite("WS", filePath, wsUploadFile)) { 1060 + if (!Storage.openFileForWrite("WS", filePath, wsUploadFile)) { 1061 1061 wsServer->sendTXT(num, "ERROR:Failed to create file"); 1062 1062 wsUploadInProgress = false; 1063 1063 return;
+1 -1
src/network/CrossPointWebServer.h
··· 1 1 #pragma once 2 2 3 - #include <SDCardManager.h> 3 + #include <HalStorage.h> 4 4 #include <WebServer.h> 5 5 #include <WebSocketsServer.h> 6 6 #include <WiFiUdp.h>
+6 -6
src/network/HttpDownloader.cpp
··· 100 100 Serial.printf("[%lu] [HTTP] Content-Length: %zu\n", millis(), contentLength); 101 101 102 102 // Remove existing file if present 103 - if (SdMan.exists(destPath.c_str())) { 104 - SdMan.remove(destPath.c_str()); 103 + if (Storage.exists(destPath.c_str())) { 104 + Storage.remove(destPath.c_str()); 105 105 } 106 106 107 107 // Open file for writing 108 108 FsFile file; 109 - if (!SdMan.openFileForWrite("HTTP", destPath.c_str(), file)) { 109 + if (!Storage.openFileForWrite("HTTP", destPath.c_str(), file)) { 110 110 Serial.printf("[%lu] [HTTP] Failed to open file for writing\n", millis()); 111 111 http.end(); 112 112 return FILE_ERROR; ··· 117 117 if (!stream) { 118 118 Serial.printf("[%lu] [HTTP] Failed to get stream\n", millis()); 119 119 file.close(); 120 - SdMan.remove(destPath.c_str()); 120 + Storage.remove(destPath.c_str()); 121 121 http.end(); 122 122 return HTTP_ERROR; 123 123 } ··· 145 145 if (written != bytesRead) { 146 146 Serial.printf("[%lu] [HTTP] Write failed: wrote %zu of %zu bytes\n", millis(), written, bytesRead); 147 147 file.close(); 148 - SdMan.remove(destPath.c_str()); 148 + Storage.remove(destPath.c_str()); 149 149 http.end(); 150 150 return FILE_ERROR; 151 151 } ··· 165 165 // Verify download size if known 166 166 if (contentLength > 0 && downloaded != contentLength) { 167 167 Serial.printf("[%lu] [HTTP] Size mismatch: got %zu, expected %zu\n", millis(), downloaded, contentLength); 168 - SdMan.remove(destPath.c_str()); 168 + Storage.remove(destPath.c_str()); 169 169 return HTTP_ERROR; 170 170 } 171 171
+1 -1
src/network/HttpDownloader.h
··· 1 1 #pragma once 2 - #include <SDCardManager.h> 2 + #include <HalStorage.h> 3 3 4 4 #include <functional> 5 5 #include <string>