Compare commits

...

5 Commits

Author SHA1 Message Date
Xuan-Son Nguyen
5dd65dbc8f
Merge 9cd9dc1f99 into d403044f76 2026-02-03 16:25:51 +01:00
Aaron Cunliffe
d403044f76
fix: Increase network SSID display length (#670)
Some checks are pending
CI / build (push) Waiting to run
## Rationale 

I have 2 wifi access points with almost identical names, just one has
`_EXT` at the end of it. With the current display limit of 13 characters
before adding ellipsis, I can't tell which is which.

Before device screenshot with masked SSIDs:
<img
src="https://github.com/user-attachments/assets/3c5cbbaa-b2f6-412f-b5a8-6278963bd0f2"
width="300">


## Summary

Adjusted displayed length from 13 characters to 30 in the Wifi selection
screen - I've left some space for potential proportional font changes in
the future

After image with masked SSIDs:
<img
src="https://github.com/user-attachments/assets/c5f0712b-bbd3-4eec-9820-4693fae90c9f"
width="300">

---

### 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 >**_
2026-02-03 18:24:23 +03:00
Xuan Son Nguyen
9cd9dc1f99 clang format 2026-02-01 23:51:12 +01:00
Xuan Son Nguyen
3cc9f8d6fb Merge branch 'master' into xsn/hal_storage 2026-02-01 23:40:52 +01:00
Xuan Son Nguyen
f751f3f2ad feat: add HalStorage 2026-02-01 23:39:04 +01:00
19 changed files with 213 additions and 97 deletions

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

@ -0,0 +1,63 @@
#include "HalStorage.h"
#include <SDCardManager.h>
HalStorage HalStorage::instance;
HalStorage::HalStorage() {}
bool HalStorage::begin() { return SdMan.begin(); }
bool HalStorage::ready() const { return SdMan.ready(); }
std::vector<String> HalStorage::listFiles(const char* path, int maxFiles) { return SdMan.listFiles(path, maxFiles); }
String HalStorage::readFile(const char* path) { return SdMan.readFile(path); }
bool HalStorage::readFileToStream(const char* path, Print& out, size_t chunkSize) {
return SdMan.readFileToStream(path, out, chunkSize);
}
size_t HalStorage::readFileToBuffer(const char* path, char* buffer, size_t bufferSize, size_t maxBytes) {
return SdMan.readFileToBuffer(path, buffer, bufferSize, maxBytes);
}
bool HalStorage::writeFile(const char* path, const String& content) { return SdMan.writeFile(path, content); }
bool HalStorage::ensureDirectoryExists(const char* path) { return SdMan.ensureDirectoryExists(path); }
File HalStorage::open(const char* path, const oflag_t oflag) { return SdMan.open(path, oflag); }
bool HalStorage::mkdir(const char* path, const bool pFlag) { return SdMan.mkdir(path, pFlag); }
bool HalStorage::exists(const char* path) { return SdMan.exists(path); }
bool HalStorage::remove(const char* path) { return SdMan.remove(path); }
bool HalStorage::rmdir(const char* path) { return SdMan.rmdir(path); }
bool HalStorage::openFileForRead(const char* moduleName, const char* path, File& file) {
return SdMan.openFileForRead(moduleName, path, file);
}
bool HalStorage::openFileForRead(const char* moduleName, const std::string& path, File& file) {
return openFileForRead(moduleName, path.c_str(), file);
}
bool HalStorage::openFileForRead(const char* moduleName, const String& path, File& file) {
return openFileForRead(moduleName, path.c_str(), file);
}
bool HalStorage::openFileForWrite(const char* moduleName, const char* path, File& file) {
return SdMan.openFileForWrite(moduleName, path, file);
}
bool HalStorage::openFileForWrite(const char* moduleName, const std::string& path, File& file) {
return openFileForWrite(moduleName, path.c_str(), file);
}
bool HalStorage::openFileForWrite(const char* moduleName, const String& path, File& file) {
return openFileForWrite(moduleName, path.c_str(), file);
}
bool HalStorage::removeDir(const char* path) { return SdMan.removeDir(path); }

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

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

View File

@ -1,7 +1,7 @@
#include "CrossPointSettings.h" #include "CrossPointSettings.h"
#include <HalStorage.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include <SDCardManager.h>
#include <Serialization.h> #include <Serialization.h>
#include <cstring> #include <cstring>
@ -11,7 +11,7 @@
// Initialize the static instance // Initialize the static instance
CrossPointSettings CrossPointSettings::instance; CrossPointSettings CrossPointSettings::instance;
void readAndValidate(FsFile& file, uint8_t& member, const uint8_t maxValue) { void readAndValidate(File& file, uint8_t& member, const uint8_t maxValue) {
uint8_t tempValue; uint8_t tempValue;
serialization::readPod(file, tempValue); serialization::readPod(file, tempValue);
if (tempValue < maxValue) { if (tempValue < maxValue) {
@ -28,10 +28,10 @@ constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
bool CrossPointSettings::saveToFile() const { bool CrossPointSettings::saveToFile() const {
// Make sure the directory exists // Make sure the directory exists
SdMan.mkdir("/.crosspoint"); Storage.mkdir("/.crosspoint");
FsFile outputFile; File outputFile;
if (!SdMan.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) { if (!Storage.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) {
return false; return false;
} }
@ -68,8 +68,8 @@ bool CrossPointSettings::saveToFile() const {
} }
bool CrossPointSettings::loadFromFile() { bool CrossPointSettings::loadFromFile() {
FsFile inputFile; File inputFile;
if (!SdMan.openFileForRead("CPS", SETTINGS_FILE, inputFile)) { if (!Storage.openFileForRead("CPS", SETTINGS_FILE, inputFile)) {
return false; return false;
} }

View File

@ -1,7 +1,7 @@
#include "CrossPointState.h" #include "CrossPointState.h"
#include <HalStorage.h>
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include <SDCardManager.h>
#include <Serialization.h> #include <Serialization.h>
namespace { namespace {
@ -12,8 +12,8 @@ constexpr char STATE_FILE[] = "/.crosspoint/state.bin";
CrossPointState CrossPointState::instance; CrossPointState CrossPointState::instance;
bool CrossPointState::saveToFile() const { bool CrossPointState::saveToFile() const {
FsFile outputFile; File outputFile;
if (!SdMan.openFileForWrite("CPS", STATE_FILE, outputFile)) { if (!Storage.openFileForWrite("CPS", STATE_FILE, outputFile)) {
return false; return false;
} }
@ -25,8 +25,8 @@ bool CrossPointState::saveToFile() const {
} }
bool CrossPointState::loadFromFile() { bool CrossPointState::loadFromFile() {
FsFile inputFile; File inputFile;
if (!SdMan.openFileForRead("CPS", STATE_FILE, inputFile)) { if (!Storage.openFileForRead("CPS", STATE_FILE, inputFile)) {
return false; return false;
} }

View File

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

View File

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

View File

@ -2,7 +2,7 @@
#include <Epub.h> #include <Epub.h>
#include <GfxRenderer.h> #include <GfxRenderer.h>
#include <SDCardManager.h> #include <HalStorage.h>
#include <Txt.h> #include <Txt.h>
#include <Xtc.h> #include <Xtc.h>
@ -35,7 +35,7 @@ void SleepActivity::onEnter() {
void SleepActivity::renderCustomSleepScreen() const { void SleepActivity::renderCustomSleepScreen() const {
// Check if we have a /sleep directory // Check if we have a /sleep directory
auto dir = SdMan.open("/sleep"); auto dir = Storage.open("/sleep");
if (dir && dir.isDirectory()) { if (dir && dir.isDirectory()) {
std::vector<std::string> files; std::vector<std::string> files;
char name[500]; char name[500];
@ -77,8 +77,8 @@ void SleepActivity::renderCustomSleepScreen() const {
APP_STATE.lastSleepImage = randomFileIndex; APP_STATE.lastSleepImage = randomFileIndex;
APP_STATE.saveToFile(); APP_STATE.saveToFile();
const auto filename = "/sleep/" + files[randomFileIndex]; const auto filename = "/sleep/" + files[randomFileIndex];
FsFile file; File file;
if (SdMan.openFileForRead("SLP", filename, file)) { if (Storage.openFileForRead("SLP", filename, file)) {
Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str()); Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
delay(100); delay(100);
Bitmap bitmap(file, true); Bitmap bitmap(file, true);
@ -94,8 +94,8 @@ void SleepActivity::renderCustomSleepScreen() const {
// Look for sleep.bmp on the root of the sd card to determine if we should // 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. // render a custom sleep screen instead of the default.
FsFile file; File file;
if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) { if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) {
Bitmap bitmap(file, true); Bitmap bitmap(file, true);
if (bitmap.parseHeaders() == BmpReaderError::Ok) { if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis()); Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis());
@ -253,8 +253,8 @@ void SleepActivity::renderCoverSleepScreen() const {
return renderDefaultSleepScreen(); return renderDefaultSleepScreen();
} }
FsFile file; File file;
if (SdMan.openFileForRead("SLP", coverBmpPath, file)) { if (Storage.openFileForRead("SLP", coverBmpPath, file)) {
Bitmap bitmap(file); Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) { if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("[SLP] Rendering sleep cover: %s\n", coverBmpPath); Serial.printf("[SLP] Rendering sleep cover: %s\n", coverBmpPath);

View File

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

View File

@ -1,7 +1,7 @@
#include "MyLibraryActivity.h" #include "MyLibraryActivity.h"
#include <GfxRenderer.h> #include <GfxRenderer.h>
#include <SDCardManager.h> #include <HalStorage.h>
#include <algorithm> #include <algorithm>
@ -72,7 +72,7 @@ void MyLibraryActivity::loadRecentBooks() {
for (const auto& book : books) { for (const auto& book : books) {
// Skip if file no longer exists // Skip if file no longer exists
if (!SdMan.exists(book.path.c_str())) { if (!Storage.exists(book.path.c_str())) {
continue; continue;
} }
recentBooks.push_back(book); recentBooks.push_back(book);
@ -82,7 +82,7 @@ void MyLibraryActivity::loadRecentBooks() {
void MyLibraryActivity::loadFiles() { void MyLibraryActivity::loadFiles() {
files.clear(); files.clear();
auto root = SdMan.open(basepath.c_str()); auto root = Storage.open(basepath.c_str());
if (!root || !root.isDirectory()) { if (!root || !root.isDirectory()) {
if (root) root.close(); if (root) root.close();
return; return;

View File

@ -546,8 +546,8 @@ void WifiSelectionActivity::renderNetworkList() const {
// Draw network name (truncate if too long) // Draw network name (truncate if too long)
std::string displayName = network.ssid; std::string displayName = network.ssid;
if (displayName.length() > 16) { if (displayName.length() > 33) {
displayName.replace(13, displayName.length() - 13, "..."); displayName.replace(30, displayName.length() - 30, "...");
} }
renderer.drawText(UI_10_FONT_ID, 20, networkY, displayName.c_str()); renderer.drawText(UI_10_FONT_ID, 20, networkY, displayName.c_str());

View File

@ -3,7 +3,7 @@
#include <Epub/Page.h> #include <Epub/Page.h>
#include <FsHelpers.h> #include <FsHelpers.h>
#include <GfxRenderer.h> #include <GfxRenderer.h>
#include <SDCardManager.h> #include <HalStorage.h>
#include "CrossPointSettings.h" #include "CrossPointSettings.h"
#include "CrossPointState.h" #include "CrossPointState.h"
@ -56,8 +56,8 @@ void EpubReaderActivity::onEnter() {
epub->setupCacheDir(); epub->setupCacheDir();
FsFile f; File f;
if (SdMan.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) { if (Storage.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
uint8_t data[6]; uint8_t data[6];
int dataSize = f.read(data, 6); int dataSize = f.read(data, 6);
if (dataSize == 4 || dataSize == 6) { if (dataSize == 4 || dataSize == 6) {
@ -435,7 +435,7 @@ void EpubReaderActivity::renderScreen() {
void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageCount) { void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageCount) {
FsFile f; FsFile f;
if (SdMan.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) { if (Storage.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
uint8_t data[6]; uint8_t data[6];
data[0] = currentSpineIndex & 0xFF; data[0] = currentSpineIndex & 0xFF;
data[1] = (currentSpineIndex >> 8) & 0xFF; data[1] = (currentSpineIndex >> 8) & 0xFF;

View File

@ -1,5 +1,7 @@
#include "ReaderActivity.h" #include "ReaderActivity.h"
#include <HalStorage.h>
#include "Epub.h" #include "Epub.h"
#include "EpubReaderActivity.h" #include "EpubReaderActivity.h"
#include "Txt.h" #include "Txt.h"
@ -27,7 +29,7 @@ bool ReaderActivity::isTxtFile(const std::string& path) {
} }
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) { std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!SdMan.exists(path.c_str())) { if (!Storage.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr; return nullptr;
} }
@ -42,7 +44,7 @@ std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
} }
std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) { std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
if (!SdMan.exists(path.c_str())) { if (!Storage.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr; return nullptr;
} }
@ -57,7 +59,7 @@ std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
} }
std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) { std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
if (!SdMan.exists(path.c_str())) { if (!Storage.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
return nullptr; return nullptr;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <Epub.h> #include <Epub.h>
#include <FsHelpers.h> #include <FsHelpers.h>
#include <SDCardManager.h> #include <HalStorage.h>
#include <WiFi.h> #include <WiFi.h>
#include <esp_task_wdt.h> #include <esp_task_wdt.h>
@ -25,7 +25,7 @@ constexpr uint16_t LOCAL_UDP_PORT = 8134;
CrossPointWebServer* wsInstance = nullptr; CrossPointWebServer* wsInstance = nullptr;
// WebSocket upload state // WebSocket upload state
FsFile wsUploadFile; File wsUploadFile;
String wsUploadFileName; String wsUploadFileName;
String wsUploadPath; String wsUploadPath;
size_t wsUploadSize = 0; size_t wsUploadSize = 0;
@ -280,7 +280,7 @@ void CrossPointWebServer::handleStatus() const {
} }
void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const { void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const {
FsFile root = SdMan.open(path); File root = Storage.open(path);
if (!root) { if (!root) {
Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path); Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path);
return; return;
@ -294,7 +294,7 @@ void CrossPointWebServer::scanFiles(const char* path, const std::function<void(F
Serial.printf("[%lu] [WEB] Scanning files in: %s\n", millis(), path); Serial.printf("[%lu] [WEB] Scanning files in: %s\n", millis(), path);
FsFile file = root.openNextFile(); File file = root.openNextFile();
char name[500]; char name[500];
while (file) { while (file) {
file.getName(name, sizeof(name)); file.getName(name, sizeof(name));
@ -422,12 +422,12 @@ void CrossPointWebServer::handleDownload() const {
} }
} }
if (!SdMan.exists(itemPath.c_str())) { if (!Storage.exists(itemPath.c_str())) {
server->send(404, "text/plain", "Item not found"); server->send(404, "text/plain", "Item not found");
return; return;
} }
FsFile file = SdMan.open(itemPath.c_str()); File file = Storage.open(itemPath.c_str());
if (!file) { if (!file) {
server->send(500, "text/plain", "Failed to open file"); server->send(500, "text/plain", "Failed to open file");
return; return;
@ -459,7 +459,7 @@ void CrossPointWebServer::handleDownload() const {
} }
// Static variables for upload handling // Static variables for upload handling
static FsFile uploadFile; static File uploadFile;
static String uploadFileName; static String uploadFileName;
static String uploadPath = "/"; static String uploadPath = "/";
static size_t uploadSize = 0; static size_t uploadSize = 0;
@ -553,15 +553,15 @@ void CrossPointWebServer::handleUpload() const {
// Check if file already exists - SD operations can be slow // Check if file already exists - SD operations can be slow
esp_task_wdt_reset(); esp_task_wdt_reset();
if (SdMan.exists(filePath.c_str())) { if (Storage.exists(filePath.c_str())) {
Serial.printf("[%lu] [WEB] [UPLOAD] Overwriting existing file: %s\n", millis(), filePath.c_str()); Serial.printf("[%lu] [WEB] [UPLOAD] Overwriting existing file: %s\n", millis(), filePath.c_str());
esp_task_wdt_reset(); esp_task_wdt_reset();
SdMan.remove(filePath.c_str()); Storage.remove(filePath.c_str());
} }
// Open file for writing - this can be slow due to FAT cluster allocation // Open file for writing - this can be slow due to FAT cluster allocation
esp_task_wdt_reset(); esp_task_wdt_reset();
if (!SdMan.openFileForWrite("WEB", filePath, uploadFile)) { if (!Storage.openFileForWrite("WEB", filePath, uploadFile)) {
uploadError = "Failed to create file on SD card"; uploadError = "Failed to create file on SD card";
Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str()); Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str());
return; return;
@ -639,7 +639,7 @@ void CrossPointWebServer::handleUpload() const {
String filePath = uploadPath; String filePath = uploadPath;
if (!filePath.endsWith("/")) filePath += "/"; if (!filePath.endsWith("/")) filePath += "/";
filePath += uploadFileName; filePath += uploadFileName;
SdMan.remove(filePath.c_str()); Storage.remove(filePath.c_str());
} }
uploadError = "Upload aborted"; uploadError = "Upload aborted";
Serial.printf("[%lu] [WEB] Upload aborted\n", millis()); Serial.printf("[%lu] [WEB] Upload aborted\n", millis());
@ -690,13 +690,13 @@ void CrossPointWebServer::handleCreateFolder() const {
Serial.printf("[%lu] [WEB] Creating folder: %s\n", millis(), folderPath.c_str()); Serial.printf("[%lu] [WEB] Creating folder: %s\n", millis(), folderPath.c_str());
// Check if already exists // Check if already exists
if (SdMan.exists(folderPath.c_str())) { if (Storage.exists(folderPath.c_str())) {
server->send(400, "text/plain", "Folder already exists"); server->send(400, "text/plain", "Folder already exists");
return; return;
} }
// Create the folder // Create the folder
if (SdMan.mkdir(folderPath.c_str())) { if (Storage.mkdir(folderPath.c_str())) {
Serial.printf("[%lu] [WEB] Folder created successfully: %s\n", millis(), folderPath.c_str()); Serial.printf("[%lu] [WEB] Folder created successfully: %s\n", millis(), folderPath.c_str());
server->send(200, "text/plain", "Folder created: " + folderName); server->send(200, "text/plain", "Folder created: " + folderName);
} else { } else {
@ -746,7 +746,7 @@ void CrossPointWebServer::handleDelete() const {
} }
// Check if item exists // Check if item exists
if (!SdMan.exists(itemPath.c_str())) { if (!Storage.exists(itemPath.c_str())) {
Serial.printf("[%lu] [WEB] Delete failed - item not found: %s\n", millis(), itemPath.c_str()); Serial.printf("[%lu] [WEB] Delete failed - item not found: %s\n", millis(), itemPath.c_str());
server->send(404, "text/plain", "Item not found"); server->send(404, "text/plain", "Item not found");
return; return;
@ -758,10 +758,10 @@ void CrossPointWebServer::handleDelete() const {
if (itemType == "folder") { if (itemType == "folder") {
// For folders, try to remove (will fail if not empty) // For folders, try to remove (will fail if not empty)
FsFile dir = SdMan.open(itemPath.c_str()); File dir = Storage.open(itemPath.c_str());
if (dir && dir.isDirectory()) { if (dir && dir.isDirectory()) {
// Check if folder is empty // Check if folder is empty
FsFile entry = dir.openNextFile(); File entry = dir.openNextFile();
if (entry) { if (entry) {
// Folder is not empty // Folder is not empty
entry.close(); entry.close();
@ -772,10 +772,10 @@ void CrossPointWebServer::handleDelete() const {
} }
dir.close(); dir.close();
} }
success = SdMan.rmdir(itemPath.c_str()); success = Storage.rmdir(itemPath.c_str());
} else { } else {
// For files, use remove // For files, use remove
success = SdMan.remove(itemPath.c_str()); success = Storage.remove(itemPath.c_str());
} }
if (success) { if (success) {
@ -811,7 +811,7 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
String filePath = wsUploadPath; String filePath = wsUploadPath;
if (!filePath.endsWith("/")) filePath += "/"; if (!filePath.endsWith("/")) filePath += "/";
filePath += wsUploadFileName; filePath += wsUploadFileName;
SdMan.remove(filePath.c_str()); Storage.remove(filePath.c_str());
Serial.printf("[%lu] [WS] Deleted incomplete upload: %s\n", millis(), filePath.c_str()); Serial.printf("[%lu] [WS] Deleted incomplete upload: %s\n", millis(), filePath.c_str());
} }
wsUploadInProgress = false; wsUploadInProgress = false;
@ -855,13 +855,13 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
// Check if file exists and remove it // Check if file exists and remove it
esp_task_wdt_reset(); esp_task_wdt_reset();
if (SdMan.exists(filePath.c_str())) { if (Storage.exists(filePath.c_str())) {
SdMan.remove(filePath.c_str()); Storage.remove(filePath.c_str());
} }
// Open file for writing // Open file for writing
esp_task_wdt_reset(); esp_task_wdt_reset();
if (!SdMan.openFileForWrite("WS", filePath, wsUploadFile)) { if (!Storage.openFileForWrite("WS", filePath, wsUploadFile)) {
wsServer->sendTXT(num, "ERROR:Failed to create file"); wsServer->sendTXT(num, "ERROR:Failed to create file");
wsUploadInProgress = false; wsUploadInProgress = false;
return; return;

View File

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

View File

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