Add exFAT support (#150)

## Summary

* Swap to updated SDCardManager which uses SdFat
* Add exFAT support
  * Swap to using FsFile everywhere
* Use newly exposed `SdMan` macro to get to static instance of
SDCardManager
* Move a bunch of FsHelpers up to SDCardManager
This commit is contained in:
Dave Allie
2025-12-30 15:09:30 +10:00
committed by GitHub
parent d4bd119950
commit fb5fc32c5d
50 changed files with 289 additions and 355 deletions

View File

@@ -5,8 +5,7 @@
#include <string>
#include <utility>
#include "../MappedInputManager.h"
class MappedInputManager;
class GfxRenderer;
class Activity {

View File

@@ -3,7 +3,7 @@
#include <Epub.h>
#include <FsHelpers.h>
#include <GfxRenderer.h>
#include <SD.h>
#include <SDCardManager.h>
#include <Xtc.h>
#include <vector>
@@ -58,29 +58,31 @@ void SleepActivity::renderPopup(const char* message) const {
void SleepActivity::renderCustomSleepScreen() const {
// Check if we have a /sleep directory
auto dir = SD.open("/sleep");
auto dir = SdMan.open("/sleep");
if (dir && dir.isDirectory()) {
std::vector<std::string> files;
char name[128];
// collect all valid BMP files
for (File file = dir.openNextFile(); file; file = dir.openNextFile()) {
for (auto file = dir.openNextFile(); file; file = dir.openNextFile()) {
if (file.isDirectory()) {
file.close();
continue;
}
auto filename = std::string(file.name());
file.getName(name, sizeof(name));
auto filename = std::string(name);
if (filename[0] == '.') {
file.close();
continue;
}
if (filename.substr(filename.length() - 4) != ".bmp") {
Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), file.name());
Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), name);
file.close();
continue;
}
Bitmap bitmap(file);
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), file.name());
Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), name);
file.close();
continue;
}
@@ -92,8 +94,8 @@ void SleepActivity::renderCustomSleepScreen() const {
// Generate a random number between 1 and numFiles
const auto randomFileIndex = random(numFiles);
const auto filename = "/sleep/" + files[randomFileIndex];
File file;
if (FsHelpers::openFileForRead("SLP", filename, file)) {
FsFile file;
if (SdMan.openFileForRead("SLP", filename, file)) {
Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
delay(100);
Bitmap bitmap(file);
@@ -109,8 +111,8 @@ void SleepActivity::renderCustomSleepScreen() const {
// Look for sleep.bmp on the root of the sd card to determine if we should
// render a custom sleep screen instead of the default.
File file;
if (FsHelpers::openFileForRead("SLP", "/sleep.bmp", file)) {
FsFile file;
if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) {
Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis());
@@ -224,8 +226,8 @@ void SleepActivity::renderCoverSleepScreen() const {
coverBmpPath = lastEpub.getCoverBmpPath();
}
File file;
if (FsHelpers::openFileForRead("SLP", coverBmpPath, file)) {
FsFile file;
if (SdMan.openFileForRead("SLP", coverBmpPath, file)) {
Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
renderBitmapSleepScreen(bitmap);

View File

@@ -1,10 +1,10 @@
#include "HomeActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include <SD.h>
#include <SDCardManager.h>
#include "CrossPointState.h"
#include "MappedInputManager.h"
#include "config.h"
void HomeActivity::taskTrampoline(void* param) {
@@ -20,7 +20,7 @@ void HomeActivity::onEnter() {
renderingMutex = xSemaphoreCreateMutex();
// Check if we have a book to continue reading
hasContinueReading = !APP_STATE.openEpubPath.empty() && SD.exists(APP_STATE.openEpubPath.c_str());
hasContinueReading = !APP_STATE.openEpubPath.empty() && SdMan.exists(APP_STATE.openEpubPath.c_str());
selectorIndex = 0;

View File

@@ -3,12 +3,12 @@
#include <DNSServer.h>
#include <ESPmDNS.h>
#include <GfxRenderer.h>
#include <InputManager.h>
#include <WiFi.h>
#include <qrcode.h>
#include <cstddef>
#include "MappedInputManager.h"
#include "NetworkModeSelectionActivity.h"
#include "WifiSelectionActivity.h"
#include "config.h"

View File

@@ -1,8 +1,8 @@
#include "NetworkModeSelectionActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include "MappedInputManager.h"
#include "config.h"
namespace {

View File

@@ -5,6 +5,7 @@
#include <map>
#include "MappedInputManager.h"
#include "WifiCredentialStore.h"
#include "activities/util/KeyboardEntryActivity.h"
#include "config.h"

View File

@@ -3,12 +3,13 @@
#include <Epub/Page.h>
#include <FsHelpers.h>
#include <GfxRenderer.h>
#include <InputManager.h>
#include <SDCardManager.h>
#include "Battery.h"
#include "CrossPointSettings.h"
#include "CrossPointState.h"
#include "EpubReaderChapterSelectionActivity.h"
#include "MappedInputManager.h"
#include "config.h"
namespace {
@@ -54,8 +55,8 @@ void EpubReaderActivity::onEnter() {
epub->setupCacheDir();
File f;
if (FsHelpers::openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
FsFile f;
if (SdMan.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
if (f.read(data, 4) == 4) {
currentSpineIndex = data[0] + (data[1] << 8);
@@ -346,8 +347,8 @@ void EpubReaderActivity::renderScreen() {
Serial.printf("[%lu] [ERS] Rendered page in %dms\n", millis(), millis() - start);
}
File f;
if (FsHelpers::openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
FsFile f;
if (SdMan.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
uint8_t data[4];
data[0] = currentSpineIndex & 0xFF;
data[1] = (currentSpineIndex >> 8) & 0xFF;

View File

@@ -1,9 +1,8 @@
#include "EpubReaderChapterSelectionActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include <SD.h>
#include "MappedInputManager.h"
#include "config.h"
namespace {

View File

@@ -1,9 +1,9 @@
#include "FileSelectionActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include <SD.h>
#include <SDCardManager.h>
#include "MappedInputManager.h"
#include "config.h"
namespace {
@@ -30,17 +30,19 @@ void FileSelectionActivity::taskTrampoline(void* param) {
void FileSelectionActivity::loadFiles() {
files.clear();
selectorIndex = 0;
auto root = SD.open(basepath.c_str());
for (File file = root.openNextFile(); file; file = root.openNextFile()) {
auto filename = std::string(file.name());
if (filename[0] == '.') {
auto root = SdMan.open(basepath.c_str());
char name[128];
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
file.getName(name, sizeof(name));
if (name[0] == '.') {
file.close();
continue;
}
if (file.isDirectory()) {
files.emplace_back(filename + "/");
files.emplace_back(std::string(name) + "/");
} else {
auto filename = std::string(name);
std::string ext4 = filename.length() >= 4 ? filename.substr(filename.length() - 4) : "";
std::string ext5 = filename.length() >= 5 ? filename.substr(filename.length() - 5) : "";
if (ext5 == ".epub" || ext5 == ".xtch" || ext4 == ".xtc") {

View File

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

View File

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

View File

@@ -1,9 +1,8 @@
#include "XtcReaderChapterSelectionActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include <SD.h>
#include "MappedInputManager.h"
#include "config.h"
namespace {

View File

@@ -1,9 +1,9 @@
#include "OtaUpdateActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include <WiFi.h>
#include "MappedInputManager.h"
#include "activities/network/WifiSelectionActivity.h"
#include "config.h"
#include "network/OtaUpdater.h"

View File

@@ -1,9 +1,9 @@
#include "SettingsActivity.h"
#include <GfxRenderer.h>
#include <InputManager.h>
#include "CrossPointSettings.h"
#include "MappedInputManager.h"
#include "OtaUpdateActivity.h"
#include "config.h"

View File

@@ -1,6 +1,7 @@
#include "KeyboardEntryActivity.h"
#include "../../config.h"
#include "MappedInputManager.h"
// Keyboard layouts - lowercase
const char* const KeyboardEntryActivity::keyboard[NUM_ROWS] = {