Compare commits

...

6 Commits

Author SHA1 Message Date
Xuan-Son Nguyen
b8ec0b73c6
Merge 9cd9dc1f99 into 78d6e5931c 2026-02-03 22:09:52 +00:00
Jake Kenneally
78d6e5931c
fix: Correct debugging_monitor.py script instructions (#676)
Some checks are pending
CI / build (push) Waiting to run
## Summary

**What is the goal of this PR?**
- Minor correction to the `debugging_monitor.py` script instructions

**What changes are included?**
- `pyserial` should be installed, NOT `serial`, which is a [different
lib](https://pypi.org/project/serial/)
- Added macOS serial port

## Additional Context

- Just a minor docs update. I can confirm the debugging script is
working great on macOS

---

### 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-04 00:33:20 +03:00
Luke Stein
dac11c3fdd
fix: Correct instruction text to match actual button text (#672)
## Summary

* Instruction text says "Press OK to scan again" but button label is
actually "Connect" (not OK)
* Corrects instruction text

---

### AI Usage

Did you use AI tools to help write this code? **No**
2026-02-04 00:32:52 +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
20 changed files with 219 additions and 98 deletions

View File

@ -102,13 +102,18 @@ After flashing the new features, its recommended to capture detailed logs fro
First, make sure all required Python packages are installed:
```python
python3 -m pip install serial colorama matplotlib
python3 -m pip install pyserial colorama matplotlib
```
after that run the script:
```sh
# For Linux
# This was tested on Debian and should work on most Linux systems.
python3 scripts/debugging_monitor.py
# For macOS
python3 scripts/debugging_monitor.py /dev/cu.usbmodem2101
```
This was tested on Debian and should work on most Linux systems. Minor adjustments may be required for Windows or macOS.
Minor adjustments may be required for Windows.
## Internals

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -520,7 +520,7 @@ void WifiSelectionActivity::renderNetworkList() const {
const auto height = renderer.getLineHeight(UI_10_FONT_ID);
const auto top = (pageHeight - height) / 2;
renderer.drawCenteredText(UI_10_FONT_ID, top, "No networks found");
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Press OK to scan again");
renderer.drawCenteredText(SMALL_FONT_ID, top + height + 10, "Press Connect to scan again");
} else {
// Calculate how many networks we can display
constexpr int startY = 60;

View File

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

View File

@ -1,5 +1,7 @@
#include "ReaderActivity.h"
#include <HalStorage.h>
#include "Epub.h"
#include "EpubReaderActivity.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) {
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());
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) {
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());
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) {
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());
return nullptr;
}

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
#include <GfxRenderer.h>
#include <HalDisplay.h>
#include <HalGPIO.h>
#include <SDCardManager.h>
#include <HalStorage.h>
#include <SPI.h>
#include <builtinFonts/all.h>
@ -283,7 +283,7 @@ void setup() {
// SD Card Initialization
// 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());
setupDisplayAndFonts();
exitActivity();

View File

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

View File

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

View File

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