mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2026-02-04 14:47:37 +03:00
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:
parent
d4bd119950
commit
fb5fc32c5d
@ -3,7 +3,7 @@
|
|||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <JpegToBmpConverter.h>
|
#include <JpegToBmpConverter.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
#include <ZipFile.h>
|
#include <ZipFile.h>
|
||||||
|
|
||||||
#include "Epub/parsers/ContainerParser.h"
|
#include "Epub/parsers/ContainerParser.h"
|
||||||
@ -94,13 +94,13 @@ bool Epub::parseTocNcxFile() const {
|
|||||||
Serial.printf("[%lu] [EBP] Parsing toc ncx file: %s\n", millis(), tocNcxItem.c_str());
|
Serial.printf("[%lu] [EBP] Parsing toc ncx file: %s\n", millis(), tocNcxItem.c_str());
|
||||||
|
|
||||||
const auto tmpNcxPath = getCachePath() + "/toc.ncx";
|
const auto tmpNcxPath = getCachePath() + "/toc.ncx";
|
||||||
File tempNcxFile;
|
FsFile tempNcxFile;
|
||||||
if (!FsHelpers::openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) {
|
if (!SdMan.openFileForWrite("EBP", tmpNcxPath, tempNcxFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
readItemContentsToStream(tocNcxItem, tempNcxFile, 1024);
|
readItemContentsToStream(tocNcxItem, tempNcxFile, 1024);
|
||||||
tempNcxFile.close();
|
tempNcxFile.close();
|
||||||
if (!FsHelpers::openFileForRead("EBP", tmpNcxPath, tempNcxFile)) {
|
if (!SdMan.openFileForRead("EBP", tmpNcxPath, tempNcxFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto ncxSize = tempNcxFile.size();
|
const auto ncxSize = tempNcxFile.size();
|
||||||
@ -132,7 +132,7 @@ bool Epub::parseTocNcxFile() const {
|
|||||||
|
|
||||||
free(ncxBuffer);
|
free(ncxBuffer);
|
||||||
tempNcxFile.close();
|
tempNcxFile.close();
|
||||||
SD.remove(tmpNcxPath.c_str());
|
SdMan.remove(tmpNcxPath.c_str());
|
||||||
|
|
||||||
Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis());
|
Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis());
|
||||||
return true;
|
return true;
|
||||||
@ -218,12 +218,12 @@ bool Epub::load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Epub::clearCache() const {
|
bool Epub::clearCache() const {
|
||||||
if (!SD.exists(cachePath.c_str())) {
|
if (!SdMan.exists(cachePath.c_str())) {
|
||||||
Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis());
|
Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FsHelpers::removeDir(cachePath.c_str())) {
|
if (!SdMan.removeDir(cachePath.c_str())) {
|
||||||
Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis());
|
Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -233,17 +233,11 @@ bool Epub::clearCache() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Epub::setupCacheDir() const {
|
void Epub::setupCacheDir() const {
|
||||||
if (SD.exists(cachePath.c_str())) {
|
if (SdMan.exists(cachePath.c_str())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop over each segment of the cache path and create directories as needed
|
SdMan.mkdir(cachePath.c_str());
|
||||||
for (size_t i = 1; i < cachePath.length(); i++) {
|
|
||||||
if (cachePath[i] == '/') {
|
|
||||||
SD.mkdir(cachePath.substr(0, i).c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SD.mkdir(cachePath.c_str());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& Epub::getCachePath() const { return cachePath; }
|
const std::string& Epub::getCachePath() const { return cachePath; }
|
||||||
@ -263,7 +257,7 @@ std::string Epub::getCoverBmpPath() const { return cachePath + "/cover.bmp"; }
|
|||||||
|
|
||||||
bool Epub::generateCoverBmp() const {
|
bool Epub::generateCoverBmp() const {
|
||||||
// Already generated, return true
|
// Already generated, return true
|
||||||
if (SD.exists(getCoverBmpPath().c_str())) {
|
if (SdMan.exists(getCoverBmpPath().c_str())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,30 +277,30 @@ bool Epub::generateCoverBmp() const {
|
|||||||
Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image\n", millis());
|
Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image\n", millis());
|
||||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||||
|
|
||||||
File coverJpg;
|
FsFile coverJpg;
|
||||||
if (!FsHelpers::openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
|
if (!SdMan.openFileForWrite("EBP", coverJpgTempPath, coverJpg)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
readItemContentsToStream(coverImageHref, coverJpg, 1024);
|
readItemContentsToStream(coverImageHref, coverJpg, 1024);
|
||||||
coverJpg.close();
|
coverJpg.close();
|
||||||
|
|
||||||
if (!FsHelpers::openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
|
if (!SdMan.openFileForRead("EBP", coverJpgTempPath, coverJpg)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
File coverBmp;
|
FsFile coverBmp;
|
||||||
if (!FsHelpers::openFileForWrite("EBP", getCoverBmpPath(), coverBmp)) {
|
if (!SdMan.openFileForWrite("EBP", getCoverBmpPath(), coverBmp)) {
|
||||||
coverJpg.close();
|
coverJpg.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp);
|
const bool success = JpegToBmpConverter::jpegFileToBmpStream(coverJpg, coverBmp);
|
||||||
coverJpg.close();
|
coverJpg.close();
|
||||||
coverBmp.close();
|
coverBmp.close();
|
||||||
SD.remove(coverJpgTempPath.c_str());
|
SdMan.remove(coverJpgTempPath.c_str());
|
||||||
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis());
|
Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis());
|
||||||
SD.remove(getCoverBmpPath().c_str());
|
SdMan.remove(getCoverBmpPath().c_str());
|
||||||
}
|
}
|
||||||
Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no");
|
Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no");
|
||||||
return success;
|
return success;
|
||||||
@ -318,6 +312,11 @@ bool Epub::generateCoverBmp() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, const bool trailingNullByte) const {
|
uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, const bool trailingNullByte) const {
|
||||||
|
if (itemHref.empty()) {
|
||||||
|
Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string path = FsHelpers::normalisePath(itemHref);
|
const std::string path = FsHelpers::normalisePath(itemHref);
|
||||||
|
|
||||||
const auto content = ZipFile(filepath).readFileToMemory(path.c_str(), size, trailingNullByte);
|
const auto content = ZipFile(filepath).readFileToMemory(path.c_str(), size, trailingNullByte);
|
||||||
@ -330,6 +329,11 @@ uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize) const {
|
bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize) const {
|
||||||
|
if (itemHref.empty()) {
|
||||||
|
Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string path = FsHelpers::normalisePath(itemHref);
|
const std::string path = FsHelpers::normalisePath(itemHref);
|
||||||
return ZipFile(filepath).readFileToStream(path.c_str(), out, chunkSize);
|
return ZipFile(filepath).readFileToStream(path.c_str(), out, chunkSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <Print.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include "BookMetadataCache.h"
|
#include "BookMetadataCache.h"
|
||||||
|
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <SD.h>
|
|
||||||
#include <Serialization.h>
|
#include <Serialization.h>
|
||||||
#include <ZipFile.h>
|
#include <ZipFile.h>
|
||||||
|
|
||||||
@ -30,7 +29,7 @@ bool BookMetadataCache::beginContentOpfPass() {
|
|||||||
Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis());
|
Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis());
|
||||||
|
|
||||||
// Open spine file for writing
|
// Open spine file for writing
|
||||||
return FsHelpers::openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile);
|
return SdMan.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BookMetadataCache::endContentOpfPass() {
|
bool BookMetadataCache::endContentOpfPass() {
|
||||||
@ -42,10 +41,10 @@ bool BookMetadataCache::beginTocPass() {
|
|||||||
Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis());
|
Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis());
|
||||||
|
|
||||||
// Open spine file for reading
|
// Open spine file for reading
|
||||||
if (!FsHelpers::openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!FsHelpers::openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) {
|
if (!SdMan.openFileForWrite("BMC", cachePath + tmpTocBinFile, tocFile)) {
|
||||||
spineFile.close();
|
spineFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -71,27 +70,27 @@ bool BookMetadataCache::endWrite() {
|
|||||||
|
|
||||||
bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMetadata& metadata) {
|
bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMetadata& metadata) {
|
||||||
// Open all three files, writing to meta, reading from spine and toc
|
// Open all three files, writing to meta, reading from spine and toc
|
||||||
if (!FsHelpers::openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) {
|
if (!SdMan.openFileForWrite("BMC", cachePath + bookBinFile, bookFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FsHelpers::openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
if (!SdMan.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
||||||
bookFile.close();
|
bookFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FsHelpers::openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) {
|
if (!SdMan.openFileForRead("BMC", cachePath + tmpTocBinFile, tocFile)) {
|
||||||
bookFile.close();
|
bookFile.close();
|
||||||
spineFile.close();
|
spineFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t headerASize =
|
constexpr uint32_t headerASize =
|
||||||
sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(size_t) + sizeof(spineCount) + sizeof(tocCount);
|
sizeof(BOOK_CACHE_VERSION) + /* LUT Offset */ sizeof(uint32_t) + sizeof(spineCount) + sizeof(tocCount);
|
||||||
const size_t metadataSize =
|
const uint32_t metadataSize =
|
||||||
metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() + sizeof(uint32_t) * 3;
|
metadata.title.size() + metadata.author.size() + metadata.coverItemHref.size() + sizeof(uint32_t) * 3;
|
||||||
const size_t lutSize = sizeof(size_t) * spineCount + sizeof(size_t) * tocCount;
|
const uint32_t lutSize = sizeof(uint32_t) * spineCount + sizeof(uint32_t) * tocCount;
|
||||||
const size_t lutOffset = headerASize + metadataSize;
|
const uint32_t lutOffset = headerASize + metadataSize;
|
||||||
|
|
||||||
// Header A
|
// Header A
|
||||||
serialization::writePod(bookFile, BOOK_CACHE_VERSION);
|
serialization::writePod(bookFile, BOOK_CACHE_VERSION);
|
||||||
@ -106,7 +105,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
// Loop through spine entries, writing LUT positions
|
// Loop through spine entries, writing LUT positions
|
||||||
spineFile.seek(0);
|
spineFile.seek(0);
|
||||||
for (int i = 0; i < spineCount; i++) {
|
for (int i = 0; i < spineCount; i++) {
|
||||||
auto pos = spineFile.position();
|
uint32_t pos = spineFile.position();
|
||||||
auto spineEntry = readSpineEntry(spineFile);
|
auto spineEntry = readSpineEntry(spineFile);
|
||||||
serialization::writePod(bookFile, pos + lutOffset + lutSize);
|
serialization::writePod(bookFile, pos + lutOffset + lutSize);
|
||||||
}
|
}
|
||||||
@ -114,9 +113,9 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
// Loop through toc entries, writing LUT positions
|
// Loop through toc entries, writing LUT positions
|
||||||
tocFile.seek(0);
|
tocFile.seek(0);
|
||||||
for (int i = 0; i < tocCount; i++) {
|
for (int i = 0; i < tocCount; i++) {
|
||||||
auto pos = tocFile.position();
|
uint32_t pos = tocFile.position();
|
||||||
auto tocEntry = readTocEntry(tocFile);
|
auto tocEntry = readTocEntry(tocFile);
|
||||||
serialization::writePod(bookFile, pos + lutOffset + lutSize + spineFile.position());
|
serialization::writePod(bookFile, pos + lutOffset + lutSize + static_cast<uint32_t>(spineFile.position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// LUTs complete
|
// LUTs complete
|
||||||
@ -142,7 +141,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
zip.close();
|
zip.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t cumSize = 0;
|
uint32_t cumSize = 0;
|
||||||
spineFile.seek(0);
|
spineFile.seek(0);
|
||||||
for (int i = 0; i < spineCount; i++) {
|
for (int i = 0; i < spineCount; i++) {
|
||||||
auto spineEntry = readSpineEntry(spineFile);
|
auto spineEntry = readSpineEntry(spineFile);
|
||||||
@ -195,25 +194,25 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool BookMetadataCache::cleanupTmpFiles() const {
|
bool BookMetadataCache::cleanupTmpFiles() const {
|
||||||
if (SD.exists((cachePath + tmpSpineBinFile).c_str())) {
|
if (SdMan.exists((cachePath + tmpSpineBinFile).c_str())) {
|
||||||
SD.remove((cachePath + tmpSpineBinFile).c_str());
|
SdMan.remove((cachePath + tmpSpineBinFile).c_str());
|
||||||
}
|
}
|
||||||
if (SD.exists((cachePath + tmpTocBinFile).c_str())) {
|
if (SdMan.exists((cachePath + tmpTocBinFile).c_str())) {
|
||||||
SD.remove((cachePath + tmpTocBinFile).c_str());
|
SdMan.remove((cachePath + tmpTocBinFile).c_str());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BookMetadataCache::writeSpineEntry(File& file, const SpineEntry& entry) const {
|
uint32_t BookMetadataCache::writeSpineEntry(FsFile& file, const SpineEntry& entry) const {
|
||||||
const auto pos = file.position();
|
const uint32_t pos = file.position();
|
||||||
serialization::writeString(file, entry.href);
|
serialization::writeString(file, entry.href);
|
||||||
serialization::writePod(file, entry.cumulativeSize);
|
serialization::writePod(file, entry.cumulativeSize);
|
||||||
serialization::writePod(file, entry.tocIndex);
|
serialization::writePod(file, entry.tocIndex);
|
||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t BookMetadataCache::writeTocEntry(File& file, const TocEntry& entry) const {
|
uint32_t BookMetadataCache::writeTocEntry(FsFile& file, const TocEntry& entry) const {
|
||||||
const auto pos = file.position();
|
const uint32_t pos = file.position();
|
||||||
serialization::writeString(file, entry.title);
|
serialization::writeString(file, entry.title);
|
||||||
serialization::writeString(file, entry.href);
|
serialization::writeString(file, entry.href);
|
||||||
serialization::writeString(file, entry.anchor);
|
serialization::writeString(file, entry.anchor);
|
||||||
@ -267,7 +266,7 @@ void BookMetadataCache::createTocEntry(const std::string& title, const std::stri
|
|||||||
/* ============= READING / LOADING FUNCTIONS ================ */
|
/* ============= READING / LOADING FUNCTIONS ================ */
|
||||||
|
|
||||||
bool BookMetadataCache::load() {
|
bool BookMetadataCache::load() {
|
||||||
if (!FsHelpers::openFileForRead("BMC", cachePath + bookBinFile, bookFile)) {
|
if (!SdMan.openFileForRead("BMC", cachePath + bookBinFile, bookFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,8 +303,8 @@ BookMetadataCache::SpineEntry BookMetadataCache::getSpineEntry(const int index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Seek to spine LUT item, read from LUT and get out data
|
// Seek to spine LUT item, read from LUT and get out data
|
||||||
bookFile.seek(lutOffset + sizeof(size_t) * index);
|
bookFile.seek(lutOffset + sizeof(uint32_t) * index);
|
||||||
size_t spineEntryPos;
|
uint32_t spineEntryPos;
|
||||||
serialization::readPod(bookFile, spineEntryPos);
|
serialization::readPod(bookFile, spineEntryPos);
|
||||||
bookFile.seek(spineEntryPos);
|
bookFile.seek(spineEntryPos);
|
||||||
return readSpineEntry(bookFile);
|
return readSpineEntry(bookFile);
|
||||||
@ -323,14 +322,14 @@ BookMetadataCache::TocEntry BookMetadataCache::getTocEntry(const int index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Seek to TOC LUT item, read from LUT and get out data
|
// Seek to TOC LUT item, read from LUT and get out data
|
||||||
bookFile.seek(lutOffset + sizeof(size_t) * spineCount + sizeof(size_t) * index);
|
bookFile.seek(lutOffset + sizeof(uint32_t) * spineCount + sizeof(uint32_t) * index);
|
||||||
size_t tocEntryPos;
|
uint32_t tocEntryPos;
|
||||||
serialization::readPod(bookFile, tocEntryPos);
|
serialization::readPod(bookFile, tocEntryPos);
|
||||||
bookFile.seek(tocEntryPos);
|
bookFile.seek(tocEntryPos);
|
||||||
return readTocEntry(bookFile);
|
return readTocEntry(bookFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(File& file) const {
|
BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(FsFile& file) const {
|
||||||
SpineEntry entry;
|
SpineEntry entry;
|
||||||
serialization::readString(file, entry.href);
|
serialization::readString(file, entry.href);
|
||||||
serialization::readPod(file, entry.cumulativeSize);
|
serialization::readPod(file, entry.cumulativeSize);
|
||||||
@ -338,7 +337,7 @@ BookMetadataCache::SpineEntry BookMetadataCache::readSpineEntry(File& file) cons
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(File& file) const {
|
BookMetadataCache::TocEntry BookMetadataCache::readTocEntry(FsFile& file) const {
|
||||||
TocEntry entry;
|
TocEntry entry;
|
||||||
serialization::readString(file, entry.title);
|
serialization::readString(file, entry.title);
|
||||||
serialization::readString(file, entry.href);
|
serialization::readString(file, entry.href);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -46,15 +46,15 @@ class BookMetadataCache {
|
|||||||
bool loaded;
|
bool loaded;
|
||||||
bool buildMode;
|
bool buildMode;
|
||||||
|
|
||||||
File bookFile;
|
FsFile bookFile;
|
||||||
// Temp file handles during build
|
// Temp file handles during build
|
||||||
File spineFile;
|
FsFile spineFile;
|
||||||
File tocFile;
|
FsFile tocFile;
|
||||||
|
|
||||||
size_t writeSpineEntry(File& file, const SpineEntry& entry) const;
|
uint32_t writeSpineEntry(FsFile& file, const SpineEntry& entry) const;
|
||||||
size_t writeTocEntry(File& file, const TocEntry& entry) const;
|
uint32_t writeTocEntry(FsFile& file, const TocEntry& entry) const;
|
||||||
SpineEntry readSpineEntry(File& file) const;
|
SpineEntry readSpineEntry(FsFile& file) const;
|
||||||
TocEntry readTocEntry(File& file) const;
|
TocEntry readTocEntry(FsFile& file) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BookMetadata coreMetadata;
|
BookMetadata coreMetadata;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset
|
|||||||
block->render(renderer, fontId, xPos + xOffset, yPos + yOffset);
|
block->render(renderer, fontId, xPos + xOffset, yPos + yOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PageLine::serialize(File& file) {
|
bool PageLine::serialize(FsFile& file) {
|
||||||
serialization::writePod(file, xPos);
|
serialization::writePod(file, xPos);
|
||||||
serialization::writePod(file, yPos);
|
serialization::writePod(file, yPos);
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ bool PageLine::serialize(File& file) {
|
|||||||
return block->serialize(file);
|
return block->serialize(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PageLine> PageLine::deserialize(File& file) {
|
std::unique_ptr<PageLine> PageLine::deserialize(FsFile& file) {
|
||||||
int16_t xPos;
|
int16_t xPos;
|
||||||
int16_t yPos;
|
int16_t yPos;
|
||||||
serialization::readPod(file, xPos);
|
serialization::readPod(file, xPos);
|
||||||
@ -31,7 +31,7 @@ void Page::render(GfxRenderer& renderer, const int fontId, const int xOffset, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Page::serialize(File& file) const {
|
bool Page::serialize(FsFile& file) const {
|
||||||
const uint32_t count = elements.size();
|
const uint32_t count = elements.size();
|
||||||
serialization::writePod(file, count);
|
serialization::writePod(file, count);
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ bool Page::serialize(File& file) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Page> Page::deserialize(File& file) {
|
std::unique_ptr<Page> Page::deserialize(FsFile& file) {
|
||||||
auto page = std::unique_ptr<Page>(new Page());
|
auto page = std::unique_ptr<Page>(new Page());
|
||||||
|
|
||||||
uint32_t count;
|
uint32_t count;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <FS.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -18,7 +18,7 @@ class PageElement {
|
|||||||
explicit PageElement(const int16_t xPos, const int16_t yPos) : xPos(xPos), yPos(yPos) {}
|
explicit PageElement(const int16_t xPos, const int16_t yPos) : xPos(xPos), yPos(yPos) {}
|
||||||
virtual ~PageElement() = default;
|
virtual ~PageElement() = default;
|
||||||
virtual void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) = 0;
|
virtual void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) = 0;
|
||||||
virtual bool serialize(File& file) = 0;
|
virtual bool serialize(FsFile& file) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// a line from a block element
|
// a line from a block element
|
||||||
@ -29,8 +29,8 @@ class PageLine final : public PageElement {
|
|||||||
PageLine(std::shared_ptr<TextBlock> block, const int16_t xPos, const int16_t yPos)
|
PageLine(std::shared_ptr<TextBlock> block, const int16_t xPos, const int16_t yPos)
|
||||||
: PageElement(xPos, yPos), block(std::move(block)) {}
|
: PageElement(xPos, yPos), block(std::move(block)) {}
|
||||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
|
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
|
||||||
bool serialize(File& file) override;
|
bool serialize(FsFile& file) override;
|
||||||
static std::unique_ptr<PageLine> deserialize(File& file);
|
static std::unique_ptr<PageLine> deserialize(FsFile& file);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Page {
|
class Page {
|
||||||
@ -38,6 +38,6 @@ class Page {
|
|||||||
// the list of block index and line numbers on this page
|
// the list of block index and line numbers on this page
|
||||||
std::vector<std::shared_ptr<PageElement>> elements;
|
std::vector<std::shared_ptr<PageElement>> elements;
|
||||||
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const;
|
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) const;
|
||||||
bool serialize(File& file) const;
|
bool serialize(FsFile& file) const;
|
||||||
static std::unique_ptr<Page> deserialize(File& file);
|
static std::unique_ptr<Page> deserialize(FsFile& file);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include "Section.h"
|
#include "Section.h"
|
||||||
|
|
||||||
#include <FsHelpers.h>
|
#include <SDCardManager.h>
|
||||||
#include <SD.h>
|
|
||||||
#include <Serialization.h>
|
#include <Serialization.h>
|
||||||
|
|
||||||
#include "Page.h"
|
#include "Page.h"
|
||||||
@ -9,17 +8,17 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr uint8_t SECTION_FILE_VERSION = 7;
|
constexpr uint8_t SECTION_FILE_VERSION = 7;
|
||||||
constexpr size_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(int) +
|
constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) + sizeof(bool) + sizeof(int) +
|
||||||
sizeof(int) + sizeof(int) + sizeof(size_t);
|
sizeof(int) + sizeof(int) + sizeof(uint32_t);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
size_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
||||||
if (!file) {
|
if (!file) {
|
||||||
Serial.printf("[%lu] [SCT] File not open for writing page %d\n", millis(), pageCount);
|
Serial.printf("[%lu] [SCT] File not open for writing page %d\n", millis(), pageCount);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto position = file.position();
|
const uint32_t position = file.position();
|
||||||
if (!page->serialize(file)) {
|
if (!page->serialize(file)) {
|
||||||
Serial.printf("[%lu] [SCT] Failed to serialize page %d\n", millis(), pageCount);
|
Serial.printf("[%lu] [SCT] Failed to serialize page %d\n", millis(), pageCount);
|
||||||
return 0;
|
return 0;
|
||||||
@ -38,7 +37,7 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
|||||||
}
|
}
|
||||||
static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) +
|
static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) +
|
||||||
sizeof(extraParagraphSpacing) + sizeof(viewportWidth) + sizeof(viewportHeight) +
|
sizeof(extraParagraphSpacing) + sizeof(viewportWidth) + sizeof(viewportHeight) +
|
||||||
sizeof(pageCount) + sizeof(size_t),
|
sizeof(pageCount) + sizeof(uint32_t),
|
||||||
"Header size mismatch");
|
"Header size mismatch");
|
||||||
serialization::writePod(file, SECTION_FILE_VERSION);
|
serialization::writePod(file, SECTION_FILE_VERSION);
|
||||||
serialization::writePod(file, fontId);
|
serialization::writePod(file, fontId);
|
||||||
@ -47,12 +46,12 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
|||||||
serialization::writePod(file, viewportWidth);
|
serialization::writePod(file, viewportWidth);
|
||||||
serialization::writePod(file, viewportHeight);
|
serialization::writePod(file, viewportHeight);
|
||||||
serialization::writePod(file, pageCount); // Placeholder for page count (will be initially 0 when written)
|
serialization::writePod(file, pageCount); // Placeholder for page count (will be initially 0 when written)
|
||||||
serialization::writePod(file, static_cast<size_t>(0)); // Placeholder for LUT offset
|
serialization::writePod(file, static_cast<uint32_t>(0)); // Placeholder for LUT offset
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
bool Section::loadSectionFile(const int fontId, const float lineCompression, const bool extraParagraphSpacing,
|
||||||
const int viewportWidth, const int viewportHeight) {
|
const int viewportWidth, const int viewportHeight) {
|
||||||
if (!FsHelpers::openFileForRead("SCT", filePath, file)) {
|
if (!SdMan.openFileForRead("SCT", filePath, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,12 +93,12 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
|||||||
|
|
||||||
// Your updated class method (assuming you are using the 'SD' object, which is a wrapper for a specific filesystem)
|
// Your updated class method (assuming you are using the 'SD' object, which is a wrapper for a specific filesystem)
|
||||||
bool Section::clearCache() const {
|
bool Section::clearCache() const {
|
||||||
if (!SD.exists(filePath.c_str())) {
|
if (!SdMan.exists(filePath.c_str())) {
|
||||||
Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis());
|
Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SD.remove(filePath.c_str())) {
|
if (!SdMan.remove(filePath.c_str())) {
|
||||||
Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis());
|
Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -112,13 +111,19 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
const int viewportWidth, const int viewportHeight,
|
const int viewportWidth, const int viewportHeight,
|
||||||
const std::function<void()>& progressSetupFn,
|
const std::function<void()>& progressSetupFn,
|
||||||
const std::function<void(int)>& progressFn) {
|
const std::function<void(int)>& progressFn) {
|
||||||
constexpr size_t MIN_SIZE_FOR_PROGRESS = 50 * 1024; // 50KB
|
constexpr uint32_t MIN_SIZE_FOR_PROGRESS = 50 * 1024; // 50KB
|
||||||
const auto localPath = epub->getSpineItem(spineIndex).href;
|
const auto localPath = epub->getSpineItem(spineIndex).href;
|
||||||
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
|
const auto tmpHtmlPath = epub->getCachePath() + "/.tmp_" + std::to_string(spineIndex) + ".html";
|
||||||
|
|
||||||
|
// Create cache directory if it doesn't exist
|
||||||
|
{
|
||||||
|
const auto sectionsDir = epub->getCachePath() + "/sections";
|
||||||
|
SdMan.mkdir(sectionsDir.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
// Retry logic for SD card timing issues
|
// Retry logic for SD card timing issues
|
||||||
bool success = false;
|
bool success = false;
|
||||||
size_t fileSize = 0;
|
uint32_t fileSize = 0;
|
||||||
for (int attempt = 0; attempt < 3 && !success; attempt++) {
|
for (int attempt = 0; attempt < 3 && !success; attempt++) {
|
||||||
if (attempt > 0) {
|
if (attempt > 0) {
|
||||||
Serial.printf("[%lu] [SCT] Retrying stream (attempt %d)...\n", millis(), attempt + 1);
|
Serial.printf("[%lu] [SCT] Retrying stream (attempt %d)...\n", millis(), attempt + 1);
|
||||||
@ -126,12 +131,12 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove any incomplete file from previous attempt before retrying
|
// Remove any incomplete file from previous attempt before retrying
|
||||||
if (SD.exists(tmpHtmlPath.c_str())) {
|
if (SdMan.exists(tmpHtmlPath.c_str())) {
|
||||||
SD.remove(tmpHtmlPath.c_str());
|
SdMan.remove(tmpHtmlPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
File tmpHtml;
|
FsFile tmpHtml;
|
||||||
if (!FsHelpers::openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
|
if (!SdMan.openFileForWrite("SCT", tmpHtmlPath, tmpHtml)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
success = epub->readItemContentsToStream(localPath, tmpHtml, 1024);
|
success = epub->readItemContentsToStream(localPath, tmpHtml, 1024);
|
||||||
@ -139,8 +144,8 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
tmpHtml.close();
|
tmpHtml.close();
|
||||||
|
|
||||||
// If streaming failed, remove the incomplete file immediately
|
// If streaming failed, remove the incomplete file immediately
|
||||||
if (!success && SD.exists(tmpHtmlPath.c_str())) {
|
if (!success && SdMan.exists(tmpHtmlPath.c_str())) {
|
||||||
SD.remove(tmpHtmlPath.c_str());
|
SdMan.remove(tmpHtmlPath.c_str());
|
||||||
Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis());
|
Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,11 +162,11 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
progressSetupFn();
|
progressSetupFn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FsHelpers::openFileForWrite("SCT", filePath, file)) {
|
if (!SdMan.openFileForWrite("SCT", filePath, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight);
|
writeSectionFileHeader(fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight);
|
||||||
std::vector<size_t> lut = {};
|
std::vector<uint32_t> lut = {};
|
||||||
|
|
||||||
ChapterHtmlSlimParser visitor(
|
ChapterHtmlSlimParser visitor(
|
||||||
tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight,
|
tmpHtmlPath, renderer, fontId, lineCompression, extraParagraphSpacing, viewportWidth, viewportHeight,
|
||||||
@ -169,18 +174,18 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
progressFn);
|
progressFn);
|
||||||
success = visitor.parseAndBuildPages();
|
success = visitor.parseAndBuildPages();
|
||||||
|
|
||||||
SD.remove(tmpHtmlPath.c_str());
|
SdMan.remove(tmpHtmlPath.c_str());
|
||||||
if (!success) {
|
if (!success) {
|
||||||
Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis());
|
Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis());
|
||||||
file.close();
|
file.close();
|
||||||
SD.remove(filePath.c_str());
|
SdMan.remove(filePath.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto lutOffset = file.position();
|
const uint32_t lutOffset = file.position();
|
||||||
bool hasFailedLutRecords = false;
|
bool hasFailedLutRecords = false;
|
||||||
// Write LUT
|
// Write LUT
|
||||||
for (const auto& pos : lut) {
|
for (const uint32_t& pos : lut) {
|
||||||
if (pos == 0) {
|
if (pos == 0) {
|
||||||
hasFailedLutRecords = true;
|
hasFailedLutRecords = true;
|
||||||
break;
|
break;
|
||||||
@ -191,12 +196,12 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
if (hasFailedLutRecords) {
|
if (hasFailedLutRecords) {
|
||||||
Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis());
|
Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis());
|
||||||
file.close();
|
file.close();
|
||||||
SD.remove(filePath.c_str());
|
SdMan.remove(filePath.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go back and write LUT offset
|
// Go back and write LUT offset
|
||||||
file.seek(HEADER_SIZE - sizeof(size_t) - sizeof(pageCount));
|
file.seek(HEADER_SIZE - sizeof(uint32_t) - sizeof(pageCount));
|
||||||
serialization::writePod(file, pageCount);
|
serialization::writePod(file, pageCount);
|
||||||
serialization::writePod(file, lutOffset);
|
serialization::writePod(file, lutOffset);
|
||||||
file.close();
|
file.close();
|
||||||
@ -204,15 +209,15 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Page> Section::loadPageFromSectionFile() {
|
std::unique_ptr<Page> Section::loadPageFromSectionFile() {
|
||||||
if (!FsHelpers::openFileForRead("SCT", filePath, file)) {
|
if (!SdMan.openFileForRead("SCT", filePath, file)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.seek(HEADER_SIZE - sizeof(size_t));
|
file.seek(HEADER_SIZE - sizeof(uint32_t));
|
||||||
size_t lutOffset;
|
uint32_t lutOffset;
|
||||||
serialization::readPod(file, lutOffset);
|
serialization::readPod(file, lutOffset);
|
||||||
file.seek(lutOffset + sizeof(size_t) * currentPage);
|
file.seek(lutOffset + sizeof(uint32_t) * currentPage);
|
||||||
size_t pagePos;
|
uint32_t pagePos;
|
||||||
serialization::readPod(file, pagePos);
|
serialization::readPod(file, pagePos);
|
||||||
file.seek(pagePos);
|
file.seek(pagePos);
|
||||||
|
|
||||||
|
|||||||
@ -12,11 +12,11 @@ class Section {
|
|||||||
const int spineIndex;
|
const int spineIndex;
|
||||||
GfxRenderer& renderer;
|
GfxRenderer& renderer;
|
||||||
std::string filePath;
|
std::string filePath;
|
||||||
File file;
|
FsFile file;
|
||||||
|
|
||||||
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, int viewportWidth,
|
void writeSectionFileHeader(int fontId, float lineCompression, bool extraParagraphSpacing, int viewportWidth,
|
||||||
int viewportHeight);
|
int viewportHeight);
|
||||||
size_t onPageComplete(std::unique_ptr<Page> page);
|
uint32_t onPageComplete(std::unique_ptr<Page> page);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int pageCount = 0;
|
int pageCount = 0;
|
||||||
|
|||||||
@ -24,7 +24,7 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextBlock::serialize(File& file) const {
|
bool TextBlock::serialize(FsFile& file) const {
|
||||||
if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) {
|
if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) {
|
||||||
Serial.printf("[%lu] [TXB] Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(),
|
Serial.printf("[%lu] [TXB] Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(),
|
||||||
words.size(), wordXpos.size(), wordStyles.size());
|
words.size(), wordXpos.size(), wordStyles.size());
|
||||||
@ -43,7 +43,7 @@ bool TextBlock::serialize(File& file) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<TextBlock> TextBlock::deserialize(File& file) {
|
std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
||||||
uint32_t wc;
|
uint32_t wc;
|
||||||
std::list<std::string> words;
|
std::list<std::string> words;
|
||||||
std::list<uint16_t> wordXpos;
|
std::list<uint16_t> wordXpos;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <EpdFontFamily.h>
|
#include <EpdFontFamily.h>
|
||||||
#include <FS.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -36,6 +36,6 @@ class TextBlock final : public Block {
|
|||||||
// given a renderer works out where to break the words into lines
|
// given a renderer works out where to break the words into lines
|
||||||
void render(const GfxRenderer& renderer, int fontId, int x, int y) const;
|
void render(const GfxRenderer& renderer, int fontId, int x, int y) const;
|
||||||
BlockType getType() override { return TEXT_BLOCK; }
|
BlockType getType() override { return TEXT_BLOCK; }
|
||||||
bool serialize(File& file) const;
|
bool serialize(FsFile& file) const;
|
||||||
static std::unique_ptr<TextBlock> deserialize(File& file);
|
static std::unique_ptr<TextBlock> deserialize(FsFile& file);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include "ChapterHtmlSlimParser.h"
|
#include "ChapterHtmlSlimParser.h"
|
||||||
|
|
||||||
#include <FsHelpers.h>
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
|
#include <SDCardManager.h>
|
||||||
#include <expat.h>
|
#include <expat.h>
|
||||||
|
|
||||||
#include "../Page.h"
|
#include "../Page.h"
|
||||||
@ -218,8 +218,8 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
File file;
|
FsFile file;
|
||||||
if (!FsHelpers::openFileForRead("EHP", filepath, file)) {
|
if (!SdMan.openFileForRead("EHP", filepath, file)) {
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,8 +35,8 @@ ContentOpfParser::~ContentOpfParser() {
|
|||||||
if (tempItemStore) {
|
if (tempItemStore) {
|
||||||
tempItemStore.close();
|
tempItemStore.close();
|
||||||
}
|
}
|
||||||
if (SD.exists((cachePath + itemCacheFile).c_str())) {
|
if (SdMan.exists((cachePath + itemCacheFile).c_str())) {
|
||||||
SD.remove((cachePath + itemCacheFile).c_str());
|
SdMan.remove((cachePath + itemCacheFile).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
|||||||
|
|
||||||
if (self->state == IN_PACKAGE && (strcmp(name, "manifest") == 0 || strcmp(name, "opf:manifest") == 0)) {
|
if (self->state == IN_PACKAGE && (strcmp(name, "manifest") == 0 || strcmp(name, "opf:manifest") == 0)) {
|
||||||
self->state = IN_MANIFEST;
|
self->state = IN_MANIFEST;
|
||||||
if (!FsHelpers::openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
if (!SdMan.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
||||||
Serial.printf(
|
Serial.printf(
|
||||||
"[%lu] [COF] Couldn't open temp items file for writing. This is probably going to be a fatal error.\n",
|
"[%lu] [COF] Couldn't open temp items file for writing. This is probably going to be a fatal error.\n",
|
||||||
millis());
|
millis());
|
||||||
@ -114,7 +114,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
|||||||
|
|
||||||
if (self->state == IN_PACKAGE && (strcmp(name, "spine") == 0 || strcmp(name, "opf:spine") == 0)) {
|
if (self->state == IN_PACKAGE && (strcmp(name, "spine") == 0 || strcmp(name, "opf:spine") == 0)) {
|
||||||
self->state = IN_SPINE;
|
self->state = IN_SPINE;
|
||||||
if (!FsHelpers::openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
if (!SdMan.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
||||||
Serial.printf(
|
Serial.printf(
|
||||||
"[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n",
|
"[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n",
|
||||||
millis());
|
millis());
|
||||||
|
|||||||
@ -22,7 +22,7 @@ class ContentOpfParser final : public Print {
|
|||||||
XML_Parser parser = nullptr;
|
XML_Parser parser = nullptr;
|
||||||
ParserState state = START;
|
ParserState state = START;
|
||||||
BookMetadataCache* cache;
|
BookMetadataCache* cache;
|
||||||
File tempItemStore;
|
FsFile tempItemStore;
|
||||||
std::string coverItemId;
|
std::string coverItemId;
|
||||||
|
|
||||||
static void startElement(void* userData, const XML_Char* name, const XML_Char** atts);
|
static void startElement(void* userData, const XML_Char* name, const XML_Char** atts);
|
||||||
|
|||||||
@ -1,81 +1,7 @@
|
|||||||
#include "FsHelpers.h"
|
#include "FsHelpers.h"
|
||||||
|
|
||||||
#include <SD.h>
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
bool FsHelpers::openFileForRead(const char* moduleName, const char* path, File& file) {
|
|
||||||
if (!SD.exists(path)) {
|
|
||||||
Serial.printf("[%lu] [%s] File does not exist: %s\n", millis(), moduleName, path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = SD.open(path, FILE_READ);
|
|
||||||
if (!file) {
|
|
||||||
Serial.printf("[%lu] [%s] Failed to open file for reading: %s\n", millis(), moduleName, path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FsHelpers::openFileForRead(const char* moduleName, const std::string& path, File& file) {
|
|
||||||
return openFileForRead(moduleName, path.c_str(), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FsHelpers::openFileForRead(const char* moduleName, const String& path, File& file) {
|
|
||||||
return openFileForRead(moduleName, path.c_str(), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FsHelpers::openFileForWrite(const char* moduleName, const char* path, File& file) {
|
|
||||||
file = SD.open(path, FILE_WRITE, true);
|
|
||||||
if (!file) {
|
|
||||||
Serial.printf("[%lu] [%s] Failed to open file for writing: %s\n", millis(), moduleName, path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FsHelpers::openFileForWrite(const char* moduleName, const std::string& path, File& file) {
|
|
||||||
return openFileForWrite(moduleName, path.c_str(), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FsHelpers::openFileForWrite(const char* moduleName, const String& path, File& file) {
|
|
||||||
return openFileForWrite(moduleName, path.c_str(), file);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FsHelpers::removeDir(const char* path) {
|
|
||||||
// 1. Open the directory
|
|
||||||
File dir = SD.open(path);
|
|
||||||
if (!dir) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!dir.isDirectory()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
File file = dir.openNextFile();
|
|
||||||
while (file) {
|
|
||||||
String filePath = path;
|
|
||||||
if (!filePath.endsWith("/")) {
|
|
||||||
filePath += "/";
|
|
||||||
}
|
|
||||||
filePath += file.name();
|
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
if (!removeDir(filePath.c_str())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!SD.remove(filePath.c_str())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
file = dir.openNextFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
return SD.rmdir(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FsHelpers::normalisePath(const std::string& path) {
|
std::string FsHelpers::normalisePath(const std::string& path) {
|
||||||
std::vector<std::string> components;
|
std::vector<std::string> components;
|
||||||
std::string component;
|
std::string component;
|
||||||
|
|||||||
@ -1,14 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <FS.h>
|
#include <string>
|
||||||
|
|
||||||
class FsHelpers {
|
class FsHelpers {
|
||||||
public:
|
public:
|
||||||
static bool openFileForRead(const char* moduleName, const char* path, File& file);
|
|
||||||
static bool openFileForRead(const char* moduleName, const std::string& path, File& file);
|
|
||||||
static bool openFileForRead(const char* moduleName, const String& path, File& file);
|
|
||||||
static bool openFileForWrite(const char* moduleName, const char* path, File& file);
|
|
||||||
static bool openFileForWrite(const char* moduleName, const std::string& path, File& file);
|
|
||||||
static bool openFileForWrite(const char* moduleName, const String& path, File& file);
|
|
||||||
static bool removeDir(const char* path);
|
|
||||||
static std::string normalisePath(const std::string& path);
|
static std::string normalisePath(const std::string& path);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -123,7 +123,7 @@ Bitmap::~Bitmap() {
|
|||||||
delete[] errorNextRow;
|
delete[] errorNextRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t Bitmap::readLE16(File& f) {
|
uint16_t Bitmap::readLE16(FsFile& f) {
|
||||||
const int c0 = f.read();
|
const int c0 = f.read();
|
||||||
const int c1 = f.read();
|
const int c1 = f.read();
|
||||||
const auto b0 = static_cast<uint8_t>(c0 < 0 ? 0 : c0);
|
const auto b0 = static_cast<uint8_t>(c0 < 0 ? 0 : c0);
|
||||||
@ -131,7 +131,7 @@ uint16_t Bitmap::readLE16(File& f) {
|
|||||||
return static_cast<uint16_t>(b0) | (static_cast<uint16_t>(b1) << 8);
|
return static_cast<uint16_t>(b0) | (static_cast<uint16_t>(b1) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Bitmap::readLE32(File& f) {
|
uint32_t Bitmap::readLE32(FsFile& f) {
|
||||||
const int c0 = f.read();
|
const int c0 = f.read();
|
||||||
const int c1 = f.read();
|
const int c1 = f.read();
|
||||||
const int c2 = f.read();
|
const int c2 = f.read();
|
||||||
@ -192,7 +192,7 @@ BmpReaderError Bitmap::parseHeaders() {
|
|||||||
const uint16_t bfType = readLE16(file);
|
const uint16_t bfType = readLE16(file);
|
||||||
if (bfType != 0x4D42) return BmpReaderError::NotBMP;
|
if (bfType != 0x4D42) return BmpReaderError::NotBMP;
|
||||||
|
|
||||||
file.seek(8, SeekCur);
|
file.seekCur(8);
|
||||||
bfOffBits = readLE32(file);
|
bfOffBits = readLE32(file);
|
||||||
|
|
||||||
// --- DIB HEADER ---
|
// --- DIB HEADER ---
|
||||||
@ -214,10 +214,10 @@ BmpReaderError Bitmap::parseHeaders() {
|
|||||||
// Allow BI_RGB (0) for all, and BI_BITFIELDS (3) for 32bpp which is common for BGRA masks.
|
// Allow BI_RGB (0) for all, and BI_BITFIELDS (3) for 32bpp which is common for BGRA masks.
|
||||||
if (!(comp == 0 || (bpp == 32 && comp == 3))) return BmpReaderError::UnsupportedCompression;
|
if (!(comp == 0 || (bpp == 32 && comp == 3))) return BmpReaderError::UnsupportedCompression;
|
||||||
|
|
||||||
file.seek(12, SeekCur); // biSizeImage, biXPelsPerMeter, biYPelsPerMeter
|
file.seekCur(12); // biSizeImage, biXPelsPerMeter, biYPelsPerMeter
|
||||||
const uint32_t colorsUsed = readLE32(file);
|
const uint32_t colorsUsed = readLE32(file);
|
||||||
if (colorsUsed > 256u) return BmpReaderError::PaletteTooLarge;
|
if (colorsUsed > 256u) return BmpReaderError::PaletteTooLarge;
|
||||||
file.seek(4, SeekCur); // biClrImportant
|
file.seekCur(4); // biClrImportant
|
||||||
|
|
||||||
if (width <= 0 || height <= 0) return BmpReaderError::BadDimensions;
|
if (width <= 0 || height <= 0) return BmpReaderError::BadDimensions;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <FS.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
enum class BmpReaderError : uint8_t {
|
enum class BmpReaderError : uint8_t {
|
||||||
Ok = 0,
|
Ok = 0,
|
||||||
@ -28,7 +28,7 @@ class Bitmap {
|
|||||||
public:
|
public:
|
||||||
static const char* errorToString(BmpReaderError err);
|
static const char* errorToString(BmpReaderError err);
|
||||||
|
|
||||||
explicit Bitmap(File& file) : file(file) {}
|
explicit Bitmap(FsFile& file) : file(file) {}
|
||||||
~Bitmap();
|
~Bitmap();
|
||||||
BmpReaderError parseHeaders();
|
BmpReaderError parseHeaders();
|
||||||
BmpReaderError readRow(uint8_t* data, uint8_t* rowBuffer, int rowY) const;
|
BmpReaderError readRow(uint8_t* data, uint8_t* rowBuffer, int rowY) const;
|
||||||
@ -40,10 +40,10 @@ class Bitmap {
|
|||||||
int getRowBytes() const { return rowBytes; }
|
int getRowBytes() const { return rowBytes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uint16_t readLE16(File& f);
|
static uint16_t readLE16(FsFile& f);
|
||||||
static uint32_t readLE32(File& f);
|
static uint32_t readLE32(FsFile& f);
|
||||||
|
|
||||||
File& file;
|
FsFile& file;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
bool topDown = false;
|
bool topDown = false;
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include <EInkDisplay.h>
|
#include <EInkDisplay.h>
|
||||||
#include <EpdFontFamily.h>
|
#include <EpdFontFamily.h>
|
||||||
#include <FS.h>
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#include "JpegToBmpConverter.h"
|
#include "JpegToBmpConverter.h"
|
||||||
|
|
||||||
|
#include <HardwareSerial.h>
|
||||||
|
#include <SdFat.h>
|
||||||
#include <picojpeg.h>
|
#include <picojpeg.h>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@ -7,7 +9,7 @@
|
|||||||
|
|
||||||
// Context structure for picojpeg callback
|
// Context structure for picojpeg callback
|
||||||
struct JpegReadContext {
|
struct JpegReadContext {
|
||||||
File& file;
|
FsFile& file;
|
||||||
uint8_t buffer[512];
|
uint8_t buffer[512];
|
||||||
size_t bufferPos;
|
size_t bufferPos;
|
||||||
size_t bufferFilled;
|
size_t bufferFilled;
|
||||||
@ -426,7 +428,7 @@ unsigned char JpegToBmpConverter::jpegReadCallback(unsigned char* pBuf, const un
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Core function: Convert JPEG file to 2-bit BMP
|
// Core function: Convert JPEG file to 2-bit BMP
|
||||||
bool JpegToBmpConverter::jpegFileToBmpStream(File& jpegFile, Print& bmpOut) {
|
bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut) {
|
||||||
Serial.printf("[%lu] [JPG] Converting JPEG to BMP\n", millis());
|
Serial.printf("[%lu] [JPG] Converting JPEG to BMP\n", millis());
|
||||||
|
|
||||||
// Setup context for picojpeg callback
|
// Setup context for picojpeg callback
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <FS.h>
|
class FsFile;
|
||||||
|
class Print;
|
||||||
class ZipFile;
|
class ZipFile;
|
||||||
|
|
||||||
class JpegToBmpConverter {
|
class JpegToBmpConverter {
|
||||||
@ -11,5 +11,5 @@ class JpegToBmpConverter {
|
|||||||
unsigned char* pBytes_actually_read, void* pCallback_data);
|
unsigned char* pBytes_actually_read, void* pCallback_data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static bool jpegFileToBmpStream(File& jpegFile, Print& bmpOut);
|
static bool jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <FS.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ static void writePod(std::ostream& os, const T& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void writePod(File& file, const T& value) {
|
static void writePod(FsFile& file, const T& value) {
|
||||||
file.write(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
|
file.write(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ static void readPod(std::istream& is, T& value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static void readPod(File& file, T& value) {
|
static void readPod(FsFile& file, T& value) {
|
||||||
file.read(reinterpret_cast<uint8_t*>(&value), sizeof(T));
|
file.read(reinterpret_cast<uint8_t*>(&value), sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ static void writeString(std::ostream& os, const std::string& s) {
|
|||||||
os.write(s.data(), len);
|
os.write(s.data(), len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeString(File& file, const std::string& s) {
|
static void writeString(FsFile& file, const std::string& s) {
|
||||||
const uint32_t len = s.size();
|
const uint32_t len = s.size();
|
||||||
writePod(file, len);
|
writePod(file, len);
|
||||||
file.write(reinterpret_cast<const uint8_t*>(s.data()), len);
|
file.write(reinterpret_cast<const uint8_t*>(s.data()), len);
|
||||||
@ -43,10 +43,10 @@ static void readString(std::istream& is, std::string& s) {
|
|||||||
is.read(&s[0], len);
|
is.read(&s[0], len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readString(File& file, std::string& s) {
|
static void readString(FsFile& file, std::string& s) {
|
||||||
uint32_t len;
|
uint32_t len;
|
||||||
readPod(file, len);
|
readPod(file, len);
|
||||||
s.resize(len);
|
s.resize(len);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&s[0]), len);
|
file.read(&s[0], len);
|
||||||
}
|
}
|
||||||
} // namespace serialization
|
} // namespace serialization
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
|
|
||||||
bool Xtc::load() {
|
bool Xtc::load() {
|
||||||
Serial.printf("[%lu] [XTC] Loading XTC: %s\n", millis(), filepath.c_str());
|
Serial.printf("[%lu] [XTC] Loading XTC: %s\n", millis(), filepath.c_str());
|
||||||
@ -31,12 +31,12 @@ bool Xtc::load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Xtc::clearCache() const {
|
bool Xtc::clearCache() const {
|
||||||
if (!SD.exists(cachePath.c_str())) {
|
if (!SdMan.exists(cachePath.c_str())) {
|
||||||
Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis());
|
Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!FsHelpers::removeDir(cachePath.c_str())) {
|
if (!SdMan.removeDir(cachePath.c_str())) {
|
||||||
Serial.printf("[%lu] [XTC] Failed to clear cache\n", millis());
|
Serial.printf("[%lu] [XTC] Failed to clear cache\n", millis());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -46,17 +46,17 @@ bool Xtc::clearCache() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Xtc::setupCacheDir() const {
|
void Xtc::setupCacheDir() const {
|
||||||
if (SD.exists(cachePath.c_str())) {
|
if (SdMan.exists(cachePath.c_str())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create directories recursively
|
// Create directories recursively
|
||||||
for (size_t i = 1; i < cachePath.length(); i++) {
|
for (size_t i = 1; i < cachePath.length(); i++) {
|
||||||
if (cachePath[i] == '/') {
|
if (cachePath[i] == '/') {
|
||||||
SD.mkdir(cachePath.substr(0, i).c_str());
|
SdMan.mkdir(cachePath.substr(0, i).c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SD.mkdir(cachePath.c_str());
|
SdMan.mkdir(cachePath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Xtc::getTitle() const {
|
std::string Xtc::getTitle() const {
|
||||||
@ -106,7 +106,7 @@ std::string Xtc::getCoverBmpPath() const { return cachePath + "/cover.bmp"; }
|
|||||||
|
|
||||||
bool Xtc::generateCoverBmp() const {
|
bool Xtc::generateCoverBmp() const {
|
||||||
// Already generated
|
// Already generated
|
||||||
if (SD.exists(getCoverBmpPath().c_str())) {
|
if (SdMan.exists(getCoverBmpPath().c_str())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,8 +157,8 @@ bool Xtc::generateCoverBmp() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create BMP file
|
// Create BMP file
|
||||||
File coverBmp;
|
FsFile coverBmp;
|
||||||
if (!FsHelpers::openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) {
|
if (!SdMan.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) {
|
||||||
Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis());
|
Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis());
|
||||||
free(pageBuffer);
|
free(pageBuffer);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
|
#include <SDCardManager.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ XtcError XtcParser::open(const char* filepath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
if (!FsHelpers::openFileForRead("XTC", filepath, m_file)) {
|
if (!SdMan.openFileForRead("XTC", filepath, m_file)) {
|
||||||
m_lastError = XtcError::FILE_NOT_FOUND;
|
m_lastError = XtcError::FILE_NOT_FOUND;
|
||||||
return m_lastError;
|
return m_lastError;
|
||||||
}
|
}
|
||||||
@ -419,8 +420,8 @@ XtcError XtcParser::loadPageStreaming(uint32_t pageIndex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool XtcParser::isValidXtcFile(const char* filepath) {
|
bool XtcParser::isValidXtcFile(const char* filepath) {
|
||||||
File file = SD.open(filepath, FILE_READ);
|
FsFile file;
|
||||||
if (!file) {
|
if (!SdMan.openFileForRead("XTC", filepath, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <SD.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -80,7 +80,7 @@ class XtcParser {
|
|||||||
XtcError getLastError() const { return m_lastError; }
|
XtcError getLastError() const { return m_lastError; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
File m_file;
|
FsFile m_file;
|
||||||
bool m_isOpen;
|
bool m_isOpen;
|
||||||
XtcHeader m_header;
|
XtcHeader m_header;
|
||||||
std::vector<PageInfo> m_pageTable;
|
std::vector<PageInfo> m_pageTable;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "ZipFile.h"
|
#include "ZipFile.h"
|
||||||
|
|
||||||
#include <FsHelpers.h>
|
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
|
#include <SDCardManager.h>
|
||||||
#include <miniz.h>
|
#include <miniz.h>
|
||||||
|
|
||||||
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
|
bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t* outputBuf, const size_t inflatedSize) {
|
||||||
@ -49,29 +49,29 @@ bool ZipFile::loadAllFileStatSlims() {
|
|||||||
fileStatSlimCache.reserve(zipDetails.totalEntries);
|
fileStatSlimCache.reserve(zipDetails.totalEntries);
|
||||||
|
|
||||||
while (file.available()) {
|
while (file.available()) {
|
||||||
file.read(reinterpret_cast<uint8_t*>(&sig), 4);
|
file.read(&sig, 4);
|
||||||
if (sig != 0x02014b50) break; // End of list
|
if (sig != 0x02014b50) break; // End of list
|
||||||
|
|
||||||
FileStatSlim fileStat = {};
|
FileStatSlim fileStat = {};
|
||||||
|
|
||||||
file.seek(6, SeekCur);
|
file.seekCur(6);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat.method), 2);
|
file.read(&fileStat.method, 2);
|
||||||
file.seek(8, SeekCur);
|
file.seekCur(8);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat.compressedSize), 4);
|
file.read(&fileStat.compressedSize, 4);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat.uncompressedSize), 4);
|
file.read(&fileStat.uncompressedSize, 4);
|
||||||
uint16_t nameLen, m, k;
|
uint16_t nameLen, m, k;
|
||||||
file.read(reinterpret_cast<uint8_t*>(&nameLen), 2);
|
file.read(&nameLen, 2);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&m), 2);
|
file.read(&m, 2);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&k), 2);
|
file.read(&k, 2);
|
||||||
file.seek(8, SeekCur);
|
file.seekCur(8);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat.localHeaderOffset), 4);
|
file.read(&fileStat.localHeaderOffset, 4);
|
||||||
file.read(reinterpret_cast<uint8_t*>(itemName), nameLen);
|
file.read(itemName, nameLen);
|
||||||
itemName[nameLen] = '\0';
|
itemName[nameLen] = '\0';
|
||||||
|
|
||||||
fileStatSlimCache.emplace(itemName, fileStat);
|
fileStatSlimCache.emplace(itemName, fileStat);
|
||||||
|
|
||||||
// Skip the rest of this entry (extra field + comment)
|
// Skip the rest of this entry (extra field + comment)
|
||||||
file.seek(m + k, SeekCur);
|
file.seekCur(m + k);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wasOpen) {
|
if (!wasOpen) {
|
||||||
@ -109,21 +109,21 @@ bool ZipFile::loadFileStatSlim(const char* filename, FileStatSlim* fileStat) {
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
while (file.available()) {
|
while (file.available()) {
|
||||||
file.read(reinterpret_cast<uint8_t*>(&sig), 4);
|
file.read(&sig, 4);
|
||||||
if (sig != 0x02014b50) break; // End of list
|
if (sig != 0x02014b50) break; // End of list
|
||||||
|
|
||||||
file.seek(6, SeekCur);
|
file.seekCur(6);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat->method), 2);
|
file.read(&fileStat->method, 2);
|
||||||
file.seek(8, SeekCur);
|
file.seekCur(8);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat->compressedSize), 4);
|
file.read(&fileStat->compressedSize, 4);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat->uncompressedSize), 4);
|
file.read(&fileStat->uncompressedSize, 4);
|
||||||
uint16_t nameLen, m, k;
|
uint16_t nameLen, m, k;
|
||||||
file.read(reinterpret_cast<uint8_t*>(&nameLen), 2);
|
file.read(&nameLen, 2);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&m), 2);
|
file.read(&m, 2);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&k), 2);
|
file.read(&k, 2);
|
||||||
file.seek(8, SeekCur);
|
file.seekCur(8);
|
||||||
file.read(reinterpret_cast<uint8_t*>(&fileStat->localHeaderOffset), 4);
|
file.read(&fileStat->localHeaderOffset, 4);
|
||||||
file.read(reinterpret_cast<uint8_t*>(itemName), nameLen);
|
file.read(itemName, nameLen);
|
||||||
itemName[nameLen] = '\0';
|
itemName[nameLen] = '\0';
|
||||||
|
|
||||||
if (strcmp(itemName, filename) == 0) {
|
if (strcmp(itemName, filename) == 0) {
|
||||||
@ -132,7 +132,7 @@ bool ZipFile::loadFileStatSlim(const char* filename, FileStatSlim* fileStat) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip the rest of this entry (extra field + comment)
|
// Skip the rest of this entry (extra field + comment)
|
||||||
file.seek(m + k, SeekCur);
|
file.seekCur(m + k);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wasOpen) {
|
if (!wasOpen) {
|
||||||
@ -243,7 +243,7 @@ bool ZipFile::loadZipDetails() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ZipFile::open() {
|
bool ZipFile::open() {
|
||||||
if (!FsHelpers::openFileForRead("ZIP", filePath, file)) {
|
if (!SdMan.openFileForRead("ZIP", filePath, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <FS.h>
|
#include <SdFat.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -21,7 +21,7 @@ class ZipFile {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const std::string& filePath;
|
const std::string& filePath;
|
||||||
File file;
|
FsFile file;
|
||||||
ZipDetails zipDetails = {0, 0, false};
|
ZipDetails zipDetails = {0, 0, false};
|
||||||
std::unordered_map<std::string, FileStatSlim> fileStatSlimCache;
|
std::unordered_map<std::string, FileStatSlim> fileStatSlimCache;
|
||||||
|
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit 98a5aa1f8969ccd317c9b45bf0fa84b6c82e167f
|
Subproject commit bd4e6707503ab9c97d13ee0d8f8c69e9ff03cd12
|
||||||
@ -21,6 +21,7 @@ build_flags =
|
|||||||
-DARDUINO_USB_CDC_ON_BOOT=1
|
-DARDUINO_USB_CDC_ON_BOOT=1
|
||||||
-DMINIZ_NO_ZLIB_COMPATIBLE_NAMES=1
|
-DMINIZ_NO_ZLIB_COMPATIBLE_NAMES=1
|
||||||
-DEINK_DISPLAY_SINGLE_BUFFER_MODE=1
|
-DEINK_DISPLAY_SINGLE_BUFFER_MODE=1
|
||||||
|
-DDISABLE_FS_H_WARNING=1
|
||||||
# https://libexpat.github.io/doc/api/latest/#XML_GE
|
# https://libexpat.github.io/doc/api/latest/#XML_GE
|
||||||
-DXML_GE=0
|
-DXML_GE=0
|
||||||
-DXML_CONTEXT_BYTES=1024
|
-DXML_CONTEXT_BYTES=1024
|
||||||
@ -39,6 +40,7 @@ lib_deps =
|
|||||||
BatteryMonitor=symlink://open-x4-sdk/libs/hardware/BatteryMonitor
|
BatteryMonitor=symlink://open-x4-sdk/libs/hardware/BatteryMonitor
|
||||||
InputManager=symlink://open-x4-sdk/libs/hardware/InputManager
|
InputManager=symlink://open-x4-sdk/libs/hardware/InputManager
|
||||||
EInkDisplay=symlink://open-x4-sdk/libs/display/EInkDisplay
|
EInkDisplay=symlink://open-x4-sdk/libs/display/EInkDisplay
|
||||||
|
SDCardManager=symlink://open-x4-sdk/libs/hardware/SDCardManager
|
||||||
ArduinoJson @ 7.4.2
|
ArduinoJson @ 7.4.2
|
||||||
QRCode @ 0.0.1
|
QRCode @ 0.0.1
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
|
|
||||||
#include <FsHelpers.h>
|
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
#include <Serialization.h>
|
#include <Serialization.h>
|
||||||
|
|
||||||
// Initialize the static instance
|
// Initialize the static instance
|
||||||
@ -17,10 +16,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
|
||||||
SD.mkdir("/.crosspoint");
|
SdMan.mkdir("/.crosspoint");
|
||||||
|
|
||||||
File outputFile;
|
FsFile outputFile;
|
||||||
if (!FsHelpers::openFileForWrite("CPS", SETTINGS_FILE, outputFile)) {
|
if (!SdMan.openFileForWrite("CPS", SETTINGS_FILE, outputFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +39,8 @@ bool CrossPointSettings::saveToFile() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CrossPointSettings::loadFromFile() {
|
bool CrossPointSettings::loadFromFile() {
|
||||||
File inputFile;
|
FsFile inputFile;
|
||||||
if (!FsHelpers::openFileForRead("CPS", SETTINGS_FILE, inputFile)) {
|
if (!SdMan.openFileForRead("CPS", SETTINGS_FILE, inputFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
#include "CrossPointState.h"
|
#include "CrossPointState.h"
|
||||||
|
|
||||||
#include <FsHelpers.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 {
|
||||||
File outputFile;
|
FsFile outputFile;
|
||||||
if (!FsHelpers::openFileForWrite("CPS", STATE_FILE, outputFile)) {
|
if (!SdMan.openFileForWrite("CPS", STATE_FILE, outputFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,8 +24,8 @@ bool CrossPointState::saveToFile() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CrossPointState::loadFromFile() {
|
bool CrossPointState::loadFromFile() {
|
||||||
File inputFile;
|
FsFile inputFile;
|
||||||
if (!FsHelpers::openFileForRead("CPS", STATE_FILE, inputFile)) {
|
if (!SdMan.openFileForRead("CPS", STATE_FILE, inputFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
|
|
||||||
|
#include "CrossPointSettings.h"
|
||||||
|
|
||||||
decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button button) const {
|
decltype(InputManager::BTN_BACK) MappedInputManager::mapButton(const Button button) const {
|
||||||
const auto frontLayout = static_cast<CrossPointSettings::FRONT_BUTTON_LAYOUT>(SETTINGS.frontButtonLayout);
|
const auto frontLayout = static_cast<CrossPointSettings::FRONT_BUTTON_LAYOUT>(SETTINGS.frontButtonLayout);
|
||||||
const auto sideLayout = static_cast<CrossPointSettings::SIDE_BUTTON_LAYOUT>(SETTINGS.sideButtonLayout);
|
const auto sideLayout = static_cast<CrossPointSettings::SIDE_BUTTON_LAYOUT>(SETTINGS.sideButtonLayout);
|
||||||
|
|||||||
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include <InputManager.h>
|
#include <InputManager.h>
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
|
||||||
|
|
||||||
class MappedInputManager {
|
class MappedInputManager {
|
||||||
public:
|
public:
|
||||||
enum class Button { Back, Confirm, Left, Right, Up, Down, Power, PageBack, PageForward };
|
enum class Button { Back, Confirm, Left, Right, Up, Down, Power, PageBack, PageForward };
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#include "WifiCredentialStore.h"
|
#include "WifiCredentialStore.h"
|
||||||
|
|
||||||
#include <FsHelpers.h>
|
|
||||||
#include <HardwareSerial.h>
|
#include <HardwareSerial.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
#include <Serialization.h>
|
#include <Serialization.h>
|
||||||
|
|
||||||
// Initialize the static instance
|
// Initialize the static instance
|
||||||
@ -30,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
|
||||||
SD.mkdir("/.crosspoint");
|
SdMan.mkdir("/.crosspoint");
|
||||||
|
|
||||||
File file;
|
FsFile file;
|
||||||
if (!FsHelpers::openFileForWrite("WCS", WIFI_FILE, file)) {
|
if (!SdMan.openFileForWrite("WCS", WIFI_FILE, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,8 +59,8 @@ bool WifiCredentialStore::saveToFile() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WifiCredentialStore::loadFromFile() {
|
bool WifiCredentialStore::loadFromFile() {
|
||||||
File file;
|
FsFile file;
|
||||||
if (!FsHelpers::openFileForRead("WCS", WIFI_FILE, file)) {
|
if (!SdMan.openFileForRead("WCS", WIFI_FILE, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,8 +5,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "../MappedInputManager.h"
|
class MappedInputManager;
|
||||||
|
|
||||||
class GfxRenderer;
|
class GfxRenderer;
|
||||||
|
|
||||||
class Activity {
|
class Activity {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include <Epub.h>
|
#include <Epub.h>
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
#include <Xtc.h>
|
#include <Xtc.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -58,29 +58,31 @@ void SleepActivity::renderPopup(const char* message) const {
|
|||||||
|
|
||||||
void SleepActivity::renderCustomSleepScreen() const {
|
void SleepActivity::renderCustomSleepScreen() const {
|
||||||
// Check if we have a /sleep directory
|
// Check if we have a /sleep directory
|
||||||
auto dir = SD.open("/sleep");
|
auto dir = SdMan.open("/sleep");
|
||||||
if (dir && dir.isDirectory()) {
|
if (dir && dir.isDirectory()) {
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
|
char name[128];
|
||||||
// collect all valid BMP files
|
// 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()) {
|
if (file.isDirectory()) {
|
||||||
file.close();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
auto filename = std::string(file.name());
|
file.getName(name, sizeof(name));
|
||||||
|
auto filename = std::string(name);
|
||||||
if (filename[0] == '.') {
|
if (filename[0] == '.') {
|
||||||
file.close();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename.substr(filename.length() - 4) != ".bmp") {
|
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();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
|
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();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -92,8 +94,8 @@ void SleepActivity::renderCustomSleepScreen() const {
|
|||||||
// Generate a random number between 1 and numFiles
|
// Generate a random number between 1 and numFiles
|
||||||
const auto randomFileIndex = random(numFiles);
|
const auto randomFileIndex = random(numFiles);
|
||||||
const auto filename = "/sleep/" + files[randomFileIndex];
|
const auto filename = "/sleep/" + files[randomFileIndex];
|
||||||
File file;
|
FsFile file;
|
||||||
if (FsHelpers::openFileForRead("SLP", filename, file)) {
|
if (SdMan.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);
|
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
|
// 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.
|
||||||
File file;
|
FsFile file;
|
||||||
if (FsHelpers::openFileForRead("SLP", "/sleep.bmp", file)) {
|
if (SdMan.openFileForRead("SLP", "/sleep.bmp", file)) {
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
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());
|
||||||
@ -224,8 +226,8 @@ void SleepActivity::renderCoverSleepScreen() const {
|
|||||||
coverBmpPath = lastEpub.getCoverBmpPath();
|
coverBmpPath = lastEpub.getCoverBmpPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
File file;
|
FsFile file;
|
||||||
if (FsHelpers::openFileForRead("SLP", coverBmpPath, file)) {
|
if (SdMan.openFileForRead("SLP", coverBmpPath, file)) {
|
||||||
Bitmap bitmap(file);
|
Bitmap bitmap(file);
|
||||||
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
|
||||||
renderBitmapSleepScreen(bitmap);
|
renderBitmapSleepScreen(bitmap);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#include "HomeActivity.h"
|
#include "HomeActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
#include <SDCardManager.h>
|
||||||
#include <SD.h>
|
|
||||||
|
|
||||||
#include "CrossPointState.h"
|
#include "CrossPointState.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
void HomeActivity::taskTrampoline(void* param) {
|
void HomeActivity::taskTrampoline(void* param) {
|
||||||
@ -20,7 +20,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() && SD.exists(APP_STATE.openEpubPath.c_str());
|
hasContinueReading = !APP_STATE.openEpubPath.empty() && SdMan.exists(APP_STATE.openEpubPath.c_str());
|
||||||
|
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
|
|
||||||
|
|||||||
@ -3,12 +3,12 @@
|
|||||||
#include <DNSServer.h>
|
#include <DNSServer.h>
|
||||||
#include <ESPmDNS.h>
|
#include <ESPmDNS.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <qrcode.h>
|
#include <qrcode.h>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "NetworkModeSelectionActivity.h"
|
#include "NetworkModeSelectionActivity.h"
|
||||||
#include "WifiSelectionActivity.h"
|
#include "WifiSelectionActivity.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include "NetworkModeSelectionActivity.h"
|
#include "NetworkModeSelectionActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "WifiCredentialStore.h"
|
#include "WifiCredentialStore.h"
|
||||||
#include "activities/util/KeyboardEntryActivity.h"
|
#include "activities/util/KeyboardEntryActivity.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|||||||
@ -3,12 +3,13 @@
|
|||||||
#include <Epub/Page.h>
|
#include <Epub/Page.h>
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
#include <SDCardManager.h>
|
||||||
|
|
||||||
#include "Battery.h"
|
#include "Battery.h"
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
#include "CrossPointState.h"
|
#include "CrossPointState.h"
|
||||||
#include "EpubReaderChapterSelectionActivity.h"
|
#include "EpubReaderChapterSelectionActivity.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -54,8 +55,8 @@ void EpubReaderActivity::onEnter() {
|
|||||||
|
|
||||||
epub->setupCacheDir();
|
epub->setupCacheDir();
|
||||||
|
|
||||||
File f;
|
FsFile f;
|
||||||
if (FsHelpers::openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
if (SdMan.openFileForRead("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
if (f.read(data, 4) == 4) {
|
if (f.read(data, 4) == 4) {
|
||||||
currentSpineIndex = data[0] + (data[1] << 8);
|
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);
|
Serial.printf("[%lu] [ERS] Rendered page in %dms\n", millis(), millis() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
File f;
|
FsFile f;
|
||||||
if (FsHelpers::openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
if (SdMan.openFileForWrite("ERS", epub->getCachePath() + "/progress.bin", f)) {
|
||||||
uint8_t data[4];
|
uint8_t data[4];
|
||||||
data[0] = currentSpineIndex & 0xFF;
|
data[0] = currentSpineIndex & 0xFF;
|
||||||
data[1] = (currentSpineIndex >> 8) & 0xFF;
|
data[1] = (currentSpineIndex >> 8) & 0xFF;
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#include "EpubReaderChapterSelectionActivity.h"
|
#include "EpubReaderChapterSelectionActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
|
||||||
#include <SD.h>
|
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
#include "FileSelectionActivity.h"
|
#include "FileSelectionActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
#include <SDCardManager.h>
|
||||||
#include <SD.h>
|
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -30,17 +30,19 @@ void FileSelectionActivity::taskTrampoline(void* param) {
|
|||||||
void FileSelectionActivity::loadFiles() {
|
void FileSelectionActivity::loadFiles() {
|
||||||
files.clear();
|
files.clear();
|
||||||
selectorIndex = 0;
|
selectorIndex = 0;
|
||||||
auto root = SD.open(basepath.c_str());
|
auto root = SdMan.open(basepath.c_str());
|
||||||
for (File file = root.openNextFile(); file; file = root.openNextFile()) {
|
char name[128];
|
||||||
auto filename = std::string(file.name());
|
for (auto file = root.openNextFile(); file; file = root.openNextFile()) {
|
||||||
if (filename[0] == '.') {
|
file.getName(name, sizeof(name));
|
||||||
|
if (name[0] == '.') {
|
||||||
file.close();
|
file.close();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
files.emplace_back(filename + "/");
|
files.emplace_back(std::string(name) + "/");
|
||||||
} else {
|
} else {
|
||||||
|
auto filename = std::string(name);
|
||||||
std::string ext4 = filename.length() >= 4 ? filename.substr(filename.length() - 4) : "";
|
std::string ext4 = filename.length() >= 4 ? filename.substr(filename.length() - 4) : "";
|
||||||
std::string ext5 = filename.length() >= 5 ? filename.substr(filename.length() - 5) : "";
|
std::string ext5 = filename.length() >= 5 ? filename.substr(filename.length() - 5) : "";
|
||||||
if (ext5 == ".epub" || ext5 == ".xtch" || ext4 == ".xtc") {
|
if (ext5 == ".epub" || ext5 == ".xtch" || ext4 == ".xtc") {
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
#include "ReaderActivity.h"
|
#include "ReaderActivity.h"
|
||||||
|
|
||||||
#include <SD.h>
|
|
||||||
|
|
||||||
#include "Epub.h"
|
#include "Epub.h"
|
||||||
#include "EpubReaderActivity.h"
|
#include "EpubReaderActivity.h"
|
||||||
#include "FileSelectionActivity.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) {
|
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());
|
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
|
||||||
return nullptr;
|
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) {
|
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());
|
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
#include <SDCardManager.h>
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
|
||||||
#include "CrossPointState.h"
|
#include "CrossPointState.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "XtcReaderChapterSelectionActivity.h"
|
#include "XtcReaderChapterSelectionActivity.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
@ -357,8 +357,8 @@ void XtcReaderActivity::renderPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void XtcReaderActivity::saveProgress() const {
|
void XtcReaderActivity::saveProgress() const {
|
||||||
File f;
|
FsFile f;
|
||||||
if (FsHelpers::openFileForWrite("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
if (SdMan.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;
|
||||||
@ -370,8 +370,8 @@ void XtcReaderActivity::saveProgress() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void XtcReaderActivity::loadProgress() {
|
void XtcReaderActivity::loadProgress() {
|
||||||
File f;
|
FsFile f;
|
||||||
if (FsHelpers::openFileForRead("XTR", xtc->getCachePath() + "/progress.bin", f)) {
|
if (SdMan.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);
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
#include "XtcReaderChapterSelectionActivity.h"
|
#include "XtcReaderChapterSelectionActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
|
||||||
#include <SD.h>
|
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
#include "OtaUpdateActivity.h"
|
#include "OtaUpdateActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "activities/network/WifiSelectionActivity.h"
|
#include "activities/network/WifiSelectionActivity.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "network/OtaUpdater.h"
|
#include "network/OtaUpdater.h"
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
#include "SettingsActivity.h"
|
#include "SettingsActivity.h"
|
||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
|
||||||
|
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
#include "OtaUpdateActivity.h"
|
#include "OtaUpdateActivity.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#include "KeyboardEntryActivity.h"
|
#include "KeyboardEntryActivity.h"
|
||||||
|
|
||||||
#include "../../config.h"
|
#include "../../config.h"
|
||||||
|
#include "MappedInputManager.h"
|
||||||
|
|
||||||
// Keyboard layouts - lowercase
|
// Keyboard layouts - lowercase
|
||||||
const char* const KeyboardEntryActivity::keyboard[NUM_ROWS] = {
|
const char* const KeyboardEntryActivity::keyboard[NUM_ROWS] = {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include <Epub.h>
|
#include <Epub.h>
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <InputManager.h>
|
#include <InputManager.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <builtinFonts/bookerly_2b.h>
|
#include <builtinFonts/bookerly_2b.h>
|
||||||
#include <builtinFonts/bookerly_bold_2b.h>
|
#include <builtinFonts/bookerly_bold_2b.h>
|
||||||
@ -37,7 +37,6 @@
|
|||||||
|
|
||||||
#define UART0_RXD 20 // Used for USB connection detection
|
#define UART0_RXD 20 // Used for USB connection detection
|
||||||
|
|
||||||
#define SD_SPI_CS 12
|
|
||||||
#define SD_SPI_MISO 7
|
#define SD_SPI_MISO 7
|
||||||
|
|
||||||
EInkDisplay einkDisplay(EPD_SCLK, EPD_MOSI, EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
|
EInkDisplay einkDisplay(EPD_SCLK, EPD_MOSI, EPD_CS, EPD_DC, EPD_RST, EPD_BUSY);
|
||||||
@ -189,7 +188,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 (!SD.begin(SD_SPI_CS, SPI, SPI_FQ, "/sd", 6)) {
|
if (!SdMan.begin()) {
|
||||||
Serial.printf("[%lu] [ ] SD card initialization failed\n", millis());
|
Serial.printf("[%lu] [ ] SD card initialization failed\n", millis());
|
||||||
setupDisplayAndFonts();
|
setupDisplayAndFonts();
|
||||||
exitActivity();
|
exitActivity();
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <ArduinoJson.h>
|
#include <ArduinoJson.h>
|
||||||
#include <FsHelpers.h>
|
#include <FsHelpers.h>
|
||||||
#include <SD.h>
|
#include <SDCardManager.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@ -170,7 +170,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 {
|
||||||
File root = SD.open(path);
|
FsFile root = SdMan.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;
|
||||||
@ -184,9 +184,11 @@ 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);
|
||||||
|
|
||||||
File file = root.openNextFile();
|
FsFile file = root.openNextFile();
|
||||||
|
char name[128];
|
||||||
while (file) {
|
while (file) {
|
||||||
auto fileName = String(file.name());
|
file.getName(name, sizeof(name));
|
||||||
|
auto fileName = String(name);
|
||||||
|
|
||||||
// Skip hidden items (starting with ".")
|
// Skip hidden items (starting with ".")
|
||||||
bool shouldHide = fileName.startsWith(".");
|
bool shouldHide = fileName.startsWith(".");
|
||||||
@ -279,7 +281,7 @@ void CrossPointWebServer::handleFileListData() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Static variables for upload handling
|
// Static variables for upload handling
|
||||||
static File uploadFile;
|
static FsFile uploadFile;
|
||||||
static String uploadFileName;
|
static String uploadFileName;
|
||||||
static String uploadPath = "/";
|
static String uploadPath = "/";
|
||||||
static size_t uploadSize = 0;
|
static size_t uploadSize = 0;
|
||||||
@ -334,13 +336,13 @@ void CrossPointWebServer::handleUpload() const {
|
|||||||
filePath += uploadFileName;
|
filePath += uploadFileName;
|
||||||
|
|
||||||
// Check if file already exists
|
// Check if file already exists
|
||||||
if (SD.exists(filePath.c_str())) {
|
if (SdMan.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());
|
||||||
SD.remove(filePath.c_str());
|
SdMan.remove(filePath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open file for writing
|
// Open file for writing
|
||||||
if (!FsHelpers::openFileForWrite("WEB", filePath, uploadFile)) {
|
if (!SdMan.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;
|
||||||
@ -393,7 +395,7 @@ void CrossPointWebServer::handleUpload() const {
|
|||||||
String filePath = uploadPath;
|
String filePath = uploadPath;
|
||||||
if (!filePath.endsWith("/")) filePath += "/";
|
if (!filePath.endsWith("/")) filePath += "/";
|
||||||
filePath += uploadFileName;
|
filePath += uploadFileName;
|
||||||
SD.remove(filePath.c_str());
|
SdMan.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());
|
||||||
@ -444,13 +446,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 (SD.exists(folderPath.c_str())) {
|
if (SdMan.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 (SD.mkdir(folderPath.c_str())) {
|
if (SdMan.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 {
|
||||||
@ -500,7 +502,7 @@ void CrossPointWebServer::handleDelete() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if item exists
|
// Check if item exists
|
||||||
if (!SD.exists(itemPath.c_str())) {
|
if (!SdMan.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;
|
||||||
@ -512,10 +514,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)
|
||||||
File dir = SD.open(itemPath.c_str());
|
FsFile dir = SdMan.open(itemPath.c_str());
|
||||||
if (dir && dir.isDirectory()) {
|
if (dir && dir.isDirectory()) {
|
||||||
// Check if folder is empty
|
// Check if folder is empty
|
||||||
File entry = dir.openNextFile();
|
FsFile entry = dir.openNextFile();
|
||||||
if (entry) {
|
if (entry) {
|
||||||
// Folder is not empty
|
// Folder is not empty
|
||||||
entry.close();
|
entry.close();
|
||||||
@ -526,10 +528,10 @@ void CrossPointWebServer::handleDelete() const {
|
|||||||
}
|
}
|
||||||
dir.close();
|
dir.close();
|
||||||
}
|
}
|
||||||
success = SD.rmdir(itemPath.c_str());
|
success = SdMan.rmdir(itemPath.c_str());
|
||||||
} else {
|
} else {
|
||||||
// For files, use remove
|
// For files, use remove
|
||||||
success = SD.remove(itemPath.c_str());
|
success = SdMan.remove(itemPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user