feat: Add central logging pragma (#843)
## Summary
* Definition and use of a central LOG function, that can later be
extended or completely be removed (for public use where debugging
information may not be required) to save flash by suppressing the
-DENABLE_SERIAL_LOG like in the slim branch
* **What changes are included?**
## Additional Context
* By using the central logger the usual:
```
#include <HardwareSerial.h>
...
Serial.printf("[%lu] [WCS] Obfuscating/deobfuscating %zu bytes\n", millis(), data.size());
```
would then become
```
#include <Logging.h>
...
LOG_DBG("WCS", "Obfuscating/deobfuscating %zu bytes", data.size());
```
You do have ``LOG_DBG`` for debug messages, ``LOG_ERR`` for error
messages and ``LOG_INF`` for informational messages. Depending on the
verbosity level defined (see below) soe of these message types will be
suppressed/not-compiled.
* The normal compilation (default) will create a firmware.elf file of
42.194.356 bytes, the same code via slim will create 42.024.048 bytes -
170.308 bytes less
* Firmware.bin : 6.469.984 bytes for default, 6.418.672 bytes for slim -
51.312 bytes less
### AI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing,
please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? _NO_
---------
Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
This commit is contained in:
@@ -2,8 +2,8 @@
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <JpegToBmpConverter.h>
|
||||
#include <Logging.h>
|
||||
#include <ZipFile.h>
|
||||
|
||||
#include "Epub/parsers/ContainerParser.h"
|
||||
@@ -17,7 +17,7 @@ bool Epub::findContentOpfFile(std::string* contentOpfFile) const {
|
||||
|
||||
// Get file size without loading it all into heap
|
||||
if (!getItemSize(containerPath, &containerSize)) {
|
||||
Serial.printf("[%lu] [EBP] Could not find or size META-INF/container.xml\n", millis());
|
||||
LOG_ERR("EBP", "Could not find or size META-INF/container.xml");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,13 +29,13 @@ bool Epub::findContentOpfFile(std::string* contentOpfFile) const {
|
||||
|
||||
// Stream read (reusing your existing stream logic)
|
||||
if (!readItemContentsToStream(containerPath, containerParser, 512)) {
|
||||
Serial.printf("[%lu] [EBP] Could not read META-INF/container.xml\n", millis());
|
||||
LOG_ERR("EBP", "Could not read META-INF/container.xml");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract the result
|
||||
if (containerParser.fullPath.empty()) {
|
||||
Serial.printf("[%lu] [EBP] Could not find valid rootfile in container.xml\n", millis());
|
||||
LOG_ERR("EBP", "Could not find valid rootfile in container.xml");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,28 +46,28 @@ bool Epub::findContentOpfFile(std::string* contentOpfFile) const {
|
||||
bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) {
|
||||
std::string contentOpfFilePath;
|
||||
if (!findContentOpfFile(&contentOpfFilePath)) {
|
||||
Serial.printf("[%lu] [EBP] Could not find content.opf in zip\n", millis());
|
||||
LOG_ERR("EBP", "Could not find content.opf in zip");
|
||||
return false;
|
||||
}
|
||||
|
||||
contentBasePath = contentOpfFilePath.substr(0, contentOpfFilePath.find_last_of('/') + 1);
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsing content.opf: %s\n", millis(), contentOpfFilePath.c_str());
|
||||
LOG_DBG("EBP", "Parsing content.opf: %s", contentOpfFilePath.c_str());
|
||||
|
||||
size_t contentOpfSize;
|
||||
if (!getItemSize(contentOpfFilePath, &contentOpfSize)) {
|
||||
Serial.printf("[%lu] [EBP] Could not get size of content.opf\n", millis());
|
||||
LOG_ERR("EBP", "Could not get size of content.opf");
|
||||
return false;
|
||||
}
|
||||
|
||||
ContentOpfParser opfParser(getCachePath(), getBasePath(), contentOpfSize, bookMetadataCache.get());
|
||||
if (!opfParser.setup()) {
|
||||
Serial.printf("[%lu] [EBP] Could not setup content.opf parser\n", millis());
|
||||
LOG_ERR("EBP", "Could not setup content.opf parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!readItemContentsToStream(contentOpfFilePath, opfParser, 1024)) {
|
||||
Serial.printf("[%lu] [EBP] Could not read content.opf\n", millis());
|
||||
LOG_ERR("EBP", "Could not read content.opf");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -90,18 +90,18 @@ bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) {
|
||||
cssFiles = opfParser.cssFiles;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Successfully parsed content.opf\n", millis());
|
||||
LOG_DBG("EBP", "Successfully parsed content.opf");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Epub::parseTocNcxFile() const {
|
||||
// the ncx file should have been specified in the content.opf file
|
||||
if (tocNcxItem.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No ncx file specified\n", millis());
|
||||
LOG_DBG("EBP", "No ncx file specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsing toc ncx file: %s\n", millis(), tocNcxItem.c_str());
|
||||
LOG_DBG("EBP", "Parsing toc ncx file: %s", tocNcxItem.c_str());
|
||||
|
||||
const auto tmpNcxPath = getCachePath() + "/toc.ncx";
|
||||
FsFile tempNcxFile;
|
||||
@@ -118,14 +118,14 @@ bool Epub::parseTocNcxFile() const {
|
||||
TocNcxParser ncxParser(contentBasePath, ncxSize, bookMetadataCache.get());
|
||||
|
||||
if (!ncxParser.setup()) {
|
||||
Serial.printf("[%lu] [EBP] Could not setup toc ncx parser\n", millis());
|
||||
LOG_ERR("EBP", "Could not setup toc ncx parser");
|
||||
tempNcxFile.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto ncxBuffer = static_cast<uint8_t*>(malloc(1024));
|
||||
if (!ncxBuffer) {
|
||||
Serial.printf("[%lu] [EBP] Could not allocate memory for toc ncx parser\n", millis());
|
||||
LOG_ERR("EBP", "Could not allocate memory for toc ncx parser");
|
||||
tempNcxFile.close();
|
||||
return false;
|
||||
}
|
||||
@@ -136,7 +136,7 @@ bool Epub::parseTocNcxFile() const {
|
||||
const auto processedSize = ncxParser.write(ncxBuffer, readSize);
|
||||
|
||||
if (processedSize != readSize) {
|
||||
Serial.printf("[%lu] [EBP] Could not process all toc ncx data\n", millis());
|
||||
LOG_ERR("EBP", "Could not process all toc ncx data");
|
||||
free(ncxBuffer);
|
||||
tempNcxFile.close();
|
||||
return false;
|
||||
@@ -147,18 +147,18 @@ bool Epub::parseTocNcxFile() const {
|
||||
tempNcxFile.close();
|
||||
Storage.remove(tmpNcxPath.c_str());
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis());
|
||||
LOG_DBG("EBP", "Parsed TOC items");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Epub::parseTocNavFile() const {
|
||||
// the nav file should have been specified in the content.opf file (EPUB 3)
|
||||
if (tocNavItem.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No nav file specified\n", millis());
|
||||
LOG_DBG("EBP", "No nav file specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsing toc nav file: %s\n", millis(), tocNavItem.c_str());
|
||||
LOG_DBG("EBP", "Parsing toc nav file: %s", tocNavItem.c_str());
|
||||
|
||||
const auto tmpNavPath = getCachePath() + "/toc.nav";
|
||||
FsFile tempNavFile;
|
||||
@@ -178,13 +178,13 @@ bool Epub::parseTocNavFile() const {
|
||||
TocNavParser navParser(navContentBasePath, navSize, bookMetadataCache.get());
|
||||
|
||||
if (!navParser.setup()) {
|
||||
Serial.printf("[%lu] [EBP] Could not setup toc nav parser\n", millis());
|
||||
LOG_ERR("EBP", "Could not setup toc nav parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto navBuffer = static_cast<uint8_t*>(malloc(1024));
|
||||
if (!navBuffer) {
|
||||
Serial.printf("[%lu] [EBP] Could not allocate memory for toc nav parser\n", millis());
|
||||
LOG_ERR("EBP", "Could not allocate memory for toc nav parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ bool Epub::parseTocNavFile() const {
|
||||
const auto processedSize = navParser.write(navBuffer, readSize);
|
||||
|
||||
if (processedSize != readSize) {
|
||||
Serial.printf("[%lu] [EBP] Could not process all toc nav data\n", millis());
|
||||
LOG_ERR("EBP", "Could not process all toc nav data");
|
||||
free(navBuffer);
|
||||
tempNavFile.close();
|
||||
return false;
|
||||
@@ -204,7 +204,7 @@ bool Epub::parseTocNavFile() const {
|
||||
tempNavFile.close();
|
||||
Storage.remove(tmpNavPath.c_str());
|
||||
|
||||
Serial.printf("[%lu] [EBP] Parsed TOC nav items\n", millis());
|
||||
LOG_DBG("EBP", "Parsed TOC nav items");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -215,35 +215,35 @@ bool Epub::loadCssRulesFromCache() const {
|
||||
if (Storage.openFileForRead("EBP", getCssRulesCache(), cssCacheFile)) {
|
||||
if (cssParser->loadFromCache(cssCacheFile)) {
|
||||
cssCacheFile.close();
|
||||
Serial.printf("[%lu] [EBP] Loaded CSS rules from cache\n", millis());
|
||||
LOG_DBG("EBP", "Loaded CSS rules from cache");
|
||||
return true;
|
||||
}
|
||||
cssCacheFile.close();
|
||||
Serial.printf("[%lu] [EBP] CSS cache invalid, reparsing\n", millis());
|
||||
LOG_DBG("EBP", "CSS cache invalid, reparsing");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Epub::parseCssFiles() const {
|
||||
if (cssFiles.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No CSS files to parse, but CssParser created for inline styles\n", millis());
|
||||
LOG_DBG("EBP", "No CSS files to parse, but CssParser created for inline styles");
|
||||
}
|
||||
|
||||
// Try to load from CSS cache first
|
||||
if (!loadCssRulesFromCache()) {
|
||||
// Cache miss - parse CSS files
|
||||
for (const auto& cssPath : cssFiles) {
|
||||
Serial.printf("[%lu] [EBP] Parsing CSS file: %s\n", millis(), cssPath.c_str());
|
||||
LOG_DBG("EBP", "Parsing CSS file: %s", cssPath.c_str());
|
||||
|
||||
// Extract CSS file to temp location
|
||||
const auto tmpCssPath = getCachePath() + "/.tmp.css";
|
||||
FsFile tempCssFile;
|
||||
if (!Storage.openFileForWrite("EBP", tmpCssPath, tempCssFile)) {
|
||||
Serial.printf("[%lu] [EBP] Could not create temp CSS file\n", millis());
|
||||
LOG_ERR("EBP", "Could not create temp CSS file");
|
||||
continue;
|
||||
}
|
||||
if (!readItemContentsToStream(cssPath, tempCssFile, 1024)) {
|
||||
Serial.printf("[%lu] [EBP] Could not read CSS file: %s\n", millis(), cssPath.c_str());
|
||||
LOG_ERR("EBP", "Could not read CSS file: %s", cssPath.c_str());
|
||||
tempCssFile.close();
|
||||
Storage.remove(tmpCssPath.c_str());
|
||||
continue;
|
||||
@@ -252,7 +252,7 @@ void Epub::parseCssFiles() const {
|
||||
|
||||
// Parse the CSS file
|
||||
if (!Storage.openFileForRead("EBP", tmpCssPath, tempCssFile)) {
|
||||
Serial.printf("[%lu] [EBP] Could not open temp CSS file for reading\n", millis());
|
||||
LOG_ERR("EBP", "Could not open temp CSS file for reading");
|
||||
Storage.remove(tmpCssPath.c_str());
|
||||
continue;
|
||||
}
|
||||
@@ -268,14 +268,13 @@ void Epub::parseCssFiles() const {
|
||||
cssCacheFile.close();
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Loaded %zu CSS style rules from %zu files\n", millis(), cssParser->ruleCount(),
|
||||
cssFiles.size());
|
||||
LOG_DBG("EBP", "Loaded %zu CSS style rules from %zu files", cssParser->ruleCount(), cssFiles.size());
|
||||
}
|
||||
}
|
||||
|
||||
// load in the meta data for the epub file
|
||||
bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
Serial.printf("[%lu] [EBP] Loading ePub: %s\n", millis(), filepath.c_str());
|
||||
LOG_DBG("EBP", "Loading ePub: %s", filepath.c_str());
|
||||
|
||||
// Initialize spine/TOC cache
|
||||
bookMetadataCache.reset(new BookMetadataCache(cachePath));
|
||||
@@ -285,15 +284,15 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
// Try to load existing cache first
|
||||
if (bookMetadataCache->load()) {
|
||||
if (!skipLoadingCss && !loadCssRulesFromCache()) {
|
||||
Serial.printf("[%lu] [EBP] Warning: CSS rules cache not found, attempting to parse CSS files\n", millis());
|
||||
LOG_DBG("EBP", "Warning: CSS rules cache not found, attempting to parse CSS files");
|
||||
// to get CSS file list
|
||||
if (!parseContentOpf(bookMetadataCache->coreMetadata)) {
|
||||
Serial.printf("[%lu] [EBP] Could not parse content.opf from cached bookMetadata for CSS files\n", millis());
|
||||
LOG_ERR("EBP", "Could not parse content.opf from cached bookMetadata for CSS files");
|
||||
// continue anyway - book will work without CSS and we'll still load any inline style CSS
|
||||
}
|
||||
parseCssFiles();
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
||||
LOG_DBG("EBP", "Loaded ePub: %s", filepath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -303,14 +302,14 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
}
|
||||
|
||||
// Cache doesn't exist or is invalid, build it
|
||||
Serial.printf("[%lu] [EBP] Cache not found, building spine/TOC cache\n", millis());
|
||||
LOG_DBG("EBP", "Cache not found, building spine/TOC cache");
|
||||
setupCacheDir();
|
||||
|
||||
const uint32_t indexingStart = millis();
|
||||
|
||||
// Begin building cache - stream entries to disk immediately
|
||||
if (!bookMetadataCache->beginWrite()) {
|
||||
Serial.printf("[%lu] [EBP] Could not begin writing cache\n", millis());
|
||||
LOG_ERR("EBP", "Could not begin writing cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -318,23 +317,23 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
const uint32_t opfStart = millis();
|
||||
BookMetadataCache::BookMetadata bookMetadata;
|
||||
if (!bookMetadataCache->beginContentOpfPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not begin writing content.opf pass\n", millis());
|
||||
LOG_ERR("EBP", "Could not begin writing content.opf pass");
|
||||
return false;
|
||||
}
|
||||
if (!parseContentOpf(bookMetadata)) {
|
||||
Serial.printf("[%lu] [EBP] Could not parse content.opf\n", millis());
|
||||
LOG_ERR("EBP", "Could not parse content.opf");
|
||||
return false;
|
||||
}
|
||||
if (!bookMetadataCache->endContentOpfPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not end writing content.opf pass\n", millis());
|
||||
LOG_ERR("EBP", "Could not end writing content.opf pass");
|
||||
return false;
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] OPF pass completed in %lu ms\n", millis(), millis() - opfStart);
|
||||
LOG_DBG("EBP", "OPF pass completed in %lu ms", millis() - opfStart);
|
||||
|
||||
// TOC Pass - try EPUB 3 nav first, fall back to NCX
|
||||
const uint32_t tocStart = millis();
|
||||
if (!bookMetadataCache->beginTocPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not begin writing toc pass\n", millis());
|
||||
LOG_ERR("EBP", "Could not begin writing toc pass");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -342,50 +341,50 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
|
||||
// Try EPUB 3 nav document first (preferred)
|
||||
if (!tocNavItem.empty()) {
|
||||
Serial.printf("[%lu] [EBP] Attempting to parse EPUB 3 nav document\n", millis());
|
||||
LOG_DBG("EBP", "Attempting to parse EPUB 3 nav document");
|
||||
tocParsed = parseTocNavFile();
|
||||
}
|
||||
|
||||
// Fall back to NCX if nav parsing failed or wasn't available
|
||||
if (!tocParsed && !tocNcxItem.empty()) {
|
||||
Serial.printf("[%lu] [EBP] Falling back to NCX TOC\n", millis());
|
||||
LOG_DBG("EBP", "Falling back to NCX TOC");
|
||||
tocParsed = parseTocNcxFile();
|
||||
}
|
||||
|
||||
if (!tocParsed) {
|
||||
Serial.printf("[%lu] [EBP] Warning: Could not parse any TOC format\n", millis());
|
||||
LOG_ERR("EBP", "Warning: Could not parse any TOC format");
|
||||
// Continue anyway - book will work without TOC
|
||||
}
|
||||
|
||||
if (!bookMetadataCache->endTocPass()) {
|
||||
Serial.printf("[%lu] [EBP] Could not end writing toc pass\n", millis());
|
||||
LOG_ERR("EBP", "Could not end writing toc pass");
|
||||
return false;
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] TOC pass completed in %lu ms\n", millis(), millis() - tocStart);
|
||||
LOG_DBG("EBP", "TOC pass completed in %lu ms", millis() - tocStart);
|
||||
|
||||
// Close the cache files
|
||||
if (!bookMetadataCache->endWrite()) {
|
||||
Serial.printf("[%lu] [EBP] Could not end writing cache\n", millis());
|
||||
LOG_ERR("EBP", "Could not end writing cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build final book.bin
|
||||
const uint32_t buildStart = millis();
|
||||
if (!bookMetadataCache->buildBookBin(filepath, bookMetadata)) {
|
||||
Serial.printf("[%lu] [EBP] Could not update mappings and sizes\n", millis());
|
||||
LOG_ERR("EBP", "Could not update mappings and sizes");
|
||||
return false;
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] buildBookBin completed in %lu ms\n", millis(), millis() - buildStart);
|
||||
Serial.printf("[%lu] [EBP] Total indexing completed in %lu ms\n", millis(), millis() - indexingStart);
|
||||
LOG_DBG("EBP", "buildBookBin completed in %lu ms", millis() - buildStart);
|
||||
LOG_DBG("EBP", "Total indexing completed in %lu ms", millis() - indexingStart);
|
||||
|
||||
if (!bookMetadataCache->cleanupTmpFiles()) {
|
||||
Serial.printf("[%lu] [EBP] Could not cleanup tmp files - ignoring\n", millis());
|
||||
LOG_DBG("EBP", "Could not cleanup tmp files - ignoring");
|
||||
}
|
||||
|
||||
// Reload the cache from disk so it's in the correct state
|
||||
bookMetadataCache.reset(new BookMetadataCache(cachePath));
|
||||
if (!bookMetadataCache->load()) {
|
||||
Serial.printf("[%lu] [EBP] Failed to reload cache after writing\n", millis());
|
||||
LOG_ERR("EBP", "Failed to reload cache after writing");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -394,22 +393,22 @@ bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) {
|
||||
parseCssFiles();
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str());
|
||||
LOG_DBG("EBP", "Loaded ePub: %s", filepath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Epub::clearCache() const {
|
||||
if (!Storage.exists(cachePath.c_str())) {
|
||||
Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis());
|
||||
LOG_DBG("EPB", "Cache does not exist, no action needed");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Storage.removeDir(cachePath.c_str())) {
|
||||
Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis());
|
||||
LOG_ERR("EPB", "Failed to clear cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EPB] Cache cleared successfully\n", millis());
|
||||
LOG_DBG("EPB", "Cache cleared successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -464,19 +463,19 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
}
|
||||
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] Cannot generate cover BMP, cache not loaded\n", millis());
|
||||
LOG_ERR("EBP", "Cannot generate cover BMP, cache not loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto coverImageHref = bookMetadataCache->coreMetadata.coverItemHref;
|
||||
if (coverImageHref.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No known cover image\n", millis());
|
||||
LOG_ERR("EBP", "No known cover image");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" ||
|
||||
coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") {
|
||||
Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image (%s mode)\n", millis(), cropped ? "cropped" : "fit");
|
||||
LOG_DBG("EBP", "Generating BMP from JPG cover image (%s mode)", cropped ? "cropped" : "fit");
|
||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||
|
||||
FsFile coverJpg;
|
||||
@@ -501,13 +500,13 @@ bool Epub::generateCoverBmp(bool cropped) const {
|
||||
Storage.remove(coverJpgTempPath.c_str());
|
||||
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis());
|
||||
LOG_ERR("EBP", "Failed to generate BMP from cover image");
|
||||
Storage.remove(getCoverBmpPath(cropped).c_str());
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no");
|
||||
LOG_DBG("EBP", "Generated BMP from cover image, success: %s", success ? "yes" : "no");
|
||||
return success;
|
||||
} else {
|
||||
Serial.printf("[%lu] [EBP] Cover image is not a JPG, skipping\n", millis());
|
||||
LOG_ERR("EBP", "Cover image is not a supported format, skipping");
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -523,16 +522,16 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
}
|
||||
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] Cannot generate thumb BMP, cache not loaded\n", millis());
|
||||
LOG_ERR("EBP", "Cannot generate thumb BMP, cache not loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto coverImageHref = bookMetadataCache->coreMetadata.coverItemHref;
|
||||
if (coverImageHref.empty()) {
|
||||
Serial.printf("[%lu] [EBP] No known cover image for thumbnail\n", millis());
|
||||
LOG_DBG("EBP", "No known cover image for thumbnail");
|
||||
} else if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" ||
|
||||
coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") {
|
||||
Serial.printf("[%lu] [EBP] Generating thumb BMP from JPG cover image\n", millis());
|
||||
LOG_DBG("EBP", "Generating thumb BMP from JPG cover image");
|
||||
const auto coverJpgTempPath = getCachePath() + "/.cover.jpg";
|
||||
|
||||
FsFile coverJpg;
|
||||
@@ -562,14 +561,13 @@ bool Epub::generateThumbBmp(int height) const {
|
||||
Storage.remove(coverJpgTempPath.c_str());
|
||||
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [EBP] Failed to generate thumb BMP from JPG cover image\n", millis());
|
||||
LOG_ERR("EBP", "Failed to generate thumb BMP from JPG cover image");
|
||||
Storage.remove(getThumbBmpPath(height).c_str());
|
||||
}
|
||||
Serial.printf("[%lu] [EBP] Generated thumb BMP from JPG cover image, success: %s\n", millis(),
|
||||
success ? "yes" : "no");
|
||||
LOG_DBG("EBP", "Generated thumb BMP from JPG cover image, success: %s", success ? "yes" : "no");
|
||||
return success;
|
||||
} else {
|
||||
Serial.printf("[%lu] [EBP] Cover image is not a JPG, skipping thumbnail\n", millis());
|
||||
LOG_ERR("EBP", "Cover image is not a supported format, skipping thumbnail");
|
||||
}
|
||||
|
||||
// Write an empty bmp file to avoid generation attempts in the future
|
||||
@@ -581,7 +579,7 @@ bool Epub::generateThumbBmp(int height) 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());
|
||||
LOG_DBG("EBP", "Failed to read item, empty href");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -589,7 +587,7 @@ uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size
|
||||
|
||||
const auto content = ZipFile(filepath).readFileToMemory(path.c_str(), size, trailingNullByte);
|
||||
if (!content) {
|
||||
Serial.printf("[%lu] [EBP] Failed to read item %s\n", millis(), path.c_str());
|
||||
LOG_DBG("EBP", "Failed to read item %s", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -598,7 +596,7 @@ 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 {
|
||||
if (itemHref.empty()) {
|
||||
Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis());
|
||||
LOG_DBG("EBP", "Failed to read item, empty href");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -622,12 +620,12 @@ size_t Epub::getCumulativeSpineItemSize(const int spineIndex) const { return get
|
||||
|
||||
BookMetadataCache::SpineEntry Epub::getSpineItem(const int spineIndex) const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineItem called but cache not loaded\n", millis());
|
||||
LOG_ERR("EBP", "getSpineItem called but cache not loaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (spineIndex < 0 || spineIndex >= bookMetadataCache->getSpineCount()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineItem index:%d is out of range\n", millis(), spineIndex);
|
||||
LOG_ERR("EBP", "getSpineItem index:%d is out of range", spineIndex);
|
||||
return bookMetadataCache->getSpineEntry(0);
|
||||
}
|
||||
|
||||
@@ -636,12 +634,12 @@ BookMetadataCache::SpineEntry Epub::getSpineItem(const int spineIndex) const {
|
||||
|
||||
BookMetadataCache::TocEntry Epub::getTocItem(const int tocIndex) const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getTocItem called but cache not loaded\n", millis());
|
||||
LOG_DBG("EBP", "getTocItem called but cache not loaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) {
|
||||
Serial.printf("[%lu] [EBP] getTocItem index:%d is out of range\n", millis(), tocIndex);
|
||||
LOG_DBG("EBP", "getTocItem index:%d is out of range", tocIndex);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -659,18 +657,18 @@ int Epub::getTocItemsCount() const {
|
||||
// work out the section index for a toc index
|
||||
int Epub::getSpineIndexForTocIndex(const int tocIndex) const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex called but cache not loaded\n", millis());
|
||||
LOG_ERR("EBP", "getSpineIndexForTocIndex called but cache not loaded");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex: tocIndex %d out of range\n", millis(), tocIndex);
|
||||
LOG_ERR("EBP", "getSpineIndexForTocIndex: tocIndex %d out of range", tocIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const int spineIndex = bookMetadataCache->getTocEntry(tocIndex).spineIndex;
|
||||
if (spineIndex < 0) {
|
||||
Serial.printf("[%lu] [EBP] Section not found for TOC index %d\n", millis(), tocIndex);
|
||||
LOG_DBG("EBP", "Section not found for TOC index %d", tocIndex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -688,14 +686,13 @@ size_t Epub::getBookSize() const {
|
||||
|
||||
int Epub::getSpineIndexForTextReference() const {
|
||||
if (!bookMetadataCache || !bookMetadataCache->isLoaded()) {
|
||||
Serial.printf("[%lu] [EBP] getSpineIndexForTextReference called but cache not loaded\n", millis());
|
||||
LOG_ERR("EBP", "getSpineIndexForTextReference called but cache not loaded");
|
||||
return 0;
|
||||
}
|
||||
Serial.printf("[%lu] [ERS] Core Metadata: cover(%d)=%s, textReference(%d)=%s\n", millis(),
|
||||
bookMetadataCache->coreMetadata.coverItemHref.size(),
|
||||
bookMetadataCache->coreMetadata.coverItemHref.c_str(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.size(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.c_str());
|
||||
LOG_DBG("EBP", "Core Metadata: cover(%d)=%s, textReference(%d)=%s",
|
||||
bookMetadataCache->coreMetadata.coverItemHref.size(), bookMetadataCache->coreMetadata.coverItemHref.c_str(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.size(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.c_str());
|
||||
|
||||
if (bookMetadataCache->coreMetadata.textReferenceHref.empty()) {
|
||||
// there was no textReference in epub, so we return 0 (the first chapter)
|
||||
@@ -705,13 +702,13 @@ int Epub::getSpineIndexForTextReference() const {
|
||||
// loop through spine items to get the correct index matching the text href
|
||||
for (size_t i = 0; i < getSpineItemsCount(); i++) {
|
||||
if (getSpineItem(i).href == bookMetadataCache->coreMetadata.textReferenceHref) {
|
||||
Serial.printf("[%lu] [ERS] Text reference %s found at index %d\n", millis(),
|
||||
bookMetadataCache->coreMetadata.textReferenceHref.c_str(), i);
|
||||
LOG_DBG("EBP", "Text reference %s found at index %d", bookMetadataCache->coreMetadata.textReferenceHref.c_str(),
|
||||
i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// This should not happen, as we checked for empty textReferenceHref earlier
|
||||
Serial.printf("[%lu] [EBP] Section not found for text reference\n", millis());
|
||||
LOG_DBG("EBP", "Section not found for text reference");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "BookMetadataCache.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <Serialization.h>
|
||||
#include <ZipFile.h>
|
||||
|
||||
@@ -21,12 +21,12 @@ bool BookMetadataCache::beginWrite() {
|
||||
buildMode = true;
|
||||
spineCount = 0;
|
||||
tocCount = 0;
|
||||
Serial.printf("[%lu] [BMC] Entering write mode\n", millis());
|
||||
LOG_DBG("BMC", "Entering write mode");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BookMetadataCache::beginContentOpfPass() {
|
||||
Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis());
|
||||
LOG_DBG("BMC", "Beginning content opf pass");
|
||||
|
||||
// Open spine file for writing
|
||||
return Storage.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile);
|
||||
@@ -38,7 +38,7 @@ bool BookMetadataCache::endContentOpfPass() {
|
||||
}
|
||||
|
||||
bool BookMetadataCache::beginTocPass() {
|
||||
Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis());
|
||||
LOG_DBG("BMC", "Beginning toc pass");
|
||||
|
||||
if (!Storage.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) {
|
||||
return false;
|
||||
@@ -66,7 +66,7 @@ bool BookMetadataCache::beginTocPass() {
|
||||
});
|
||||
spineFile.seek(0);
|
||||
useSpineHrefIndex = true;
|
||||
Serial.printf("[%lu] [BMC] Using fast index for %d spine items\n", millis(), spineCount);
|
||||
LOG_DBG("BMC", "Using fast index for %d spine items", spineCount);
|
||||
} else {
|
||||
useSpineHrefIndex = false;
|
||||
}
|
||||
@@ -87,12 +87,12 @@ bool BookMetadataCache::endTocPass() {
|
||||
|
||||
bool BookMetadataCache::endWrite() {
|
||||
if (!buildMode) {
|
||||
Serial.printf("[%lu] [BMC] endWrite called but not in build mode\n", millis());
|
||||
LOG_DBG("BMC", "endWrite called but not in build mode");
|
||||
return false;
|
||||
}
|
||||
|
||||
buildMode = false;
|
||||
Serial.printf("[%lu] [BMC] Wrote %d spine, %d TOC entries\n", millis(), spineCount, tocCount);
|
||||
LOG_DBG("BMC", "Wrote %d spine, %d TOC entries", spineCount, tocCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
ZipFile zip(epubPath);
|
||||
// Pre-open zip file to speed up size calculations
|
||||
if (!zip.open()) {
|
||||
Serial.printf("[%lu] [BMC] Could not open EPUB zip for size calculations\n", millis());
|
||||
LOG_ERR("BMC", "Could not open EPUB zip for size calculations");
|
||||
bookFile.close();
|
||||
spineFile.close();
|
||||
tocFile.close();
|
||||
@@ -185,7 +185,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
bool useBatchSizes = false;
|
||||
|
||||
if (spineCount >= LARGE_SPINE_THRESHOLD) {
|
||||
Serial.printf("[%lu] [BMC] Using batch size lookup for %d spine items\n", millis(), spineCount);
|
||||
LOG_DBG("BMC", "Using batch size lookup for %d spine items", spineCount);
|
||||
|
||||
std::vector<ZipFile::SizeTarget> targets;
|
||||
targets.reserve(spineCount);
|
||||
@@ -208,7 +208,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
|
||||
spineSizes.resize(spineCount, 0);
|
||||
int matched = zip.fillUncompressedSizes(targets, spineSizes);
|
||||
Serial.printf("[%lu] [BMC] Batch lookup matched %d/%d spine items\n", millis(), matched, spineCount);
|
||||
LOG_DBG("BMC", "Batch lookup matched %d/%d spine items", matched, spineCount);
|
||||
|
||||
targets.clear();
|
||||
targets.shrink_to_fit();
|
||||
@@ -227,9 +227,8 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
// Not a huge deal if we don't fine a TOC entry for the spine entry, this is expected behaviour for EPUBs
|
||||
// Logging here is for debugging
|
||||
if (spineEntry.tocIndex == -1) {
|
||||
Serial.printf(
|
||||
"[%lu] [BMC] Warning: Could not find TOC entry for spine item %d: %s, using title from last section\n",
|
||||
millis(), i, spineEntry.href.c_str());
|
||||
LOG_DBG("BMC", "Warning: Could not find TOC entry for spine item %d: %s, using title from last section", i,
|
||||
spineEntry.href.c_str());
|
||||
spineEntry.tocIndex = lastSpineTocIndex;
|
||||
}
|
||||
lastSpineTocIndex = spineEntry.tocIndex;
|
||||
@@ -240,13 +239,13 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
if (itemSize == 0) {
|
||||
const std::string path = FsHelpers::normalisePath(spineEntry.href);
|
||||
if (!zip.getInflatedFileSize(path.c_str(), &itemSize)) {
|
||||
Serial.printf("[%lu] [BMC] Warning: Could not get size for spine item: %s\n", millis(), path.c_str());
|
||||
LOG_ERR("BMC", "Warning: Could not get size for spine item: %s", path.c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const std::string path = FsHelpers::normalisePath(spineEntry.href);
|
||||
if (!zip.getInflatedFileSize(path.c_str(), &itemSize)) {
|
||||
Serial.printf("[%lu] [BMC] Warning: Could not get size for spine item: %s\n", millis(), path.c_str());
|
||||
LOG_ERR("BMC", "Warning: Could not get size for spine item: %s", path.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +269,7 @@ bool BookMetadataCache::buildBookBin(const std::string& epubPath, const BookMeta
|
||||
spineFile.close();
|
||||
tocFile.close();
|
||||
|
||||
Serial.printf("[%lu] [BMC] Successfully built book.bin\n", millis());
|
||||
LOG_DBG("BMC", "Successfully built book.bin");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -306,7 +305,7 @@ uint32_t BookMetadataCache::writeTocEntry(FsFile& file, const TocEntry& entry) c
|
||||
// this is because in this function we're marking positions of the items
|
||||
void BookMetadataCache::createSpineEntry(const std::string& href) {
|
||||
if (!buildMode || !spineFile) {
|
||||
Serial.printf("[%lu] [BMC] createSpineEntry called but not in build mode\n", millis());
|
||||
LOG_DBG("BMC", "createSpineEntry called but not in build mode");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -318,7 +317,7 @@ void BookMetadataCache::createSpineEntry(const std::string& href) {
|
||||
void BookMetadataCache::createTocEntry(const std::string& title, const std::string& href, const std::string& anchor,
|
||||
const uint8_t level) {
|
||||
if (!buildMode || !tocFile || !spineFile) {
|
||||
Serial.printf("[%lu] [BMC] createTocEntry called but not in build mode\n", millis());
|
||||
LOG_DBG("BMC", "createTocEntry called but not in build mode");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -340,7 +339,7 @@ void BookMetadataCache::createTocEntry(const std::string& title, const std::stri
|
||||
}
|
||||
|
||||
if (spineIndex == -1) {
|
||||
Serial.printf("[%lu] [BMC] createTocEntry: Could not find spine item for TOC href %s\n", millis(), href.c_str());
|
||||
LOG_DBG("BMC", "createTocEntry: Could not find spine item for TOC href %s", href.c_str());
|
||||
}
|
||||
} else {
|
||||
spineFile.seek(0);
|
||||
@@ -352,7 +351,7 @@ void BookMetadataCache::createTocEntry(const std::string& title, const std::stri
|
||||
}
|
||||
}
|
||||
if (spineIndex == -1) {
|
||||
Serial.printf("[%lu] [BMC] createTocEntry: Could not find spine item for TOC href %s\n", millis(), href.c_str());
|
||||
LOG_DBG("BMC", "createTocEntry: Could not find spine item for TOC href %s", href.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +370,7 @@ bool BookMetadataCache::load() {
|
||||
uint8_t version;
|
||||
serialization::readPod(bookFile, version);
|
||||
if (version != BOOK_CACHE_VERSION) {
|
||||
Serial.printf("[%lu] [BMC] Cache version mismatch: expected %d, got %d\n", millis(), BOOK_CACHE_VERSION, version);
|
||||
LOG_DBG("BMC", "Cache version mismatch: expected %d, got %d", BOOK_CACHE_VERSION, version);
|
||||
bookFile.close();
|
||||
return false;
|
||||
}
|
||||
@@ -387,18 +386,18 @@ bool BookMetadataCache::load() {
|
||||
serialization::readString(bookFile, coreMetadata.textReferenceHref);
|
||||
|
||||
loaded = true;
|
||||
Serial.printf("[%lu] [BMC] Loaded cache data: %d spine, %d TOC entries\n", millis(), spineCount, tocCount);
|
||||
LOG_DBG("BMC", "Loaded cache data: %d spine, %d TOC entries", spineCount, tocCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
BookMetadataCache::SpineEntry BookMetadataCache::getSpineEntry(const int index) {
|
||||
if (!loaded) {
|
||||
Serial.printf("[%lu] [BMC] getSpineEntry called but cache not loaded\n", millis());
|
||||
LOG_ERR("BMC", "getSpineEntry called but cache not loaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index < 0 || index >= static_cast<int>(spineCount)) {
|
||||
Serial.printf("[%lu] [BMC] getSpineEntry index %d out of range\n", millis(), index);
|
||||
LOG_ERR("BMC", "getSpineEntry index %d out of range", index);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -412,12 +411,12 @@ BookMetadataCache::SpineEntry BookMetadataCache::getSpineEntry(const int index)
|
||||
|
||||
BookMetadataCache::TocEntry BookMetadataCache::getTocEntry(const int index) {
|
||||
if (!loaded) {
|
||||
Serial.printf("[%lu] [BMC] getTocEntry called but cache not loaded\n", millis());
|
||||
LOG_ERR("BMC", "getTocEntry called but cache not loaded");
|
||||
return {};
|
||||
}
|
||||
|
||||
if (index < 0 || index >= static_cast<int>(tocCount)) {
|
||||
Serial.printf("[%lu] [BMC] getTocEntry index %d out of range\n", millis(), index);
|
||||
LOG_ERR("BMC", "getTocEntry index %d out of range", index);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "Page.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) {
|
||||
@@ -60,7 +60,7 @@ std::unique_ptr<Page> Page::deserialize(FsFile& file) {
|
||||
auto pl = PageLine::deserialize(file);
|
||||
page->elements.push_back(std::move(pl));
|
||||
} else {
|
||||
Serial.printf("[%lu] [PGE] Deserialization failed: Unknown tag %u\n", millis(), tag);
|
||||
LOG_ERR("PGE", "Deserialization failed: Unknown tag %u", tag);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "Section.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <Logging.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
#include "Page.h"
|
||||
@@ -16,16 +17,16 @@ constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + sizeof(int) + sizeof(float) +
|
||||
|
||||
uint32_t Section::onPageComplete(std::unique_ptr<Page> page) {
|
||||
if (!file) {
|
||||
Serial.printf("[%lu] [SCT] File not open for writing page %d\n", millis(), pageCount);
|
||||
LOG_ERR("SCT", "File not open for writing page %d", pageCount);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint32_t position = file.position();
|
||||
if (!page->serialize(file)) {
|
||||
Serial.printf("[%lu] [SCT] Failed to serialize page %d\n", millis(), pageCount);
|
||||
LOG_ERR("SCT", "Failed to serialize page %d", pageCount);
|
||||
return 0;
|
||||
}
|
||||
Serial.printf("[%lu] [SCT] Page %d processed\n", millis(), pageCount);
|
||||
LOG_DBG("SCT", "Page %d processed", pageCount);
|
||||
|
||||
pageCount++;
|
||||
return position;
|
||||
@@ -36,7 +37,7 @@ void Section::writeSectionFileHeader(const int fontId, const float lineCompressi
|
||||
const uint16_t viewportHeight, const bool hyphenationEnabled,
|
||||
const bool embeddedStyle) {
|
||||
if (!file) {
|
||||
Serial.printf("[%lu] [SCT] File not open for writing header\n", millis());
|
||||
LOG_DBG("SCT", "File not open for writing header");
|
||||
return;
|
||||
}
|
||||
static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) +
|
||||
@@ -70,7 +71,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
||||
serialization::readPod(file, version);
|
||||
if (version != SECTION_FILE_VERSION) {
|
||||
file.close();
|
||||
Serial.printf("[%lu] [SCT] Deserialization failed: Unknown version %u\n", millis(), version);
|
||||
LOG_ERR("SCT", "Deserialization failed: Unknown version %u", version);
|
||||
clearCache();
|
||||
return false;
|
||||
}
|
||||
@@ -96,7 +97,7 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
||||
viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight ||
|
||||
hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle) {
|
||||
file.close();
|
||||
Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis());
|
||||
LOG_ERR("SCT", "Deserialization failed: Parameters do not match");
|
||||
clearCache();
|
||||
return false;
|
||||
}
|
||||
@@ -104,23 +105,23 @@ bool Section::loadSectionFile(const int fontId, const float lineCompression, con
|
||||
|
||||
serialization::readPod(file, pageCount);
|
||||
file.close();
|
||||
Serial.printf("[%lu] [SCT] Deserialization succeeded: %d pages\n", millis(), pageCount);
|
||||
LOG_DBG("SCT", "Deserialization succeeded: %d pages", pageCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Your updated class method (assuming you are using the 'SD' object, which is a wrapper for a specific filesystem)
|
||||
bool Section::clearCache() const {
|
||||
if (!Storage.exists(filePath.c_str())) {
|
||||
Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis());
|
||||
LOG_DBG("SCT", "Cache does not exist, no action needed");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Storage.remove(filePath.c_str())) {
|
||||
Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis());
|
||||
LOG_ERR("SCT", "Failed to clear cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [SCT] Cache cleared successfully\n", millis());
|
||||
LOG_DBG("SCT", "Cache cleared successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -142,7 +143,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
uint32_t fileSize = 0;
|
||||
for (int attempt = 0; attempt < 3 && !success; attempt++) {
|
||||
if (attempt > 0) {
|
||||
Serial.printf("[%lu] [SCT] Retrying stream (attempt %d)...\n", millis(), attempt + 1);
|
||||
LOG_DBG("SCT", "Retrying stream (attempt %d)...", attempt + 1);
|
||||
delay(50); // Brief delay before retry
|
||||
}
|
||||
|
||||
@@ -162,16 +163,16 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
// If streaming failed, remove the incomplete file immediately
|
||||
if (!success && Storage.exists(tmpHtmlPath.c_str())) {
|
||||
Storage.remove(tmpHtmlPath.c_str());
|
||||
Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis());
|
||||
LOG_DBG("SCT", "Removed incomplete temp file after failed attempt");
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [SCT] Failed to stream item contents to temp file after retries\n", millis());
|
||||
LOG_ERR("SCT", "Failed to stream item contents to temp file after retries");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [SCT] Streamed temp HTML to %s (%d bytes)\n", millis(), tmpHtmlPath.c_str(), fileSize);
|
||||
LOG_DBG("SCT", "Streamed temp HTML to %s (%d bytes)", tmpHtmlPath.c_str(), fileSize);
|
||||
|
||||
if (!Storage.openFileForWrite("SCT", filePath, file)) {
|
||||
return false;
|
||||
@@ -190,7 +191,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
|
||||
Storage.remove(tmpHtmlPath.c_str());
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis());
|
||||
LOG_ERR("SCT", "Failed to parse XML and build pages");
|
||||
file.close();
|
||||
Storage.remove(filePath.c_str());
|
||||
return false;
|
||||
@@ -208,7 +209,7 @@ bool Section::createSectionFile(const int fontId, const float lineCompression, c
|
||||
}
|
||||
|
||||
if (hasFailedLutRecords) {
|
||||
Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis());
|
||||
LOG_ERR("SCT", "Failed to write LUT due to invalid page positions");
|
||||
file.close();
|
||||
Storage.remove(filePath.c_str());
|
||||
return false;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "TextBlock.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <Logging.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const {
|
||||
// Validate iterator bounds before rendering
|
||||
if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) {
|
||||
Serial.printf("[%lu] [TXB] Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(),
|
||||
(uint32_t)words.size(), (uint32_t)wordXpos.size(), (uint32_t)wordStyles.size());
|
||||
LOG_ERR("TXB", "Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", (uint32_t)words.size(),
|
||||
(uint32_t)wordXpos.size(), (uint32_t)wordStyles.size());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -49,8 +50,8 @@ void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int
|
||||
|
||||
bool TextBlock::serialize(FsFile& file) const {
|
||||
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(),
|
||||
words.size(), wordXpos.size(), wordStyles.size());
|
||||
LOG_ERR("TXB", "Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", words.size(),
|
||||
wordXpos.size(), wordStyles.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -89,7 +90,7 @@ std::unique_ptr<TextBlock> TextBlock::deserialize(FsFile& file) {
|
||||
|
||||
// Sanity check: prevent allocation of unreasonably large lists (max 10000 words per block)
|
||||
if (wc > 10000) {
|
||||
Serial.printf("[%lu] [TXB] Deserialization failed: word count %u exceeds maximum\n", millis(), wc);
|
||||
LOG_ERR("TXB", "Deserialization failed: word count %u exceeds maximum", wc);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "CssParser.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
@@ -449,7 +449,7 @@ void CssParser::processRuleBlock(const std::string& selectorGroup, const std::st
|
||||
|
||||
bool CssParser::loadFromStream(FsFile& source) {
|
||||
if (!source) {
|
||||
Serial.printf("[%lu] [CSS] Cannot read from invalid file\n", millis());
|
||||
LOG_ERR("CSS", "Cannot read from invalid file");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ bool CssParser::loadFromStream(FsFile& source) {
|
||||
processRuleBlock(selector, body);
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [CSS] Parsed %zu rules\n", millis(), rulesBySelector_.size());
|
||||
LOG_DBG("CSS", "Parsed %zu rules", rulesBySelector_.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -582,7 +582,7 @@ bool CssParser::saveToCache(FsFile& file) const {
|
||||
file.write(reinterpret_cast<const uint8_t*>(&definedBits), sizeof(definedBits));
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [CSS] Saved %u rules to cache\n", millis(), ruleCount);
|
||||
LOG_DBG("CSS", "Saved %u rules to cache", ruleCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -597,7 +597,7 @@ bool CssParser::loadFromCache(FsFile& file) {
|
||||
// Read and verify version
|
||||
uint8_t version = 0;
|
||||
if (file.read(&version, 1) != 1 || version != CSS_CACHE_VERSION) {
|
||||
Serial.printf("[%lu] [CSS] Cache version mismatch (got %u, expected %u)\n", millis(), version, CSS_CACHE_VERSION);
|
||||
LOG_DBG("CSS", "Cache version mismatch (got %u, expected %u)", version, CSS_CACHE_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -694,6 +694,6 @@ bool CssParser::loadFromCache(FsFile& file) {
|
||||
rulesBySelector_[selector] = style;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [CSS] Loaded %u rules from cache\n", millis(), ruleCount);
|
||||
LOG_DBG("CSS", "Loaded %u rules from cache", ruleCount);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <expat.h>
|
||||
|
||||
#include "../Page.h"
|
||||
@@ -168,7 +168,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [EHP] Image alt: %s\n", millis(), alt.c_str());
|
||||
LOG_DBG("EHP", "Image alt: %s", alt.c_str());
|
||||
|
||||
self->startNewTextBlock(centeredBlockStyle);
|
||||
self->italicUntilDepth = min(self->italicUntilDepth, self->depth);
|
||||
@@ -386,7 +386,7 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
|
||||
// memory.
|
||||
// Spotted when reading Intermezzo, there are some really long text blocks in there.
|
||||
if (self->currentTextBlock->size() > 750) {
|
||||
Serial.printf("[%lu] [EHP] Text block too long, splitting into multiple pages\n", millis());
|
||||
LOG_DBG("EHP", "Text block too long, splitting into multiple pages");
|
||||
self->currentTextBlock->layoutAndExtractLines(
|
||||
self->renderer, self->fontId, self->viewportWidth,
|
||||
[self](const std::shared_ptr<TextBlock>& textBlock) { self->addLineToPage(textBlock); }, false);
|
||||
@@ -477,7 +477,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
int done;
|
||||
|
||||
if (!parser) {
|
||||
Serial.printf("[%lu] [EHP] Couldn't allocate memory for parser\n", millis());
|
||||
LOG_ERR("EHP", "Couldn't allocate memory for parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -499,7 +499,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
do {
|
||||
void* const buf = XML_GetBuffer(parser, 1024);
|
||||
if (!buf) {
|
||||
Serial.printf("[%lu] [EHP] Couldn't allocate memory for buffer\n", millis());
|
||||
LOG_ERR("EHP", "Couldn't allocate memory for buffer");
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -511,7 +511,7 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
const size_t len = file.read(buf, 1024);
|
||||
|
||||
if (len == 0 && file.available() > 0) {
|
||||
Serial.printf("[%lu] [EHP] File read error\n", millis());
|
||||
LOG_ERR("EHP", "File read error");
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -523,8 +523,8 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
||||
done = file.available() == 0;
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(len), done) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(), XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
LOG_ERR("EHP", "Parse error at line %lu:\n%s", XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -568,7 +568,7 @@ void ChapterHtmlSlimParser::addLineToPage(std::shared_ptr<TextBlock> line) {
|
||||
|
||||
void ChapterHtmlSlimParser::makePages() {
|
||||
if (!currentTextBlock) {
|
||||
Serial.printf("[%lu] [EHP] !! No text block to make pages for !!\n", millis());
|
||||
LOG_ERR("EHP", "!! No text block to make pages for !!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
#include "ContainerParser.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
bool ContainerParser::setup() {
|
||||
parser = XML_ParserCreate(nullptr);
|
||||
if (!parser) {
|
||||
Serial.printf("[%lu] [CTR] Couldn't allocate memory for parser\n", millis());
|
||||
LOG_ERR("CTR", "Couldn't allocate memory for parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ size_t ContainerParser::write(const uint8_t* buffer, const size_t size) {
|
||||
while (remainingInBuffer > 0) {
|
||||
void* const buf = XML_GetBuffer(parser, 1024);
|
||||
if (!buf) {
|
||||
Serial.printf("[%lu] [CTR] Couldn't allocate buffer\n", millis());
|
||||
LOG_DBG("CTR", "Couldn't allocate buffer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ size_t ContainerParser::write(const uint8_t* buffer, const size_t size) {
|
||||
memcpy(buf, currentBufferPos, toRead);
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [CTR] Parse error: %s\n", millis(), XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
LOG_ERR("CTR", "Parse error: %s", XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "ContentOpfParser.h"
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
#include "../BookMetadataCache.h"
|
||||
@@ -15,7 +15,7 @@ constexpr char itemCacheFile[] = "/.items.bin";
|
||||
bool ContentOpfParser::setup() {
|
||||
parser = XML_ParserCreate(nullptr);
|
||||
if (!parser) {
|
||||
Serial.printf("[%lu] [COF] Couldn't allocate memory for parser\n", millis());
|
||||
LOG_DBG("COF", "Couldn't allocate memory for parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ size_t ContentOpfParser::write(const uint8_t* buffer, const size_t size) {
|
||||
void* const buf = XML_GetBuffer(parser, 1024);
|
||||
|
||||
if (!buf) {
|
||||
Serial.printf("[%lu] [COF] Couldn't allocate memory for buffer\n", millis());
|
||||
LOG_ERR("COF", "Couldn't allocate memory for buffer");
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -69,8 +69,8 @@ size_t ContentOpfParser::write(const uint8_t* buffer, const size_t size) {
|
||||
memcpy(buf, currentBufferPos, toRead);
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [COF] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
LOG_DBG("COF", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -119,9 +119,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)) {
|
||||
self->state = IN_MANIFEST;
|
||||
if (!Storage.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
||||
Serial.printf(
|
||||
"[%lu] [COF] Couldn't open temp items file for writing. This is probably going to be a fatal error.\n",
|
||||
millis());
|
||||
LOG_ERR("COF", "Couldn't open temp items file for writing. This is probably going to be a fatal error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -129,9 +127,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)) {
|
||||
self->state = IN_SPINE;
|
||||
if (!Storage.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
||||
Serial.printf(
|
||||
"[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n",
|
||||
millis());
|
||||
LOG_ERR("COF", "Couldn't open temp items file for reading. This is probably going to be a fatal error.");
|
||||
}
|
||||
|
||||
// Sort item index for binary search if we have enough items
|
||||
@@ -140,7 +136,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
||||
return a.idHash < b.idHash || (a.idHash == b.idHash && a.idLen < b.idLen);
|
||||
});
|
||||
self->useItemIndex = true;
|
||||
Serial.printf("[%lu] [COF] Using fast index for %zu manifest items\n", millis(), self->itemIndex.size());
|
||||
LOG_DBG("COF", "Using fast index for %zu manifest items", self->itemIndex.size());
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -148,11 +144,9 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
||||
if (self->state == IN_PACKAGE && (strcmp(name, "guide") == 0 || strcmp(name, "opf:guide") == 0)) {
|
||||
self->state = IN_GUIDE;
|
||||
// TODO Remove print
|
||||
Serial.printf("[%lu] [COF] Entering guide state.\n", millis());
|
||||
LOG_DBG("COF", "Entering guide state.");
|
||||
if (!Storage.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) {
|
||||
Serial.printf(
|
||||
"[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n",
|
||||
millis());
|
||||
LOG_ERR("COF", "Couldn't open temp items file for reading. This is probably going to be a fatal error.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -214,8 +208,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
||||
if (self->tocNcxPath.empty()) {
|
||||
self->tocNcxPath = href;
|
||||
} else {
|
||||
Serial.printf("[%lu] [COF] Warning: Multiple NCX files found in manifest. Ignoring duplicate: %s\n", millis(),
|
||||
href.c_str());
|
||||
LOG_DBG("COF", "Warning: Multiple NCX files found in manifest. Ignoring duplicate: %s", href.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +222,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
||||
// Properties is space-separated, check if "nav" is present as a word
|
||||
if (properties == "nav" || properties.find("nav ") == 0 || properties.find(" nav") != std::string::npos) {
|
||||
self->tocNavPath = href;
|
||||
Serial.printf("[%lu] [COF] Found EPUB 3 nav document: %s\n", millis(), href.c_str());
|
||||
LOG_DBG("COF", "Found EPUB 3 nav document: %s", href.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +303,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
||||
if (type == "text" || type == "start") {
|
||||
continue;
|
||||
} else {
|
||||
Serial.printf("[%lu] [COF] Skipping non-text reference in guide: %s\n", millis(), type.c_str());
|
||||
LOG_DBG("COF", "Skipping non-text reference in guide: %s", type.c_str());
|
||||
break;
|
||||
}
|
||||
} else if (strcmp(atts[i], "href") == 0) {
|
||||
@@ -318,7 +311,7 @@ void XMLCALL ContentOpfParser::startElement(void* userData, const XML_Char* name
|
||||
}
|
||||
}
|
||||
if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) {
|
||||
Serial.printf("[%lu] [COF] Found %s reference in guide: %s.\n", millis(), type.c_str(), textHref.c_str());
|
||||
LOG_DBG("COF", "Found %s reference in guide: %s.", type.c_str(), textHref.c_str());
|
||||
self->textReferenceHref = textHref;
|
||||
}
|
||||
return;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "TocNavParser.h"
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include "../BookMetadataCache.h"
|
||||
|
||||
bool TocNavParser::setup() {
|
||||
parser = XML_ParserCreate(nullptr);
|
||||
if (!parser) {
|
||||
Serial.printf("[%lu] [NAV] Couldn't allocate memory for parser\n", millis());
|
||||
LOG_DBG("NAV", "Couldn't allocate memory for parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ size_t TocNavParser::write(const uint8_t* buffer, const size_t size) {
|
||||
while (remainingInBuffer > 0) {
|
||||
void* const buf = XML_GetBuffer(parser, 1024);
|
||||
if (!buf) {
|
||||
Serial.printf("[%lu] [NAV] Couldn't allocate memory for buffer\n", millis());
|
||||
LOG_DBG("NAV", "Couldn't allocate memory for buffer");
|
||||
XML_StopParser(parser, XML_FALSE);
|
||||
XML_SetElementHandler(parser, nullptr, nullptr);
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -52,8 +52,8 @@ size_t TocNavParser::write(const uint8_t* buffer, const size_t size) {
|
||||
memcpy(buf, currentBufferPos, toRead);
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [NAV] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
LOG_DBG("NAV", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
XML_StopParser(parser, XML_FALSE);
|
||||
XML_SetElementHandler(parser, nullptr, nullptr);
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -88,7 +88,7 @@ void XMLCALL TocNavParser::startElement(void* userData, const XML_Char* name, co
|
||||
for (int i = 0; atts[i]; i += 2) {
|
||||
if ((strcmp(atts[i], "epub:type") == 0 || strcmp(atts[i], "type") == 0) && strcmp(atts[i + 1], "toc") == 0) {
|
||||
self->state = IN_NAV_TOC;
|
||||
Serial.printf("[%lu] [NAV] Found nav toc element\n", millis());
|
||||
LOG_DBG("NAV", "Found nav toc element");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -179,7 +179,7 @@ void XMLCALL TocNavParser::endElement(void* userData, const XML_Char* name) {
|
||||
|
||||
if (strcmp(name, "nav") == 0 && self->state >= IN_NAV_TOC) {
|
||||
self->state = IN_BODY;
|
||||
Serial.printf("[%lu] [NAV] Finished parsing nav toc\n", millis());
|
||||
LOG_DBG("NAV", "Finished parsing nav toc");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "TocNcxParser.h"
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include "../BookMetadataCache.h"
|
||||
|
||||
bool TocNcxParser::setup() {
|
||||
parser = XML_ParserCreate(nullptr);
|
||||
if (!parser) {
|
||||
Serial.printf("[%lu] [TOC] Couldn't allocate memory for parser\n", millis());
|
||||
LOG_DBG("TOC", "Couldn't allocate memory for parser");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ size_t TocNcxParser::write(const uint8_t* buffer, const size_t size) {
|
||||
while (remainingInBuffer > 0) {
|
||||
void* const buf = XML_GetBuffer(parser, 1024);
|
||||
if (!buf) {
|
||||
Serial.printf("[%lu] [TOC] Couldn't allocate memory for buffer\n", millis());
|
||||
LOG_DBG("TOC", "Couldn't allocate memory for buffer");
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
@@ -52,8 +52,8 @@ size_t TocNcxParser::write(const uint8_t* buffer, const size_t size) {
|
||||
memcpy(buf, currentBufferPos, toRead);
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) {
|
||||
Serial.printf("[%lu] [TOC] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
LOG_DBG("TOC", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||
XML_SetCharacterDataHandler(parser, nullptr);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "GfxRenderer.h"
|
||||
|
||||
#include <Logging.h>
|
||||
#include <Utf8.h>
|
||||
|
||||
void GfxRenderer::begin() {
|
||||
frameBuffer = display.getFrameBuffer();
|
||||
if (!frameBuffer) {
|
||||
Serial.printf("[%lu] [GFX] !! No framebuffer\n", millis());
|
||||
LOG_ERR("GFX", "!! No framebuffer");
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
@@ -57,7 +58,7 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const {
|
||||
|
||||
// Bounds checking against physical panel dimensions
|
||||
if (phyX < 0 || phyX >= HalDisplay::DISPLAY_WIDTH || phyY < 0 || phyY >= HalDisplay::DISPLAY_HEIGHT) {
|
||||
Serial.printf("[%lu] [GFX] !! Outside range (%d, %d) -> (%d, %d)\n", millis(), x, y, phyX, phyY);
|
||||
LOG_ERR("GFX", "!! Outside range (%d, %d) -> (%d, %d)", x, y, phyX, phyY);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const {
|
||||
|
||||
int GfxRenderer::getTextWidth(const int fontId, const char* text, const EpdFontFamily::Style style) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -100,7 +101,7 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
||||
}
|
||||
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return;
|
||||
}
|
||||
const auto font = fontMap.at(fontId);
|
||||
@@ -133,7 +134,7 @@ void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, const bool state) con
|
||||
}
|
||||
} else {
|
||||
// TODO: Implement
|
||||
Serial.printf("[%lu] [GFX] Line drawing not supported\n", millis());
|
||||
LOG_ERR("GFX", "Line drawing not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,8 +420,8 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
|
||||
bool isScaled = false;
|
||||
int cropPixX = std::floor(bitmap.getWidth() * cropX / 2.0f);
|
||||
int cropPixY = std::floor(bitmap.getHeight() * cropY / 2.0f);
|
||||
Serial.printf("[%lu] [GFX] Cropping %dx%d by %dx%d pix, is %s\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
|
||||
cropPixX, cropPixY, bitmap.isTopDown() ? "top-down" : "bottom-up");
|
||||
LOG_DBG("GFX", "Cropping %dx%d by %dx%d pix, is %s", bitmap.getWidth(), bitmap.getHeight(), cropPixX, cropPixY,
|
||||
bitmap.isTopDown() ? "top-down" : "bottom-up");
|
||||
|
||||
if (maxWidth > 0 && (1.0f - cropX) * bitmap.getWidth() > maxWidth) {
|
||||
scale = static_cast<float>(maxWidth) / static_cast<float>((1.0f - cropX) * bitmap.getWidth());
|
||||
@@ -430,7 +431,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
|
||||
scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>((1.0f - cropY) * bitmap.getHeight()));
|
||||
isScaled = true;
|
||||
}
|
||||
Serial.printf("[%lu] [GFX] Scaling by %f - %s\n", millis(), scale, isScaled ? "scaled" : "not scaled");
|
||||
LOG_DBG("GFX", "Scaling by %f - %s", scale, isScaled ? "scaled" : "not scaled");
|
||||
|
||||
// Calculate output row size (2 bits per pixel, packed into bytes)
|
||||
// IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels wide
|
||||
@@ -439,7 +440,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
|
||||
auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes()));
|
||||
|
||||
if (!outputRow || !rowBytes) {
|
||||
Serial.printf("[%lu] [GFX] !! Failed to allocate BMP row buffers\n", millis());
|
||||
LOG_ERR("GFX", "!! Failed to allocate BMP row buffers");
|
||||
free(outputRow);
|
||||
free(rowBytes);
|
||||
return;
|
||||
@@ -458,7 +459,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
|
||||
}
|
||||
|
||||
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
|
||||
Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), bmpY);
|
||||
LOG_ERR("GFX", "Failed to read row %d from bitmap", bmpY);
|
||||
free(outputRow);
|
||||
free(rowBytes);
|
||||
return;
|
||||
@@ -521,7 +522,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y,
|
||||
auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes()));
|
||||
|
||||
if (!outputRow || !rowBytes) {
|
||||
Serial.printf("[%lu] [GFX] !! Failed to allocate 1-bit BMP row buffers\n", millis());
|
||||
LOG_ERR("GFX", "!! Failed to allocate 1-bit BMP row buffers");
|
||||
free(outputRow);
|
||||
free(rowBytes);
|
||||
return;
|
||||
@@ -530,7 +531,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y,
|
||||
for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) {
|
||||
// Read rows sequentially using readNextRow
|
||||
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
|
||||
Serial.printf("[%lu] [GFX] Failed to read row %d from 1-bit bitmap\n", millis(), bmpY);
|
||||
LOG_ERR("GFX", "Failed to read row %d from 1-bit bitmap", bmpY);
|
||||
free(outputRow);
|
||||
free(rowBytes);
|
||||
return;
|
||||
@@ -588,7 +589,7 @@ void GfxRenderer::fillPolygon(const int* xPoints, const int* yPoints, int numPoi
|
||||
// Allocate node buffer for scanline algorithm
|
||||
auto* nodeX = static_cast<int*>(malloc(numPoints * sizeof(int)));
|
||||
if (!nodeX) {
|
||||
Serial.printf("[%lu] [GFX] !! Failed to allocate polygon node buffer\n", millis());
|
||||
LOG_ERR("GFX", "!! Failed to allocate polygon node buffer");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -655,7 +656,7 @@ void GfxRenderer::invertScreen() const {
|
||||
|
||||
void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const {
|
||||
auto elapsed = millis() - start_ms;
|
||||
Serial.printf("[%lu] [GFX] Time = %lu ms from clearScreen to displayBuffer\n", millis(), elapsed);
|
||||
LOG_DBG("GFX", "Time = %lu ms from clearScreen to displayBuffer", elapsed);
|
||||
display.displayBuffer(refreshMode, fadingFix);
|
||||
}
|
||||
|
||||
@@ -709,7 +710,7 @@ int GfxRenderer::getScreenHeight() const {
|
||||
|
||||
int GfxRenderer::getSpaceWidth(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -718,7 +719,7 @@ int GfxRenderer::getSpaceWidth(const int fontId) const {
|
||||
|
||||
int GfxRenderer::getTextAdvanceX(const int fontId, const char* text) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -732,7 +733,7 @@ int GfxRenderer::getTextAdvanceX(const int fontId, const char* text) const {
|
||||
|
||||
int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -741,7 +742,7 @@ int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
||||
|
||||
int GfxRenderer::getLineHeight(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -750,7 +751,7 @@ int GfxRenderer::getLineHeight(const int fontId) const {
|
||||
|
||||
int GfxRenderer::getTextHeight(const int fontId) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return 0;
|
||||
}
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
|
||||
@@ -764,7 +765,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y
|
||||
}
|
||||
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
LOG_ERR("GFX", "Font %d not found", fontId);
|
||||
return;
|
||||
}
|
||||
const auto font = fontMap.at(fontId);
|
||||
@@ -872,8 +873,7 @@ bool GfxRenderer::storeBwBuffer() {
|
||||
for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) {
|
||||
// Check if any chunks are already allocated
|
||||
if (bwBufferChunks[i]) {
|
||||
Serial.printf("[%lu] [GFX] !! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk\n",
|
||||
millis(), i);
|
||||
LOG_ERR("GFX", "!! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk", i);
|
||||
free(bwBufferChunks[i]);
|
||||
bwBufferChunks[i] = nullptr;
|
||||
}
|
||||
@@ -882,8 +882,7 @@ bool GfxRenderer::storeBwBuffer() {
|
||||
bwBufferChunks[i] = static_cast<uint8_t*>(malloc(BW_BUFFER_CHUNK_SIZE));
|
||||
|
||||
if (!bwBufferChunks[i]) {
|
||||
Serial.printf("[%lu] [GFX] !! Failed to allocate BW buffer chunk %zu (%zu bytes)\n", millis(), i,
|
||||
BW_BUFFER_CHUNK_SIZE);
|
||||
LOG_ERR("GFX", "!! Failed to allocate BW buffer chunk %zu (%zu bytes)", i, BW_BUFFER_CHUNK_SIZE);
|
||||
// Free previously allocated chunks
|
||||
freeBwBufferChunks();
|
||||
return false;
|
||||
@@ -892,8 +891,7 @@ bool GfxRenderer::storeBwBuffer() {
|
||||
memcpy(bwBufferChunks[i], frameBuffer + offset, BW_BUFFER_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [GFX] Stored BW buffer in %zu chunks (%zu bytes each)\n", millis(), BW_BUFFER_NUM_CHUNKS,
|
||||
BW_BUFFER_CHUNK_SIZE);
|
||||
LOG_DBG("GFX", "Stored BW buffer in %zu chunks (%zu bytes each)", BW_BUFFER_NUM_CHUNKS, BW_BUFFER_CHUNK_SIZE);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -920,7 +918,7 @@ void GfxRenderer::restoreBwBuffer() {
|
||||
for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) {
|
||||
// Check if chunk is missing
|
||||
if (!bwBufferChunks[i]) {
|
||||
Serial.printf("[%lu] [GFX] !! BW buffer chunks not stored - this is likely a bug\n", millis());
|
||||
LOG_ERR("GFX", "!! BW buffer chunks not stored - this is likely a bug");
|
||||
freeBwBufferChunks();
|
||||
return;
|
||||
}
|
||||
@@ -932,7 +930,7 @@ void GfxRenderer::restoreBwBuffer() {
|
||||
display.cleanupGrayscaleBuffers(frameBuffer);
|
||||
|
||||
freeBwBufferChunks();
|
||||
Serial.printf("[%lu] [GFX] Restored and freed BW buffer chunks\n", millis());
|
||||
LOG_DBG("GFX", "Restored and freed BW buffer chunks");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -954,7 +952,7 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp,
|
||||
|
||||
// no glyph?
|
||||
if (!glyph) {
|
||||
Serial.printf("[%lu] [GFX] No glyph for codepoint %d\n", millis(), cp);
|
||||
LOG_ERR("GFX", "No glyph for codepoint %d", cp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "JpegToBmpConverter.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <picojpeg.h>
|
||||
|
||||
#include <cstdio>
|
||||
@@ -201,8 +201,7 @@ unsigned char JpegToBmpConverter::jpegReadCallback(unsigned char* pBuf, const un
|
||||
// Internal implementation with configurable target size and bit depth
|
||||
bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight,
|
||||
bool oneBit, bool crop) {
|
||||
Serial.printf("[%lu] [JPG] Converting JPEG to %s BMP (target: %dx%d)\n", millis(), oneBit ? "1-bit" : "2-bit",
|
||||
targetWidth, targetHeight);
|
||||
LOG_DBG("JPG", "Converting JPEG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight);
|
||||
|
||||
// Setup context for picojpeg callback
|
||||
JpegReadContext context = {.file = jpegFile, .bufferPos = 0, .bufferFilled = 0};
|
||||
@@ -211,12 +210,12 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
pjpeg_image_info_t imageInfo;
|
||||
const unsigned char status = pjpeg_decode_init(&imageInfo, jpegReadCallback, &context, 0);
|
||||
if (status != 0) {
|
||||
Serial.printf("[%lu] [JPG] JPEG decode init failed with error code: %d\n", millis(), status);
|
||||
LOG_ERR("JPG", "JPEG decode init failed with error code: %d", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [JPG] JPEG dimensions: %dx%d, components: %d, MCUs: %dx%d\n", millis(), imageInfo.m_width,
|
||||
imageInfo.m_height, imageInfo.m_comps, imageInfo.m_MCUSPerRow, imageInfo.m_MCUSPerCol);
|
||||
LOG_DBG("JPG", "JPEG dimensions: %dx%d, components: %d, MCUs: %dx%d", imageInfo.m_width, imageInfo.m_height,
|
||||
imageInfo.m_comps, imageInfo.m_MCUSPerRow, imageInfo.m_MCUSPerCol);
|
||||
|
||||
// Safety limits to prevent memory issues on ESP32
|
||||
constexpr int MAX_IMAGE_WIDTH = 2048;
|
||||
@@ -224,8 +223,8 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
constexpr int MAX_MCU_ROW_BYTES = 65536;
|
||||
|
||||
if (imageInfo.m_width > MAX_IMAGE_WIDTH || imageInfo.m_height > MAX_IMAGE_HEIGHT) {
|
||||
Serial.printf("[%lu] [JPG] Image too large (%dx%d), max supported: %dx%d\n", millis(), imageInfo.m_width,
|
||||
imageInfo.m_height, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT);
|
||||
LOG_DBG("JPG", "Image too large (%dx%d), max supported: %dx%d", imageInfo.m_width, imageInfo.m_height,
|
||||
MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -262,8 +261,8 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
scaleY_fp = (static_cast<uint32_t>(imageInfo.m_height) << 16) / outHeight;
|
||||
needsScaling = true;
|
||||
|
||||
Serial.printf("[%lu] [JPG] Pre-scaling %dx%d -> %dx%d (fit to %dx%d)\n", millis(), imageInfo.m_width,
|
||||
imageInfo.m_height, outWidth, outHeight, targetWidth, targetHeight);
|
||||
LOG_DBG("JPG", "Pre-scaling %dx%d -> %dx%d (fit to %dx%d)", imageInfo.m_width, imageInfo.m_height, outWidth,
|
||||
outHeight, targetWidth, targetHeight);
|
||||
}
|
||||
|
||||
// Write BMP header with output dimensions
|
||||
@@ -282,7 +281,7 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
// Allocate row buffer
|
||||
auto* rowBuffer = static_cast<uint8_t*>(malloc(bytesPerRow));
|
||||
if (!rowBuffer) {
|
||||
Serial.printf("[%lu] [JPG] Failed to allocate row buffer\n", millis());
|
||||
LOG_ERR("JPG", "Failed to allocate row buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -293,15 +292,14 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
|
||||
// Validate MCU row buffer size before allocation
|
||||
if (mcuRowPixels > MAX_MCU_ROW_BYTES) {
|
||||
Serial.printf("[%lu] [JPG] MCU row buffer too large (%d bytes), max: %d\n", millis(), mcuRowPixels,
|
||||
MAX_MCU_ROW_BYTES);
|
||||
LOG_DBG("JPG", "MCU row buffer too large (%d bytes), max: %d", mcuRowPixels, MAX_MCU_ROW_BYTES);
|
||||
free(rowBuffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* mcuRowBuffer = static_cast<uint8_t*>(malloc(mcuRowPixels));
|
||||
if (!mcuRowBuffer) {
|
||||
Serial.printf("[%lu] [JPG] Failed to allocate MCU row buffer (%d bytes)\n", millis(), mcuRowPixels);
|
||||
LOG_ERR("JPG", "Failed to allocate MCU row buffer (%d bytes)", mcuRowPixels);
|
||||
free(rowBuffer);
|
||||
return false;
|
||||
}
|
||||
@@ -349,10 +347,9 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
const unsigned char mcuStatus = pjpeg_decode_mcu();
|
||||
if (mcuStatus != 0) {
|
||||
if (mcuStatus == PJPG_NO_MORE_BLOCKS) {
|
||||
Serial.printf("[%lu] [JPG] Unexpected end of blocks at MCU (%d, %d)\n", millis(), mcuX, mcuY);
|
||||
LOG_ERR("JPG", "Unexpected end of blocks at MCU (%d, %d)", mcuX, mcuY);
|
||||
} else {
|
||||
Serial.printf("[%lu] [JPG] JPEG decode MCU failed at (%d, %d) with error code: %d\n", millis(), mcuX, mcuY,
|
||||
mcuStatus);
|
||||
LOG_ERR("JPG", "JPEG decode MCU failed at (%d, %d) with error code: %d", mcuX, mcuY, mcuStatus);
|
||||
}
|
||||
free(mcuRowBuffer);
|
||||
free(rowBuffer);
|
||||
@@ -549,7 +546,7 @@ bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bm
|
||||
free(mcuRowBuffer);
|
||||
free(rowBuffer);
|
||||
|
||||
Serial.printf("[%lu] [JPG] Successfully converted JPEG to BMP\n", millis());
|
||||
LOG_DBG("JPG", "Successfully converted JPEG to BMP");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "KOReaderCredentialStore.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <MD5Builder.h>
|
||||
#include <Serialization.h>
|
||||
|
||||
@@ -44,7 +44,7 @@ bool KOReaderCredentialStore::saveToFile() const {
|
||||
|
||||
// Write username (plaintext - not particularly sensitive)
|
||||
serialization::writeString(file, username);
|
||||
Serial.printf("[%lu] [KRS] Saving username: %s\n", millis(), username.c_str());
|
||||
LOG_DBG("KRS", "Saving username: %s", username.c_str());
|
||||
|
||||
// Write password (obfuscated)
|
||||
std::string obfuscatedPwd = password;
|
||||
@@ -58,14 +58,14 @@ bool KOReaderCredentialStore::saveToFile() const {
|
||||
serialization::writePod(file, static_cast<uint8_t>(matchMethod));
|
||||
|
||||
file.close();
|
||||
Serial.printf("[%lu] [KRS] Saved KOReader credentials to file\n", millis());
|
||||
LOG_DBG("KRS", "Saved KOReader credentials to file");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KOReaderCredentialStore::loadFromFile() {
|
||||
FsFile file;
|
||||
if (!Storage.openFileForRead("KRS", KOREADER_FILE, file)) {
|
||||
Serial.printf("[%lu] [KRS] No credentials file found\n", millis());
|
||||
LOG_DBG("KRS", "No credentials file found");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ bool KOReaderCredentialStore::loadFromFile() {
|
||||
uint8_t version;
|
||||
serialization::readPod(file, version);
|
||||
if (version != KOREADER_FILE_VERSION) {
|
||||
Serial.printf("[%lu] [KRS] Unknown file version: %u\n", millis(), version);
|
||||
LOG_DBG("KRS", "Unknown file version: %u", version);
|
||||
file.close();
|
||||
return false;
|
||||
}
|
||||
@@ -110,14 +110,14 @@ bool KOReaderCredentialStore::loadFromFile() {
|
||||
}
|
||||
|
||||
file.close();
|
||||
Serial.printf("[%lu] [KRS] Loaded KOReader credentials for user: %s\n", millis(), username.c_str());
|
||||
LOG_DBG("KRS", "Loaded KOReader credentials for user: %s", username.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void KOReaderCredentialStore::setCredentials(const std::string& user, const std::string& pass) {
|
||||
username = user;
|
||||
password = pass;
|
||||
Serial.printf("[%lu] [KRS] Set credentials for user: %s\n", millis(), user.c_str());
|
||||
LOG_DBG("KRS", "Set credentials for user: %s", user.c_str());
|
||||
}
|
||||
|
||||
std::string KOReaderCredentialStore::getMd5Password() const {
|
||||
@@ -140,12 +140,12 @@ void KOReaderCredentialStore::clearCredentials() {
|
||||
username.clear();
|
||||
password.clear();
|
||||
saveToFile();
|
||||
Serial.printf("[%lu] [KRS] Cleared KOReader credentials\n", millis());
|
||||
LOG_DBG("KRS", "Cleared KOReader credentials");
|
||||
}
|
||||
|
||||
void KOReaderCredentialStore::setServerUrl(const std::string& url) {
|
||||
serverUrl = url;
|
||||
Serial.printf("[%lu] [KRS] Set server URL: %s\n", millis(), url.empty() ? "(default)" : url.c_str());
|
||||
LOG_DBG("KRS", "Set server URL: %s", url.empty() ? "(default)" : url.c_str());
|
||||
}
|
||||
|
||||
std::string KOReaderCredentialStore::getBaseUrl() const {
|
||||
@@ -163,6 +163,5 @@ std::string KOReaderCredentialStore::getBaseUrl() const {
|
||||
|
||||
void KOReaderCredentialStore::setMatchMethod(DocumentMatchMethod method) {
|
||||
matchMethod = method;
|
||||
Serial.printf("[%lu] [KRS] Set match method: %s\n", millis(),
|
||||
method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary");
|
||||
LOG_DBG("KRS", "Set match method: %s", method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary");
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "KOReaderDocumentId.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <MD5Builder.h>
|
||||
|
||||
namespace {
|
||||
@@ -27,7 +27,7 @@ std::string KOReaderDocumentId::calculateFromFilename(const std::string& filePat
|
||||
md5.calculate();
|
||||
|
||||
std::string result = md5.toString().c_str();
|
||||
Serial.printf("[%lu] [KODoc] Filename hash: %s (from '%s')\n", millis(), result.c_str(), filename.c_str());
|
||||
LOG_DBG("KODoc", "Filename hash: %s (from '%s')", result.c_str(), filename.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -44,12 +44,12 @@ size_t KOReaderDocumentId::getOffset(int i) {
|
||||
std::string KOReaderDocumentId::calculate(const std::string& filePath) {
|
||||
FsFile file;
|
||||
if (!Storage.openFileForRead("KODoc", filePath, file)) {
|
||||
Serial.printf("[%lu] [KODoc] Failed to open file: %s\n", millis(), filePath.c_str());
|
||||
LOG_DBG("KODoc", "Failed to open file: %s", filePath.c_str());
|
||||
return "";
|
||||
}
|
||||
|
||||
const size_t fileSize = file.fileSize();
|
||||
Serial.printf("[%lu] [KODoc] Calculating hash for file: %s (size: %zu)\n", millis(), filePath.c_str(), fileSize);
|
||||
LOG_DBG("KODoc", "Calculating hash for file: %s (size: %zu)", filePath.c_str(), fileSize);
|
||||
|
||||
// Initialize MD5 builder
|
||||
MD5Builder md5;
|
||||
@@ -70,7 +70,7 @@ std::string KOReaderDocumentId::calculate(const std::string& filePath) {
|
||||
|
||||
// Seek to offset
|
||||
if (!file.seekSet(offset)) {
|
||||
Serial.printf("[%lu] [KODoc] Failed to seek to offset %zu\n", millis(), offset);
|
||||
LOG_DBG("KODoc", "Failed to seek to offset %zu", offset);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ std::string KOReaderDocumentId::calculate(const std::string& filePath) {
|
||||
md5.calculate();
|
||||
std::string result = md5.toString().c_str();
|
||||
|
||||
Serial.printf("[%lu] [KODoc] Hash calculated: %s (from %zu bytes)\n", millis(), result.c_str(), totalBytesRead);
|
||||
LOG_DBG("KODoc", "Hash calculated: %s (from %zu bytes)", result.c_str(), totalBytesRead);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
|
||||
@@ -30,12 +30,12 @@ bool isHttpsUrl(const std::string& url) { return url.rfind("https://", 0) == 0;
|
||||
|
||||
KOReaderSyncClient::Error KOReaderSyncClient::authenticate() {
|
||||
if (!KOREADER_STORE.hasCredentials()) {
|
||||
Serial.printf("[%lu] [KOSync] No credentials configured\n", millis());
|
||||
LOG_DBG("KOSync", "No credentials configured");
|
||||
return NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
std::string url = KOREADER_STORE.getBaseUrl() + "/users/auth";
|
||||
Serial.printf("[%lu] [KOSync] Authenticating: %s\n", millis(), url.c_str());
|
||||
LOG_DBG("KOSync", "Authenticating: %s", url.c_str());
|
||||
|
||||
HTTPClient http;
|
||||
std::unique_ptr<WiFiClientSecure> secureClient;
|
||||
@@ -53,7 +53,7 @@ KOReaderSyncClient::Error KOReaderSyncClient::authenticate() {
|
||||
const int httpCode = http.GET();
|
||||
http.end();
|
||||
|
||||
Serial.printf("[%lu] [KOSync] Auth response: %d\n", millis(), httpCode);
|
||||
LOG_DBG("KOSync", "Auth response: %d", httpCode);
|
||||
|
||||
if (httpCode == 200) {
|
||||
return OK;
|
||||
@@ -68,12 +68,12 @@ KOReaderSyncClient::Error KOReaderSyncClient::authenticate() {
|
||||
KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& documentHash,
|
||||
KOReaderProgress& outProgress) {
|
||||
if (!KOREADER_STORE.hasCredentials()) {
|
||||
Serial.printf("[%lu] [KOSync] No credentials configured\n", millis());
|
||||
LOG_DBG("KOSync", "No credentials configured");
|
||||
return NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress/" + documentHash;
|
||||
Serial.printf("[%lu] [KOSync] Getting progress: %s\n", millis(), url.c_str());
|
||||
LOG_DBG("KOSync", "Getting progress: %s", url.c_str());
|
||||
|
||||
HTTPClient http;
|
||||
std::unique_ptr<WiFiClientSecure> secureClient;
|
||||
@@ -99,7 +99,7 @@ KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& doc
|
||||
const DeserializationError error = deserializeJson(doc, responseBody);
|
||||
|
||||
if (error) {
|
||||
Serial.printf("[%lu] [KOSync] JSON parse failed: %s\n", millis(), error.c_str());
|
||||
LOG_ERR("KOSync", "JSON parse failed: %s", error.c_str());
|
||||
return JSON_ERROR;
|
||||
}
|
||||
|
||||
@@ -110,14 +110,13 @@ KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& doc
|
||||
outProgress.deviceId = doc["device_id"].as<std::string>();
|
||||
outProgress.timestamp = doc["timestamp"].as<int64_t>();
|
||||
|
||||
Serial.printf("[%lu] [KOSync] Got progress: %.2f%% at %s\n", millis(), outProgress.percentage * 100,
|
||||
outProgress.progress.c_str());
|
||||
LOG_DBG("KOSync", "Got progress: %.2f%% at %s", outProgress.percentage * 100, outProgress.progress.c_str());
|
||||
return OK;
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
Serial.printf("[%lu] [KOSync] Get progress response: %d\n", millis(), httpCode);
|
||||
LOG_DBG("KOSync", "Get progress response: %d", httpCode);
|
||||
|
||||
if (httpCode == 401) {
|
||||
return AUTH_FAILED;
|
||||
@@ -131,12 +130,12 @@ KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& doc
|
||||
|
||||
KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgress& progress) {
|
||||
if (!KOREADER_STORE.hasCredentials()) {
|
||||
Serial.printf("[%lu] [KOSync] No credentials configured\n", millis());
|
||||
LOG_DBG("KOSync", "No credentials configured");
|
||||
return NO_CREDENTIALS;
|
||||
}
|
||||
|
||||
std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress";
|
||||
Serial.printf("[%lu] [KOSync] Updating progress: %s\n", millis(), url.c_str());
|
||||
LOG_DBG("KOSync", "Updating progress: %s", url.c_str());
|
||||
|
||||
HTTPClient http;
|
||||
std::unique_ptr<WiFiClientSecure> secureClient;
|
||||
@@ -163,12 +162,12 @@ KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgr
|
||||
std::string body;
|
||||
serializeJson(doc, body);
|
||||
|
||||
Serial.printf("[%lu] [KOSync] Request body: %s\n", millis(), body.c_str());
|
||||
LOG_DBG("KOSync", "Request body: %s", body.c_str());
|
||||
|
||||
const int httpCode = http.PUT(body.c_str());
|
||||
http.end();
|
||||
|
||||
Serial.printf("[%lu] [KOSync] Update progress response: %d\n", millis(), httpCode);
|
||||
LOG_DBG("KOSync", "Update progress response: %d", httpCode);
|
||||
|
||||
if (httpCode == 200 || httpCode == 202) {
|
||||
return OK;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "ProgressMapper.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@@ -23,8 +23,8 @@ KOReaderPosition ProgressMapper::toKOReader(const std::shared_ptr<Epub>& epub, c
|
||||
const int tocIndex = epub->getTocIndexForSpineIndex(pos.spineIndex);
|
||||
const std::string chapterName = (tocIndex >= 0) ? epub->getTocItem(tocIndex).title : "unknown";
|
||||
|
||||
Serial.printf("[%lu] [ProgressMapper] CrossPoint -> KOReader: chapter='%s', page=%d/%d -> %.2f%% at %s\n", millis(),
|
||||
chapterName.c_str(), pos.pageNumber, pos.totalPages, result.percentage * 100, result.xpath.c_str());
|
||||
LOG_DBG("ProgressMapper", "CrossPoint -> KOReader: chapter='%s', page=%d/%d -> %.2f%% at %s", chapterName.c_str(),
|
||||
pos.pageNumber, pos.totalPages, result.percentage * 100, result.xpath.c_str());
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -76,8 +76,8 @@ CrossPointPosition ProgressMapper::toCrossPoint(const std::shared_ptr<Epub>& epu
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [ProgressMapper] KOReader -> CrossPoint: %.2f%% at %s -> spine=%d, page=%d\n", millis(),
|
||||
koPos.percentage * 100, koPos.xpath.c_str(), result.spineIndex, result.pageNumber);
|
||||
LOG_DBG("ProgressMapper", "KOReader -> CrossPoint: %.2f%% at %s -> spine=%d, page=%d", koPos.percentage * 100,
|
||||
koPos.xpath.c_str(), result.spineIndex, result.pageNumber);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
47
lib/Logging/Logging.cpp
Normal file
47
lib/Logging/Logging.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
#include "Logging.h"
|
||||
|
||||
// Since logging can take a large amount of flash, we want to make the format string as short as possible.
|
||||
// This logPrintf prepend the timestamp, level and origin to the user-provided message, so that the user only needs to
|
||||
// provide the format string for the message itself.
|
||||
void logPrintf(const char* level, const char* origin, const char* format, ...) {
|
||||
if (!logSerial) {
|
||||
return; // Serial not initialized, skip logging
|
||||
}
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
char buf[256];
|
||||
char* c = buf;
|
||||
// add the timestamp
|
||||
{
|
||||
unsigned long ms = millis();
|
||||
int len = snprintf(c, sizeof(buf), "[%lu] ", ms);
|
||||
if (len < 0) {
|
||||
return; // encoding error, skip logging
|
||||
}
|
||||
c += len;
|
||||
}
|
||||
// add the level
|
||||
{
|
||||
const char* p = level;
|
||||
size_t remaining = sizeof(buf) - (c - buf);
|
||||
while (*p && remaining > 1) {
|
||||
*c++ = *p++;
|
||||
remaining--;
|
||||
}
|
||||
if (remaining > 1) {
|
||||
*c++ = ' ';
|
||||
}
|
||||
}
|
||||
// add the origin
|
||||
{
|
||||
int len = snprintf(c, sizeof(buf) - (c - buf), "[%s] ", origin);
|
||||
if (len < 0) {
|
||||
return; // encoding error, skip logging
|
||||
}
|
||||
c += len;
|
||||
}
|
||||
// add the user message
|
||||
vsnprintf(c, sizeof(buf) - (c - buf), format, args);
|
||||
va_end(args);
|
||||
logSerial.print(buf);
|
||||
}
|
||||
71
lib/Logging/Logging.h
Normal file
71
lib/Logging/Logging.h
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
|
||||
/*
|
||||
Define ENABLE_SERIAL_LOG to enable logging
|
||||
Can be set in platformio.ini build_flags or as a compile definition
|
||||
|
||||
Define LOG_LEVEL to control log verbosity:
|
||||
0 = ERR only
|
||||
1 = ERR + INF
|
||||
2 = ERR + INF + DBG
|
||||
If not defined, defaults to 0
|
||||
|
||||
If you have a legitimate need for raw Serial access (e.g., binary data,
|
||||
special formatting), use the underlying logSerial object directly:
|
||||
logSerial.printf("Special case: %d\n", value);
|
||||
logSerial.write(binaryData, length);
|
||||
|
||||
The logSerial reference (defined below) points to the real Serial object and
|
||||
won't trigger deprecation warnings.
|
||||
*/
|
||||
|
||||
#ifndef LOG_LEVEL
|
||||
#define LOG_LEVEL 0
|
||||
#endif
|
||||
|
||||
static HWCDC& logSerial = Serial;
|
||||
|
||||
void logPrintf(const char* level, const char* origin, const char* format, ...);
|
||||
|
||||
#ifdef ENABLE_SERIAL_LOG
|
||||
#if LOG_LEVEL >= 0
|
||||
#define LOG_ERR(origin, format, ...) logPrintf("[ERR]", origin, format "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_ERR(origin, format, ...)
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL >= 1
|
||||
#define LOG_INF(origin, format, ...) logPrintf("[INF]", origin, format "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_INF(origin, format, ...)
|
||||
#endif
|
||||
|
||||
#if LOG_LEVEL >= 2
|
||||
#define LOG_DBG(origin, format, ...) logPrintf("[DBG]", origin, format "\n", ##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_DBG(origin, format, ...)
|
||||
#endif
|
||||
#else
|
||||
#define LOG_DBG(origin, format, ...)
|
||||
#define LOG_ERR(origin, format, ...)
|
||||
#define LOG_INF(origin, format, ...)
|
||||
#endif
|
||||
|
||||
class MySerialImpl : public Print {
|
||||
public:
|
||||
void begin(unsigned long baud) { logSerial.begin(baud); }
|
||||
|
||||
// Support boolean conversion for compatibility with code like:
|
||||
// if (Serial) or while (!Serial)
|
||||
operator bool() const { return logSerial; }
|
||||
|
||||
__attribute__((deprecated("Use LOG_* macro instead"))) size_t printf(const char* format, ...);
|
||||
size_t write(uint8_t b) override;
|
||||
size_t write(const uint8_t* buffer, size_t size) override;
|
||||
void flush() override;
|
||||
static MySerialImpl instance;
|
||||
};
|
||||
|
||||
#define Serial MySerialImpl::instance
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "OpdsParser.h"
|
||||
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -8,7 +8,7 @@ OpdsParser::OpdsParser() {
|
||||
parser = XML_ParserCreate(nullptr);
|
||||
if (!parser) {
|
||||
errorOccured = true;
|
||||
Serial.printf("[%lu] [OPDS] Couldn't allocate memory for parser\n", millis());
|
||||
LOG_DBG("OPDS", "Couldn't allocate memory for parser");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ size_t OpdsParser::write(const uint8_t* xmlData, const size_t length) {
|
||||
void* const buf = XML_GetBuffer(parser, chunkSize);
|
||||
if (!buf) {
|
||||
errorOccured = true;
|
||||
Serial.printf("[%lu] [OPDS] Couldn't allocate memory for buffer\n", millis());
|
||||
LOG_DBG("OPDS", "Couldn't allocate memory for buffer");
|
||||
XML_ParserFree(parser);
|
||||
parser = nullptr;
|
||||
return length;
|
||||
@@ -53,8 +53,8 @@ size_t OpdsParser::write(const uint8_t* xmlData, const size_t length) {
|
||||
|
||||
if (XML_ParseBuffer(parser, static_cast<int>(toRead), 0) == XML_STATUS_ERROR) {
|
||||
errorOccured = true;
|
||||
Serial.printf("[%lu] [OPDS] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
LOG_DBG("OPDS", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
XML_ParserFree(parser);
|
||||
parser = nullptr;
|
||||
return length;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <JpegToBmpConverter.h>
|
||||
#include <Logging.h>
|
||||
|
||||
Txt::Txt(std::string path, std::string cacheBasePath)
|
||||
: filepath(std::move(path)), cacheBasePath(std::move(cacheBasePath)) {
|
||||
@@ -16,13 +17,13 @@ bool Txt::load() {
|
||||
}
|
||||
|
||||
if (!Storage.exists(filepath.c_str())) {
|
||||
Serial.printf("[%lu] [TXT] File does not exist: %s\n", millis(), filepath.c_str());
|
||||
LOG_ERR("TXT", "File does not exist: %s", filepath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
FsFile file;
|
||||
if (!Storage.openFileForRead("TXT", filepath, file)) {
|
||||
Serial.printf("[%lu] [TXT] Failed to open file: %s\n", millis(), filepath.c_str());
|
||||
LOG_ERR("TXT", "Failed to open file: %s", filepath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -30,7 +31,7 @@ bool Txt::load() {
|
||||
file.close();
|
||||
|
||||
loaded = true;
|
||||
Serial.printf("[%lu] [TXT] Loaded TXT file: %s (%zu bytes)\n", millis(), filepath.c_str(), fileSize);
|
||||
LOG_DBG("TXT", "Loaded TXT file: %s (%zu bytes)", filepath.c_str(), fileSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -74,7 +75,7 @@ std::string Txt::findCoverImage() const {
|
||||
for (const auto& ext : extensions) {
|
||||
std::string coverPath = folder + "/" + baseName + ext;
|
||||
if (Storage.exists(coverPath.c_str())) {
|
||||
Serial.printf("[%lu] [TXT] Found matching cover image: %s\n", millis(), coverPath.c_str());
|
||||
LOG_DBG("TXT", "Found matching cover image: %s", coverPath.c_str());
|
||||
return coverPath;
|
||||
}
|
||||
}
|
||||
@@ -85,7 +86,7 @@ std::string Txt::findCoverImage() const {
|
||||
for (const auto& ext : extensions) {
|
||||
std::string coverPath = folder + "/" + std::string(name) + ext;
|
||||
if (Storage.exists(coverPath.c_str())) {
|
||||
Serial.printf("[%lu] [TXT] Found fallback cover image: %s\n", millis(), coverPath.c_str());
|
||||
LOG_DBG("TXT", "Found fallback cover image: %s", coverPath.c_str());
|
||||
return coverPath;
|
||||
}
|
||||
}
|
||||
@@ -104,7 +105,7 @@ bool Txt::generateCoverBmp() const {
|
||||
|
||||
std::string coverImagePath = findCoverImage();
|
||||
if (coverImagePath.empty()) {
|
||||
Serial.printf("[%lu] [TXT] No cover image found for TXT file\n", millis());
|
||||
LOG_DBG("TXT", "No cover image found for TXT file");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -120,7 +121,7 @@ bool Txt::generateCoverBmp() const {
|
||||
|
||||
if (isBmp) {
|
||||
// Copy BMP file to cache
|
||||
Serial.printf("[%lu] [TXT] Copying BMP cover image to cache\n", millis());
|
||||
LOG_DBG("TXT", "Copying BMP cover image to cache");
|
||||
FsFile src, dst;
|
||||
if (!Storage.openFileForRead("TXT", coverImagePath, src)) {
|
||||
return false;
|
||||
@@ -136,13 +137,13 @@ bool Txt::generateCoverBmp() const {
|
||||
}
|
||||
src.close();
|
||||
dst.close();
|
||||
Serial.printf("[%lu] [TXT] Copied BMP cover to cache\n", millis());
|
||||
LOG_DBG("TXT", "Copied BMP cover to cache");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isJpg) {
|
||||
// Convert JPG/JPEG to BMP (same approach as Epub)
|
||||
Serial.printf("[%lu] [TXT] Generating BMP from JPG cover image\n", millis());
|
||||
LOG_DBG("TXT", "Generating BMP from JPG cover image");
|
||||
FsFile coverJpg, coverBmp;
|
||||
if (!Storage.openFileForRead("TXT", coverImagePath, coverJpg)) {
|
||||
return false;
|
||||
@@ -156,16 +157,16 @@ bool Txt::generateCoverBmp() const {
|
||||
coverBmp.close();
|
||||
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [TXT] Failed to generate BMP from JPG cover image\n", millis());
|
||||
LOG_ERR("TXT", "Failed to generate BMP from JPG cover image");
|
||||
Storage.remove(getCoverBmpPath().c_str());
|
||||
} else {
|
||||
Serial.printf("[%lu] [TXT] Generated BMP from JPG cover image\n", millis());
|
||||
LOG_DBG("TXT", "Generated BMP from JPG cover image");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// PNG files are not supported (would need a PNG decoder)
|
||||
Serial.printf("[%lu] [TXT] Cover image format not supported (only BMP/JPG/JPEG)\n", millis());
|
||||
LOG_ERR("TXT", "Cover image format not supported (only BMP/JPG/JPEG)");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
#include "Xtc.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
bool Xtc::load() {
|
||||
Serial.printf("[%lu] [XTC] Loading XTC: %s\n", millis(), filepath.c_str());
|
||||
LOG_DBG("XTC", "Loading XTC: %s", filepath.c_str());
|
||||
|
||||
// Initialize parser
|
||||
parser.reset(new xtc::XtcParser());
|
||||
@@ -19,28 +19,28 @@ bool Xtc::load() {
|
||||
// Open XTC file
|
||||
xtc::XtcError err = parser->open(filepath.c_str());
|
||||
if (err != xtc::XtcError::OK) {
|
||||
Serial.printf("[%lu] [XTC] Failed to load: %s\n", millis(), xtc::errorToString(err));
|
||||
LOG_ERR("XTC", "Failed to load: %s", xtc::errorToString(err));
|
||||
parser.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
Serial.printf("[%lu] [XTC] Loaded XTC: %s (%lu pages)\n", millis(), filepath.c_str(), parser->getPageCount());
|
||||
LOG_DBG("XTC", "Loaded XTC: %s (%lu pages)", filepath.c_str(), parser->getPageCount());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Xtc::clearCache() const {
|
||||
if (!Storage.exists(cachePath.c_str())) {
|
||||
Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis());
|
||||
LOG_DBG("XTC", "Cache does not exist, no action needed");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Storage.removeDir(cachePath.c_str())) {
|
||||
Serial.printf("[%lu] [XTC] Failed to clear cache\n", millis());
|
||||
LOG_ERR("XTC", "Failed to clear cache");
|
||||
return false;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [XTC] Cache cleared successfully\n", millis());
|
||||
LOG_DBG("XTC", "Cache cleared successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -119,12 +119,12 @@ bool Xtc::generateCoverBmp() const {
|
||||
}
|
||||
|
||||
if (!loaded || !parser) {
|
||||
Serial.printf("[%lu] [XTC] Cannot generate cover BMP, file not loaded\n", millis());
|
||||
LOG_ERR("XTC", "Cannot generate cover BMP, file not loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parser->getPageCount() == 0) {
|
||||
Serial.printf("[%lu] [XTC] No pages in XTC file\n", millis());
|
||||
LOG_ERR("XTC", "No pages in XTC file");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ bool Xtc::generateCoverBmp() const {
|
||||
// Get first page info for cover
|
||||
xtc::PageInfo pageInfo;
|
||||
if (!parser->getPageInfo(0, pageInfo)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to get first page info\n", millis());
|
||||
LOG_DBG("XTC", "Failed to get first page info");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -152,14 +152,14 @@ bool Xtc::generateCoverBmp() const {
|
||||
}
|
||||
uint8_t* pageBuffer = static_cast<uint8_t*>(malloc(bitmapSize));
|
||||
if (!pageBuffer) {
|
||||
Serial.printf("[%lu] [XTC] Failed to allocate page buffer (%lu bytes)\n", millis(), bitmapSize);
|
||||
LOG_ERR("XTC", "Failed to allocate page buffer (%lu bytes)", bitmapSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load first page (cover)
|
||||
size_t bytesRead = const_cast<xtc::XtcParser*>(parser.get())->loadPage(0, pageBuffer, bitmapSize);
|
||||
if (bytesRead == 0) {
|
||||
Serial.printf("[%lu] [XTC] Failed to load cover page\n", millis());
|
||||
LOG_ERR("XTC", "Failed to load cover page");
|
||||
free(pageBuffer);
|
||||
return false;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ bool Xtc::generateCoverBmp() const {
|
||||
// Create BMP file
|
||||
FsFile coverBmp;
|
||||
if (!Storage.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis());
|
||||
LOG_DBG("XTC", "Failed to create cover BMP file");
|
||||
free(pageBuffer);
|
||||
return false;
|
||||
}
|
||||
@@ -297,7 +297,7 @@ bool Xtc::generateCoverBmp() const {
|
||||
coverBmp.close();
|
||||
free(pageBuffer);
|
||||
|
||||
Serial.printf("[%lu] [XTC] Generated cover BMP: %s\n", millis(), getCoverBmpPath().c_str());
|
||||
LOG_DBG("XTC", "Generated cover BMP: %s", getCoverBmpPath().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -311,12 +311,12 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
}
|
||||
|
||||
if (!loaded || !parser) {
|
||||
Serial.printf("[%lu] [XTC] Cannot generate thumb BMP, file not loaded\n", millis());
|
||||
LOG_ERR("XTC", "Cannot generate thumb BMP, file not loaded");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parser->getPageCount() == 0) {
|
||||
Serial.printf("[%lu] [XTC] No pages in XTC file\n", millis());
|
||||
LOG_ERR("XTC", "No pages in XTC file");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -326,7 +326,7 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
// Get first page info for cover
|
||||
xtc::PageInfo pageInfo;
|
||||
if (!parser->getPageInfo(0, pageInfo)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to get first page info\n", millis());
|
||||
LOG_DBG("XTC", "Failed to get first page info");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -359,7 +359,7 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
}
|
||||
src.close();
|
||||
}
|
||||
Serial.printf("[%lu] [XTC] Copied cover to thumb (no scaling needed)\n", millis());
|
||||
LOG_DBG("XTC", "Copied cover to thumb (no scaling needed)");
|
||||
return Storage.exists(getThumbBmpPath(height).c_str());
|
||||
}
|
||||
return false;
|
||||
@@ -368,8 +368,8 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
uint16_t thumbWidth = static_cast<uint16_t>(pageInfo.width * scale);
|
||||
uint16_t thumbHeight = static_cast<uint16_t>(pageInfo.height * scale);
|
||||
|
||||
Serial.printf("[%lu] [XTC] Generating thumb BMP: %dx%d -> %dx%d (scale: %.3f)\n", millis(), pageInfo.width,
|
||||
pageInfo.height, thumbWidth, thumbHeight, scale);
|
||||
LOG_DBG("XTC", "Generating thumb BMP: %dx%d -> %dx%d (scale: %.3f)", pageInfo.width, pageInfo.height, thumbWidth,
|
||||
thumbHeight, scale);
|
||||
|
||||
// Allocate buffer for page data
|
||||
size_t bitmapSize;
|
||||
@@ -380,14 +380,14 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
}
|
||||
uint8_t* pageBuffer = static_cast<uint8_t*>(malloc(bitmapSize));
|
||||
if (!pageBuffer) {
|
||||
Serial.printf("[%lu] [XTC] Failed to allocate page buffer (%lu bytes)\n", millis(), bitmapSize);
|
||||
LOG_ERR("XTC", "Failed to allocate page buffer (%lu bytes)", bitmapSize);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load first page (cover)
|
||||
size_t bytesRead = const_cast<xtc::XtcParser*>(parser.get())->loadPage(0, pageBuffer, bitmapSize);
|
||||
if (bytesRead == 0) {
|
||||
Serial.printf("[%lu] [XTC] Failed to load cover page for thumb\n", millis());
|
||||
LOG_ERR("XTC", "Failed to load cover page for thumb");
|
||||
free(pageBuffer);
|
||||
return false;
|
||||
}
|
||||
@@ -395,7 +395,7 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
// Create thumbnail BMP file - use 1-bit format for fast home screen rendering (no gray passes)
|
||||
FsFile thumbBmp;
|
||||
if (!Storage.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to create thumb BMP file\n", millis());
|
||||
LOG_DBG("XTC", "Failed to create thumb BMP file");
|
||||
free(pageBuffer);
|
||||
return false;
|
||||
}
|
||||
@@ -558,8 +558,7 @@ bool Xtc::generateThumbBmp(int height) const {
|
||||
thumbBmp.close();
|
||||
free(pageBuffer);
|
||||
|
||||
Serial.printf("[%lu] [XTC] Generated thumb BMP (%dx%d): %s\n", millis(), thumbWidth, thumbHeight,
|
||||
getThumbBmpPath(height).c_str());
|
||||
LOG_DBG("XTC", "Generated thumb BMP (%dx%d): %s", thumbWidth, thumbHeight, getThumbBmpPath(height).c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
#include <FsHelpers.h>
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -42,7 +42,7 @@ XtcError XtcParser::open(const char* filepath) {
|
||||
// Read header
|
||||
m_lastError = readHeader();
|
||||
if (m_lastError != XtcError::OK) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read header: %s\n", millis(), errorToString(m_lastError));
|
||||
LOG_DBG("XTC", "Failed to read header: %s", errorToString(m_lastError));
|
||||
m_file.close();
|
||||
return m_lastError;
|
||||
}
|
||||
@@ -51,13 +51,13 @@ XtcError XtcParser::open(const char* filepath) {
|
||||
if (m_header.hasMetadata) {
|
||||
m_lastError = readTitle();
|
||||
if (m_lastError != XtcError::OK) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read title: %s\n", millis(), errorToString(m_lastError));
|
||||
LOG_DBG("XTC", "Failed to read title: %s", errorToString(m_lastError));
|
||||
m_file.close();
|
||||
return m_lastError;
|
||||
}
|
||||
m_lastError = readAuthor();
|
||||
if (m_lastError != XtcError::OK) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read author: %s\n", millis(), errorToString(m_lastError));
|
||||
LOG_DBG("XTC", "Failed to read author: %s", errorToString(m_lastError));
|
||||
m_file.close();
|
||||
return m_lastError;
|
||||
}
|
||||
@@ -66,7 +66,7 @@ XtcError XtcParser::open(const char* filepath) {
|
||||
// Read page table
|
||||
m_lastError = readPageTable();
|
||||
if (m_lastError != XtcError::OK) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read page table: %s\n", millis(), errorToString(m_lastError));
|
||||
LOG_DBG("XTC", "Failed to read page table: %s", errorToString(m_lastError));
|
||||
m_file.close();
|
||||
return m_lastError;
|
||||
}
|
||||
@@ -74,14 +74,13 @@ XtcError XtcParser::open(const char* filepath) {
|
||||
// Read chapters if present
|
||||
m_lastError = readChapters();
|
||||
if (m_lastError != XtcError::OK) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read chapters: %s\n", millis(), errorToString(m_lastError));
|
||||
LOG_DBG("XTC", "Failed to read chapters: %s", errorToString(m_lastError));
|
||||
m_file.close();
|
||||
return m_lastError;
|
||||
}
|
||||
|
||||
m_isOpen = true;
|
||||
Serial.printf("[%lu] [XTC] Opened file: %s (%u pages, %dx%d)\n", millis(), filepath, m_header.pageCount,
|
||||
m_defaultWidth, m_defaultHeight);
|
||||
LOG_DBG("XTC", "Opened file: %s (%u pages, %dx%d)", filepath, m_header.pageCount, m_defaultWidth, m_defaultHeight);
|
||||
return XtcError::OK;
|
||||
}
|
||||
|
||||
@@ -106,8 +105,7 @@ XtcError XtcParser::readHeader() {
|
||||
|
||||
// Verify magic number (accept both XTC and XTCH)
|
||||
if (m_header.magic != XTC_MAGIC && m_header.magic != XTCH_MAGIC) {
|
||||
Serial.printf("[%lu] [XTC] Invalid magic: 0x%08X (expected 0x%08X or 0x%08X)\n", millis(), m_header.magic,
|
||||
XTC_MAGIC, XTCH_MAGIC);
|
||||
LOG_DBG("XTC", "Invalid magic: 0x%08X (expected 0x%08X or 0x%08X)", m_header.magic, XTC_MAGIC, XTCH_MAGIC);
|
||||
return XtcError::INVALID_MAGIC;
|
||||
}
|
||||
|
||||
@@ -120,7 +118,7 @@ XtcError XtcParser::readHeader() {
|
||||
const bool validVersion = m_header.versionMajor == 1 && m_header.versionMinor == 0 ||
|
||||
m_header.versionMajor == 0 && m_header.versionMinor == 1;
|
||||
if (!validVersion) {
|
||||
Serial.printf("[%lu] [XTC] Unsupported version: %u.%u\n", millis(), m_header.versionMajor, m_header.versionMinor);
|
||||
LOG_DBG("XTC", "Unsupported version: %u.%u", m_header.versionMajor, m_header.versionMinor);
|
||||
return XtcError::INVALID_VERSION;
|
||||
}
|
||||
|
||||
@@ -129,9 +127,9 @@ XtcError XtcParser::readHeader() {
|
||||
return XtcError::CORRUPTED_HEADER;
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [XTC] Header: magic=0x%08X (%s), ver=%u.%u, pages=%u, bitDepth=%u\n", millis(), m_header.magic,
|
||||
(m_header.magic == XTCH_MAGIC) ? "XTCH" : "XTC", m_header.versionMajor, m_header.versionMinor,
|
||||
m_header.pageCount, m_bitDepth);
|
||||
LOG_DBG("XTC", "Header: magic=0x%08X (%s), ver=%u.%u, pages=%u, bitDepth=%u", m_header.magic,
|
||||
(m_header.magic == XTCH_MAGIC) ? "XTCH" : "XTC", m_header.versionMajor, m_header.versionMinor,
|
||||
m_header.pageCount, m_bitDepth);
|
||||
|
||||
return XtcError::OK;
|
||||
}
|
||||
@@ -146,7 +144,7 @@ XtcError XtcParser::readTitle() {
|
||||
m_file.read(titleBuf, sizeof(titleBuf) - 1);
|
||||
m_title = titleBuf;
|
||||
|
||||
Serial.printf("[%lu] [XTC] Title: %s\n", millis(), m_title.c_str());
|
||||
LOG_DBG("XTC", "Title: %s", m_title.c_str());
|
||||
return XtcError::OK;
|
||||
}
|
||||
|
||||
@@ -161,19 +159,19 @@ XtcError XtcParser::readAuthor() {
|
||||
m_file.read(authorBuf, sizeof(authorBuf) - 1);
|
||||
m_author = authorBuf;
|
||||
|
||||
Serial.printf("[%lu] [XTC] Author: %s\n", millis(), m_author.c_str());
|
||||
LOG_DBG("XTC", "Author: %s", m_author.c_str());
|
||||
return XtcError::OK;
|
||||
}
|
||||
|
||||
XtcError XtcParser::readPageTable() {
|
||||
if (m_header.pageTableOffset == 0) {
|
||||
Serial.printf("[%lu] [XTC] Page table offset is 0, cannot read\n", millis());
|
||||
LOG_DBG("XTC", "Page table offset is 0, cannot read");
|
||||
return XtcError::CORRUPTED_HEADER;
|
||||
}
|
||||
|
||||
// Seek to page table
|
||||
if (!m_file.seek(m_header.pageTableOffset)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to seek to page table at %llu\n", millis(), m_header.pageTableOffset);
|
||||
LOG_DBG("XTC", "Failed to seek to page table at %llu", m_header.pageTableOffset);
|
||||
return XtcError::READ_ERROR;
|
||||
}
|
||||
|
||||
@@ -184,7 +182,7 @@ XtcError XtcParser::readPageTable() {
|
||||
PageTableEntry entry;
|
||||
size_t bytesRead = m_file.read(reinterpret_cast<uint8_t*>(&entry), sizeof(PageTableEntry));
|
||||
if (bytesRead != sizeof(PageTableEntry)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read page table entry %u\n", millis(), i);
|
||||
LOG_DBG("XTC", "Failed to read page table entry %u", i);
|
||||
return XtcError::READ_ERROR;
|
||||
}
|
||||
|
||||
@@ -201,7 +199,7 @@ XtcError XtcParser::readPageTable() {
|
||||
}
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [XTC] Read %u page table entries\n", millis(), m_header.pageCount);
|
||||
LOG_DBG("XTC", "Read %u page table entries", m_header.pageCount);
|
||||
return XtcError::OK;
|
||||
}
|
||||
|
||||
@@ -307,7 +305,7 @@ XtcError XtcParser::readChapters() {
|
||||
}
|
||||
|
||||
m_hasChapters = !m_chapters.empty();
|
||||
Serial.printf("[%lu] [XTC] Chapters: %u\n", millis(), static_cast<unsigned int>(m_chapters.size()));
|
||||
LOG_DBG("XTC", "Chapters: %u", static_cast<unsigned int>(m_chapters.size()));
|
||||
return XtcError::OK;
|
||||
}
|
||||
|
||||
@@ -334,7 +332,7 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
|
||||
|
||||
// Seek to page data
|
||||
if (!m_file.seek(page.offset)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to seek to page %u at offset %lu\n", millis(), pageIndex, page.offset);
|
||||
LOG_DBG("XTC", "Failed to seek to page %u at offset %lu", pageIndex, page.offset);
|
||||
m_lastError = XtcError::READ_ERROR;
|
||||
return 0;
|
||||
}
|
||||
@@ -343,7 +341,7 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
|
||||
XtgPageHeader pageHeader;
|
||||
size_t headerRead = m_file.read(reinterpret_cast<uint8_t*>(&pageHeader), sizeof(XtgPageHeader));
|
||||
if (headerRead != sizeof(XtgPageHeader)) {
|
||||
Serial.printf("[%lu] [XTC] Failed to read page header for page %u\n", millis(), pageIndex);
|
||||
LOG_DBG("XTC", "Failed to read page header for page %u", pageIndex);
|
||||
m_lastError = XtcError::READ_ERROR;
|
||||
return 0;
|
||||
}
|
||||
@@ -351,8 +349,8 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
|
||||
// Verify page magic (XTG for 1-bit, XTH for 2-bit)
|
||||
const uint32_t expectedMagic = (m_bitDepth == 2) ? XTH_MAGIC : XTG_MAGIC;
|
||||
if (pageHeader.magic != expectedMagic) {
|
||||
Serial.printf("[%lu] [XTC] Invalid page magic for page %u: 0x%08X (expected 0x%08X)\n", millis(), pageIndex,
|
||||
pageHeader.magic, expectedMagic);
|
||||
LOG_DBG("XTC", "Invalid page magic for page %u: 0x%08X (expected 0x%08X)", pageIndex, pageHeader.magic,
|
||||
expectedMagic);
|
||||
m_lastError = XtcError::INVALID_MAGIC;
|
||||
return 0;
|
||||
}
|
||||
@@ -370,7 +368,7 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
|
||||
|
||||
// Check buffer size
|
||||
if (bufferSize < bitmapSize) {
|
||||
Serial.printf("[%lu] [XTC] Buffer too small: need %u, have %u\n", millis(), bitmapSize, bufferSize);
|
||||
LOG_DBG("XTC", "Buffer too small: need %u, have %u", bitmapSize, bufferSize);
|
||||
m_lastError = XtcError::MEMORY_ERROR;
|
||||
return 0;
|
||||
}
|
||||
@@ -378,7 +376,7 @@ size_t XtcParser::loadPage(uint32_t pageIndex, uint8_t* buffer, size_t bufferSiz
|
||||
// Read bitmap data
|
||||
size_t bytesRead = m_file.read(buffer, bitmapSize);
|
||||
if (bytesRead != bitmapSize) {
|
||||
Serial.printf("[%lu] [XTC] Page read error: expected %u, got %u\n", millis(), bitmapSize, bytesRead);
|
||||
LOG_DBG("XTC", "Page read error: expected %u, got %u", bitmapSize, bytesRead);
|
||||
m_lastError = XtcError::READ_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "ZipFile.h"
|
||||
|
||||
#include <HalStorage.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
#include <miniz.h>
|
||||
|
||||
#include <algorithm>
|
||||
@@ -10,7 +10,7 @@ bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t*
|
||||
// Setup inflator
|
||||
const auto inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor)));
|
||||
if (!inflator) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for inflator\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for inflator");
|
||||
return false;
|
||||
}
|
||||
memset(inflator, 0, sizeof(tinfl_decompressor));
|
||||
@@ -23,7 +23,7 @@ bool inflateOneShot(const uint8_t* inputBuf, const size_t deflatedSize, uint8_t*
|
||||
free(inflator);
|
||||
|
||||
if (status != TINFL_STATUS_DONE) {
|
||||
Serial.printf("[%lu] [ZIP] tinfl_decompress() failed with status %d\n", millis(), status);
|
||||
LOG_ERR("ZIP", "tinfl_decompress() failed with status %d", status);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -195,13 +195,13 @@ long ZipFile::getDataOffset(const FileStatSlim& fileStat) {
|
||||
}
|
||||
|
||||
if (read != localHeaderSize) {
|
||||
Serial.printf("[%lu] [ZIP] Something went wrong reading the local header\n", millis());
|
||||
LOG_ERR("ZIP", "Something went wrong reading the local header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pLocalHeader[0] + (pLocalHeader[1] << 8) + (pLocalHeader[2] << 16) + (pLocalHeader[3] << 24) !=
|
||||
0x04034b50 /* MZ_ZIP_LOCAL_DIR_HEADER_SIG */) {
|
||||
Serial.printf("[%lu] [ZIP] Not a valid zip file header\n", millis());
|
||||
LOG_ERR("ZIP", "Not a valid zip file header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ bool ZipFile::loadZipDetails() {
|
||||
|
||||
const size_t fileSize = file.size();
|
||||
if (fileSize < 22) {
|
||||
Serial.printf("[%lu] [ZIP] File too small to be a valid zip\n", millis());
|
||||
LOG_ERR("ZIP", "File too small to be a valid zip");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -234,7 +234,7 @@ bool ZipFile::loadZipDetails() {
|
||||
const int scanRange = fileSize > 1024 ? 1024 : fileSize;
|
||||
const auto buffer = static_cast<uint8_t*>(malloc(scanRange));
|
||||
if (!buffer) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for EOCD scan buffer\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for EOCD scan buffer");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -255,7 +255,7 @@ bool ZipFile::loadZipDetails() {
|
||||
}
|
||||
|
||||
if (foundOffset == -1) {
|
||||
Serial.printf("[%lu] [ZIP] EOCD signature not found in zip file\n", millis());
|
||||
LOG_ERR("ZIP", "EOCD signature not found in zip file");
|
||||
free(buffer);
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
@@ -407,7 +407,7 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
|
||||
const auto dataSize = trailingNullByte ? inflatedDataSize + 1 : inflatedDataSize;
|
||||
const auto data = static_cast<uint8_t*>(malloc(dataSize));
|
||||
if (data == nullptr) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for output buffer (%zu bytes)\n", millis(), dataSize);
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for output buffer (%zu bytes)", dataSize);
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -422,7 +422,7 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
|
||||
}
|
||||
|
||||
if (dataRead != inflatedDataSize) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to read data\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to read data");
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -432,7 +432,7 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
|
||||
// Read out deflated content from file
|
||||
const auto deflatedData = static_cast<uint8_t*>(malloc(deflatedDataSize));
|
||||
if (deflatedData == nullptr) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for decompression buffer\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for decompression buffer");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -445,7 +445,7 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
|
||||
}
|
||||
|
||||
if (dataRead != deflatedDataSize) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to read data, expected %d got %d\n", millis(), deflatedDataSize, dataRead);
|
||||
LOG_ERR("ZIP", "Failed to read data, expected %d got %d", deflatedDataSize, dataRead);
|
||||
free(deflatedData);
|
||||
free(data);
|
||||
return nullptr;
|
||||
@@ -455,14 +455,14 @@ uint8_t* ZipFile::readFileToMemory(const char* filename, size_t* size, const boo
|
||||
free(deflatedData);
|
||||
|
||||
if (!success) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to inflate file\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to inflate file");
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Continue out of block with data set
|
||||
} else {
|
||||
Serial.printf("[%lu] [ZIP] Unsupported compression method\n", millis());
|
||||
LOG_ERR("ZIP", "Unsupported compression method");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -498,7 +498,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
// no deflation, just read content
|
||||
const auto buffer = static_cast<uint8_t*>(malloc(chunkSize));
|
||||
if (!buffer) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for buffer\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for buffer");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -509,7 +509,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
while (remaining > 0) {
|
||||
const size_t dataRead = file.read(buffer, remaining < chunkSize ? remaining : chunkSize);
|
||||
if (dataRead == 0) {
|
||||
Serial.printf("[%lu] [ZIP] Could not read more bytes\n", millis());
|
||||
LOG_ERR("ZIP", "Could not read more bytes");
|
||||
free(buffer);
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
@@ -532,7 +532,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
// Setup inflator
|
||||
const auto inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor)));
|
||||
if (!inflator) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for inflator\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for inflator");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -544,7 +544,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
// Setup file read buffer
|
||||
const auto fileReadBuffer = static_cast<uint8_t*>(malloc(chunkSize));
|
||||
if (!fileReadBuffer) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for zip file read buffer\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for zip file read buffer");
|
||||
free(inflator);
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
@@ -554,7 +554,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
|
||||
const auto outputBuffer = static_cast<uint8_t*>(malloc(TINFL_LZ_DICT_SIZE));
|
||||
if (!outputBuffer) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to allocate memory for dictionary\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to allocate memory for dictionary");
|
||||
free(inflator);
|
||||
free(fileReadBuffer);
|
||||
if (!wasOpen) {
|
||||
@@ -605,7 +605,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
if (outBytes > 0) {
|
||||
processedOutputBytes += outBytes;
|
||||
if (out.write(outputBuffer + outputCursor, outBytes) != outBytes) {
|
||||
Serial.printf("[%lu] [ZIP] Failed to write all output bytes to stream\n", millis());
|
||||
LOG_ERR("ZIP", "Failed to write all output bytes to stream");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -619,7 +619,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
}
|
||||
|
||||
if (status < 0) {
|
||||
Serial.printf("[%lu] [ZIP] tinfl_decompress() failed with status %d\n", millis(), status);
|
||||
LOG_ERR("ZIP", "tinfl_decompress() failed with status %d", status);
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -630,8 +630,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
}
|
||||
|
||||
if (status == TINFL_STATUS_DONE) {
|
||||
Serial.printf("[%lu] [ZIP] Decompressed %d bytes into %d bytes\n", millis(), deflatedDataSize,
|
||||
inflatedDataSize);
|
||||
LOG_ERR("ZIP", "Decompressed %d bytes into %d bytes", deflatedDataSize, inflatedDataSize);
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -643,7 +642,7 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
}
|
||||
|
||||
// If we get here, EOF reached without TINFL_STATUS_DONE
|
||||
Serial.printf("[%lu] [ZIP] Unexpected EOF\n", millis());
|
||||
LOG_ERR("ZIP", "Unexpected EOF");
|
||||
if (!wasOpen) {
|
||||
close();
|
||||
}
|
||||
@@ -657,6 +656,6 @@ bool ZipFile::readFileToStream(const char* filename, Print& out, const size_t ch
|
||||
close();
|
||||
}
|
||||
|
||||
Serial.printf("[%lu] [ZIP] Unsupported compression method\n", millis());
|
||||
LOG_ERR("ZIP", "Unsupported compression method");
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user