A fork of https://github.com/crosspoint-reader/crosspoint-reader
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

jpirnay
Xuan Son Nguyen
and committed by
GitHub
cb249474 7a385d78

+795 -688
+86 -89
lib/Epub/Epub.cpp
··· 2 2 3 3 #include <FsHelpers.h> 4 4 #include <HalStorage.h> 5 - #include <HardwareSerial.h> 6 5 #include <JpegToBmpConverter.h> 6 + #include <Logging.h> 7 7 #include <ZipFile.h> 8 8 9 9 #include "Epub/parsers/ContainerParser.h" ··· 17 17 18 18 // Get file size without loading it all into heap 19 19 if (!getItemSize(containerPath, &containerSize)) { 20 - Serial.printf("[%lu] [EBP] Could not find or size META-INF/container.xml\n", millis()); 20 + LOG_ERR("EBP", "Could not find or size META-INF/container.xml"); 21 21 return false; 22 22 } 23 23 ··· 29 29 30 30 // Stream read (reusing your existing stream logic) 31 31 if (!readItemContentsToStream(containerPath, containerParser, 512)) { 32 - Serial.printf("[%lu] [EBP] Could not read META-INF/container.xml\n", millis()); 32 + LOG_ERR("EBP", "Could not read META-INF/container.xml"); 33 33 return false; 34 34 } 35 35 36 36 // Extract the result 37 37 if (containerParser.fullPath.empty()) { 38 - Serial.printf("[%lu] [EBP] Could not find valid rootfile in container.xml\n", millis()); 38 + LOG_ERR("EBP", "Could not find valid rootfile in container.xml"); 39 39 return false; 40 40 } 41 41 ··· 46 46 bool Epub::parseContentOpf(BookMetadataCache::BookMetadata& bookMetadata) { 47 47 std::string contentOpfFilePath; 48 48 if (!findContentOpfFile(&contentOpfFilePath)) { 49 - Serial.printf("[%lu] [EBP] Could not find content.opf in zip\n", millis()); 49 + LOG_ERR("EBP", "Could not find content.opf in zip"); 50 50 return false; 51 51 } 52 52 53 53 contentBasePath = contentOpfFilePath.substr(0, contentOpfFilePath.find_last_of('/') + 1); 54 54 55 - Serial.printf("[%lu] [EBP] Parsing content.opf: %s\n", millis(), contentOpfFilePath.c_str()); 55 + LOG_DBG("EBP", "Parsing content.opf: %s", contentOpfFilePath.c_str()); 56 56 57 57 size_t contentOpfSize; 58 58 if (!getItemSize(contentOpfFilePath, &contentOpfSize)) { 59 - Serial.printf("[%lu] [EBP] Could not get size of content.opf\n", millis()); 59 + LOG_ERR("EBP", "Could not get size of content.opf"); 60 60 return false; 61 61 } 62 62 63 63 ContentOpfParser opfParser(getCachePath(), getBasePath(), contentOpfSize, bookMetadataCache.get()); 64 64 if (!opfParser.setup()) { 65 - Serial.printf("[%lu] [EBP] Could not setup content.opf parser\n", millis()); 65 + LOG_ERR("EBP", "Could not setup content.opf parser"); 66 66 return false; 67 67 } 68 68 69 69 if (!readItemContentsToStream(contentOpfFilePath, opfParser, 1024)) { 70 - Serial.printf("[%lu] [EBP] Could not read content.opf\n", millis()); 70 + LOG_ERR("EBP", "Could not read content.opf"); 71 71 return false; 72 72 } 73 73 ··· 90 90 cssFiles = opfParser.cssFiles; 91 91 } 92 92 93 - Serial.printf("[%lu] [EBP] Successfully parsed content.opf\n", millis()); 93 + LOG_DBG("EBP", "Successfully parsed content.opf"); 94 94 return true; 95 95 } 96 96 97 97 bool Epub::parseTocNcxFile() const { 98 98 // the ncx file should have been specified in the content.opf file 99 99 if (tocNcxItem.empty()) { 100 - Serial.printf("[%lu] [EBP] No ncx file specified\n", millis()); 100 + LOG_DBG("EBP", "No ncx file specified"); 101 101 return false; 102 102 } 103 103 104 - Serial.printf("[%lu] [EBP] Parsing toc ncx file: %s\n", millis(), tocNcxItem.c_str()); 104 + LOG_DBG("EBP", "Parsing toc ncx file: %s", tocNcxItem.c_str()); 105 105 106 106 const auto tmpNcxPath = getCachePath() + "/toc.ncx"; 107 107 FsFile tempNcxFile; ··· 118 118 TocNcxParser ncxParser(contentBasePath, ncxSize, bookMetadataCache.get()); 119 119 120 120 if (!ncxParser.setup()) { 121 - Serial.printf("[%lu] [EBP] Could not setup toc ncx parser\n", millis()); 121 + LOG_ERR("EBP", "Could not setup toc ncx parser"); 122 122 tempNcxFile.close(); 123 123 return false; 124 124 } 125 125 126 126 const auto ncxBuffer = static_cast<uint8_t*>(malloc(1024)); 127 127 if (!ncxBuffer) { 128 - Serial.printf("[%lu] [EBP] Could not allocate memory for toc ncx parser\n", millis()); 128 + LOG_ERR("EBP", "Could not allocate memory for toc ncx parser"); 129 129 tempNcxFile.close(); 130 130 return false; 131 131 } ··· 136 136 const auto processedSize = ncxParser.write(ncxBuffer, readSize); 137 137 138 138 if (processedSize != readSize) { 139 - Serial.printf("[%lu] [EBP] Could not process all toc ncx data\n", millis()); 139 + LOG_ERR("EBP", "Could not process all toc ncx data"); 140 140 free(ncxBuffer); 141 141 tempNcxFile.close(); 142 142 return false; ··· 147 147 tempNcxFile.close(); 148 148 Storage.remove(tmpNcxPath.c_str()); 149 149 150 - Serial.printf("[%lu] [EBP] Parsed TOC items\n", millis()); 150 + LOG_DBG("EBP", "Parsed TOC items"); 151 151 return true; 152 152 } 153 153 154 154 bool Epub::parseTocNavFile() const { 155 155 // the nav file should have been specified in the content.opf file (EPUB 3) 156 156 if (tocNavItem.empty()) { 157 - Serial.printf("[%lu] [EBP] No nav file specified\n", millis()); 157 + LOG_DBG("EBP", "No nav file specified"); 158 158 return false; 159 159 } 160 160 161 - Serial.printf("[%lu] [EBP] Parsing toc nav file: %s\n", millis(), tocNavItem.c_str()); 161 + LOG_DBG("EBP", "Parsing toc nav file: %s", tocNavItem.c_str()); 162 162 163 163 const auto tmpNavPath = getCachePath() + "/toc.nav"; 164 164 FsFile tempNavFile; ··· 178 178 TocNavParser navParser(navContentBasePath, navSize, bookMetadataCache.get()); 179 179 180 180 if (!navParser.setup()) { 181 - Serial.printf("[%lu] [EBP] Could not setup toc nav parser\n", millis()); 181 + LOG_ERR("EBP", "Could not setup toc nav parser"); 182 182 return false; 183 183 } 184 184 185 185 const auto navBuffer = static_cast<uint8_t*>(malloc(1024)); 186 186 if (!navBuffer) { 187 - Serial.printf("[%lu] [EBP] Could not allocate memory for toc nav parser\n", millis()); 187 + LOG_ERR("EBP", "Could not allocate memory for toc nav parser"); 188 188 return false; 189 189 } 190 190 ··· 193 193 const auto processedSize = navParser.write(navBuffer, readSize); 194 194 195 195 if (processedSize != readSize) { 196 - Serial.printf("[%lu] [EBP] Could not process all toc nav data\n", millis()); 196 + LOG_ERR("EBP", "Could not process all toc nav data"); 197 197 free(navBuffer); 198 198 tempNavFile.close(); 199 199 return false; ··· 204 204 tempNavFile.close(); 205 205 Storage.remove(tmpNavPath.c_str()); 206 206 207 - Serial.printf("[%lu] [EBP] Parsed TOC nav items\n", millis()); 207 + LOG_DBG("EBP", "Parsed TOC nav items"); 208 208 return true; 209 209 } 210 210 ··· 215 215 if (Storage.openFileForRead("EBP", getCssRulesCache(), cssCacheFile)) { 216 216 if (cssParser->loadFromCache(cssCacheFile)) { 217 217 cssCacheFile.close(); 218 - Serial.printf("[%lu] [EBP] Loaded CSS rules from cache\n", millis()); 218 + LOG_DBG("EBP", "Loaded CSS rules from cache"); 219 219 return true; 220 220 } 221 221 cssCacheFile.close(); 222 - Serial.printf("[%lu] [EBP] CSS cache invalid, reparsing\n", millis()); 222 + LOG_DBG("EBP", "CSS cache invalid, reparsing"); 223 223 } 224 224 return false; 225 225 } 226 226 227 227 void Epub::parseCssFiles() const { 228 228 if (cssFiles.empty()) { 229 - Serial.printf("[%lu] [EBP] No CSS files to parse, but CssParser created for inline styles\n", millis()); 229 + LOG_DBG("EBP", "No CSS files to parse, but CssParser created for inline styles"); 230 230 } 231 231 232 232 // Try to load from CSS cache first 233 233 if (!loadCssRulesFromCache()) { 234 234 // Cache miss - parse CSS files 235 235 for (const auto& cssPath : cssFiles) { 236 - Serial.printf("[%lu] [EBP] Parsing CSS file: %s\n", millis(), cssPath.c_str()); 236 + LOG_DBG("EBP", "Parsing CSS file: %s", cssPath.c_str()); 237 237 238 238 // Extract CSS file to temp location 239 239 const auto tmpCssPath = getCachePath() + "/.tmp.css"; 240 240 FsFile tempCssFile; 241 241 if (!Storage.openFileForWrite("EBP", tmpCssPath, tempCssFile)) { 242 - Serial.printf("[%lu] [EBP] Could not create temp CSS file\n", millis()); 242 + LOG_ERR("EBP", "Could not create temp CSS file"); 243 243 continue; 244 244 } 245 245 if (!readItemContentsToStream(cssPath, tempCssFile, 1024)) { 246 - Serial.printf("[%lu] [EBP] Could not read CSS file: %s\n", millis(), cssPath.c_str()); 246 + LOG_ERR("EBP", "Could not read CSS file: %s", cssPath.c_str()); 247 247 tempCssFile.close(); 248 248 Storage.remove(tmpCssPath.c_str()); 249 249 continue; ··· 252 252 253 253 // Parse the CSS file 254 254 if (!Storage.openFileForRead("EBP", tmpCssPath, tempCssFile)) { 255 - Serial.printf("[%lu] [EBP] Could not open temp CSS file for reading\n", millis()); 255 + LOG_ERR("EBP", "Could not open temp CSS file for reading"); 256 256 Storage.remove(tmpCssPath.c_str()); 257 257 continue; 258 258 } ··· 268 268 cssCacheFile.close(); 269 269 } 270 270 271 - Serial.printf("[%lu] [EBP] Loaded %zu CSS style rules from %zu files\n", millis(), cssParser->ruleCount(), 272 - cssFiles.size()); 271 + LOG_DBG("EBP", "Loaded %zu CSS style rules from %zu files", cssParser->ruleCount(), cssFiles.size()); 273 272 } 274 273 } 275 274 276 275 // load in the meta data for the epub file 277 276 bool Epub::load(const bool buildIfMissing, const bool skipLoadingCss) { 278 - Serial.printf("[%lu] [EBP] Loading ePub: %s\n", millis(), filepath.c_str()); 277 + LOG_DBG("EBP", "Loading ePub: %s", filepath.c_str()); 279 278 280 279 // Initialize spine/TOC cache 281 280 bookMetadataCache.reset(new BookMetadataCache(cachePath)); ··· 285 284 // Try to load existing cache first 286 285 if (bookMetadataCache->load()) { 287 286 if (!skipLoadingCss && !loadCssRulesFromCache()) { 288 - Serial.printf("[%lu] [EBP] Warning: CSS rules cache not found, attempting to parse CSS files\n", millis()); 287 + LOG_DBG("EBP", "Warning: CSS rules cache not found, attempting to parse CSS files"); 289 288 // to get CSS file list 290 289 if (!parseContentOpf(bookMetadataCache->coreMetadata)) { 291 - Serial.printf("[%lu] [EBP] Could not parse content.opf from cached bookMetadata for CSS files\n", millis()); 290 + LOG_ERR("EBP", "Could not parse content.opf from cached bookMetadata for CSS files"); 292 291 // continue anyway - book will work without CSS and we'll still load any inline style CSS 293 292 } 294 293 parseCssFiles(); 295 294 } 296 - Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str()); 295 + LOG_DBG("EBP", "Loaded ePub: %s", filepath.c_str()); 297 296 return true; 298 297 } 299 298 ··· 303 302 } 304 303 305 304 // Cache doesn't exist or is invalid, build it 306 - Serial.printf("[%lu] [EBP] Cache not found, building spine/TOC cache\n", millis()); 305 + LOG_DBG("EBP", "Cache not found, building spine/TOC cache"); 307 306 setupCacheDir(); 308 307 309 308 const uint32_t indexingStart = millis(); 310 309 311 310 // Begin building cache - stream entries to disk immediately 312 311 if (!bookMetadataCache->beginWrite()) { 313 - Serial.printf("[%lu] [EBP] Could not begin writing cache\n", millis()); 312 + LOG_ERR("EBP", "Could not begin writing cache"); 314 313 return false; 315 314 } 316 315 ··· 318 317 const uint32_t opfStart = millis(); 319 318 BookMetadataCache::BookMetadata bookMetadata; 320 319 if (!bookMetadataCache->beginContentOpfPass()) { 321 - Serial.printf("[%lu] [EBP] Could not begin writing content.opf pass\n", millis()); 320 + LOG_ERR("EBP", "Could not begin writing content.opf pass"); 322 321 return false; 323 322 } 324 323 if (!parseContentOpf(bookMetadata)) { 325 - Serial.printf("[%lu] [EBP] Could not parse content.opf\n", millis()); 324 + LOG_ERR("EBP", "Could not parse content.opf"); 326 325 return false; 327 326 } 328 327 if (!bookMetadataCache->endContentOpfPass()) { 329 - Serial.printf("[%lu] [EBP] Could not end writing content.opf pass\n", millis()); 328 + LOG_ERR("EBP", "Could not end writing content.opf pass"); 330 329 return false; 331 330 } 332 - Serial.printf("[%lu] [EBP] OPF pass completed in %lu ms\n", millis(), millis() - opfStart); 331 + LOG_DBG("EBP", "OPF pass completed in %lu ms", millis() - opfStart); 333 332 334 333 // TOC Pass - try EPUB 3 nav first, fall back to NCX 335 334 const uint32_t tocStart = millis(); 336 335 if (!bookMetadataCache->beginTocPass()) { 337 - Serial.printf("[%lu] [EBP] Could not begin writing toc pass\n", millis()); 336 + LOG_ERR("EBP", "Could not begin writing toc pass"); 338 337 return false; 339 338 } 340 339 ··· 342 341 343 342 // Try EPUB 3 nav document first (preferred) 344 343 if (!tocNavItem.empty()) { 345 - Serial.printf("[%lu] [EBP] Attempting to parse EPUB 3 nav document\n", millis()); 344 + LOG_DBG("EBP", "Attempting to parse EPUB 3 nav document"); 346 345 tocParsed = parseTocNavFile(); 347 346 } 348 347 349 348 // Fall back to NCX if nav parsing failed or wasn't available 350 349 if (!tocParsed && !tocNcxItem.empty()) { 351 - Serial.printf("[%lu] [EBP] Falling back to NCX TOC\n", millis()); 350 + LOG_DBG("EBP", "Falling back to NCX TOC"); 352 351 tocParsed = parseTocNcxFile(); 353 352 } 354 353 355 354 if (!tocParsed) { 356 - Serial.printf("[%lu] [EBP] Warning: Could not parse any TOC format\n", millis()); 355 + LOG_ERR("EBP", "Warning: Could not parse any TOC format"); 357 356 // Continue anyway - book will work without TOC 358 357 } 359 358 360 359 if (!bookMetadataCache->endTocPass()) { 361 - Serial.printf("[%lu] [EBP] Could not end writing toc pass\n", millis()); 360 + LOG_ERR("EBP", "Could not end writing toc pass"); 362 361 return false; 363 362 } 364 - Serial.printf("[%lu] [EBP] TOC pass completed in %lu ms\n", millis(), millis() - tocStart); 363 + LOG_DBG("EBP", "TOC pass completed in %lu ms", millis() - tocStart); 365 364 366 365 // Close the cache files 367 366 if (!bookMetadataCache->endWrite()) { 368 - Serial.printf("[%lu] [EBP] Could not end writing cache\n", millis()); 367 + LOG_ERR("EBP", "Could not end writing cache"); 369 368 return false; 370 369 } 371 370 372 371 // Build final book.bin 373 372 const uint32_t buildStart = millis(); 374 373 if (!bookMetadataCache->buildBookBin(filepath, bookMetadata)) { 375 - Serial.printf("[%lu] [EBP] Could not update mappings and sizes\n", millis()); 374 + LOG_ERR("EBP", "Could not update mappings and sizes"); 376 375 return false; 377 376 } 378 - Serial.printf("[%lu] [EBP] buildBookBin completed in %lu ms\n", millis(), millis() - buildStart); 379 - Serial.printf("[%lu] [EBP] Total indexing completed in %lu ms\n", millis(), millis() - indexingStart); 377 + LOG_DBG("EBP", "buildBookBin completed in %lu ms", millis() - buildStart); 378 + LOG_DBG("EBP", "Total indexing completed in %lu ms", millis() - indexingStart); 380 379 381 380 if (!bookMetadataCache->cleanupTmpFiles()) { 382 - Serial.printf("[%lu] [EBP] Could not cleanup tmp files - ignoring\n", millis()); 381 + LOG_DBG("EBP", "Could not cleanup tmp files - ignoring"); 383 382 } 384 383 385 384 // Reload the cache from disk so it's in the correct state 386 385 bookMetadataCache.reset(new BookMetadataCache(cachePath)); 387 386 if (!bookMetadataCache->load()) { 388 - Serial.printf("[%lu] [EBP] Failed to reload cache after writing\n", millis()); 387 + LOG_ERR("EBP", "Failed to reload cache after writing"); 389 388 return false; 390 389 } 391 390 ··· 394 393 parseCssFiles(); 395 394 } 396 395 397 - Serial.printf("[%lu] [EBP] Loaded ePub: %s\n", millis(), filepath.c_str()); 396 + LOG_DBG("EBP", "Loaded ePub: %s", filepath.c_str()); 398 397 return true; 399 398 } 400 399 401 400 bool Epub::clearCache() const { 402 401 if (!Storage.exists(cachePath.c_str())) { 403 - Serial.printf("[%lu] [EPB] Cache does not exist, no action needed\n", millis()); 402 + LOG_DBG("EPB", "Cache does not exist, no action needed"); 404 403 return true; 405 404 } 406 405 407 406 if (!Storage.removeDir(cachePath.c_str())) { 408 - Serial.printf("[%lu] [EPB] Failed to clear cache\n", millis()); 407 + LOG_ERR("EPB", "Failed to clear cache"); 409 408 return false; 410 409 } 411 410 412 - Serial.printf("[%lu] [EPB] Cache cleared successfully\n", millis()); 411 + LOG_DBG("EPB", "Cache cleared successfully"); 413 412 return true; 414 413 } 415 414 ··· 464 463 } 465 464 466 465 if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { 467 - Serial.printf("[%lu] [EBP] Cannot generate cover BMP, cache not loaded\n", millis()); 466 + LOG_ERR("EBP", "Cannot generate cover BMP, cache not loaded"); 468 467 return false; 469 468 } 470 469 471 470 const auto coverImageHref = bookMetadataCache->coreMetadata.coverItemHref; 472 471 if (coverImageHref.empty()) { 473 - Serial.printf("[%lu] [EBP] No known cover image\n", millis()); 472 + LOG_ERR("EBP", "No known cover image"); 474 473 return false; 475 474 } 476 475 477 476 if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" || 478 477 coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") { 479 - Serial.printf("[%lu] [EBP] Generating BMP from JPG cover image (%s mode)\n", millis(), cropped ? "cropped" : "fit"); 478 + LOG_DBG("EBP", "Generating BMP from JPG cover image (%s mode)", cropped ? "cropped" : "fit"); 480 479 const auto coverJpgTempPath = getCachePath() + "/.cover.jpg"; 481 480 482 481 FsFile coverJpg; ··· 501 500 Storage.remove(coverJpgTempPath.c_str()); 502 501 503 502 if (!success) { 504 - Serial.printf("[%lu] [EBP] Failed to generate BMP from JPG cover image\n", millis()); 503 + LOG_ERR("EBP", "Failed to generate BMP from cover image"); 505 504 Storage.remove(getCoverBmpPath(cropped).c_str()); 506 505 } 507 - Serial.printf("[%lu] [EBP] Generated BMP from JPG cover image, success: %s\n", millis(), success ? "yes" : "no"); 506 + LOG_DBG("EBP", "Generated BMP from cover image, success: %s", success ? "yes" : "no"); 508 507 return success; 509 508 } else { 510 - Serial.printf("[%lu] [EBP] Cover image is not a JPG, skipping\n", millis()); 509 + LOG_ERR("EBP", "Cover image is not a supported format, skipping"); 511 510 } 512 511 513 512 return false; ··· 523 522 } 524 523 525 524 if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { 526 - Serial.printf("[%lu] [EBP] Cannot generate thumb BMP, cache not loaded\n", millis()); 525 + LOG_ERR("EBP", "Cannot generate thumb BMP, cache not loaded"); 527 526 return false; 528 527 } 529 528 530 529 const auto coverImageHref = bookMetadataCache->coreMetadata.coverItemHref; 531 530 if (coverImageHref.empty()) { 532 - Serial.printf("[%lu] [EBP] No known cover image for thumbnail\n", millis()); 531 + LOG_DBG("EBP", "No known cover image for thumbnail"); 533 532 } else if (coverImageHref.substr(coverImageHref.length() - 4) == ".jpg" || 534 533 coverImageHref.substr(coverImageHref.length() - 5) == ".jpeg") { 535 - Serial.printf("[%lu] [EBP] Generating thumb BMP from JPG cover image\n", millis()); 534 + LOG_DBG("EBP", "Generating thumb BMP from JPG cover image"); 536 535 const auto coverJpgTempPath = getCachePath() + "/.cover.jpg"; 537 536 538 537 FsFile coverJpg; ··· 562 561 Storage.remove(coverJpgTempPath.c_str()); 563 562 564 563 if (!success) { 565 - Serial.printf("[%lu] [EBP] Failed to generate thumb BMP from JPG cover image\n", millis()); 564 + LOG_ERR("EBP", "Failed to generate thumb BMP from JPG cover image"); 566 565 Storage.remove(getThumbBmpPath(height).c_str()); 567 566 } 568 - Serial.printf("[%lu] [EBP] Generated thumb BMP from JPG cover image, success: %s\n", millis(), 569 - success ? "yes" : "no"); 567 + LOG_DBG("EBP", "Generated thumb BMP from JPG cover image, success: %s", success ? "yes" : "no"); 570 568 return success; 571 569 } else { 572 - Serial.printf("[%lu] [EBP] Cover image is not a JPG, skipping thumbnail\n", millis()); 570 + LOG_ERR("EBP", "Cover image is not a supported format, skipping thumbnail"); 573 571 } 574 572 575 573 // Write an empty bmp file to avoid generation attempts in the future ··· 581 579 582 580 uint8_t* Epub::readItemContentsToBytes(const std::string& itemHref, size_t* size, const bool trailingNullByte) const { 583 581 if (itemHref.empty()) { 584 - Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis()); 582 + LOG_DBG("EBP", "Failed to read item, empty href"); 585 583 return nullptr; 586 584 } 587 585 ··· 589 587 590 588 const auto content = ZipFile(filepath).readFileToMemory(path.c_str(), size, trailingNullByte); 591 589 if (!content) { 592 - Serial.printf("[%lu] [EBP] Failed to read item %s\n", millis(), path.c_str()); 590 + LOG_DBG("EBP", "Failed to read item %s", path.c_str()); 593 591 return nullptr; 594 592 } 595 593 ··· 598 596 599 597 bool Epub::readItemContentsToStream(const std::string& itemHref, Print& out, const size_t chunkSize) const { 600 598 if (itemHref.empty()) { 601 - Serial.printf("[%lu] [EBP] Failed to read item, empty href\n", millis()); 599 + LOG_DBG("EBP", "Failed to read item, empty href"); 602 600 return false; 603 601 } 604 602 ··· 622 620 623 621 BookMetadataCache::SpineEntry Epub::getSpineItem(const int spineIndex) const { 624 622 if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { 625 - Serial.printf("[%lu] [EBP] getSpineItem called but cache not loaded\n", millis()); 623 + LOG_ERR("EBP", "getSpineItem called but cache not loaded"); 626 624 return {}; 627 625 } 628 626 629 627 if (spineIndex < 0 || spineIndex >= bookMetadataCache->getSpineCount()) { 630 - Serial.printf("[%lu] [EBP] getSpineItem index:%d is out of range\n", millis(), spineIndex); 628 + LOG_ERR("EBP", "getSpineItem index:%d is out of range", spineIndex); 631 629 return bookMetadataCache->getSpineEntry(0); 632 630 } 633 631 ··· 636 634 637 635 BookMetadataCache::TocEntry Epub::getTocItem(const int tocIndex) const { 638 636 if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { 639 - Serial.printf("[%lu] [EBP] getTocItem called but cache not loaded\n", millis()); 637 + LOG_DBG("EBP", "getTocItem called but cache not loaded"); 640 638 return {}; 641 639 } 642 640 643 641 if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) { 644 - Serial.printf("[%lu] [EBP] getTocItem index:%d is out of range\n", millis(), tocIndex); 642 + LOG_DBG("EBP", "getTocItem index:%d is out of range", tocIndex); 645 643 return {}; 646 644 } 647 645 ··· 659 657 // work out the section index for a toc index 660 658 int Epub::getSpineIndexForTocIndex(const int tocIndex) const { 661 659 if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { 662 - Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex called but cache not loaded\n", millis()); 660 + LOG_ERR("EBP", "getSpineIndexForTocIndex called but cache not loaded"); 663 661 return 0; 664 662 } 665 663 666 664 if (tocIndex < 0 || tocIndex >= bookMetadataCache->getTocCount()) { 667 - Serial.printf("[%lu] [EBP] getSpineIndexForTocIndex: tocIndex %d out of range\n", millis(), tocIndex); 665 + LOG_ERR("EBP", "getSpineIndexForTocIndex: tocIndex %d out of range", tocIndex); 668 666 return 0; 669 667 } 670 668 671 669 const int spineIndex = bookMetadataCache->getTocEntry(tocIndex).spineIndex; 672 670 if (spineIndex < 0) { 673 - Serial.printf("[%lu] [EBP] Section not found for TOC index %d\n", millis(), tocIndex); 671 + LOG_DBG("EBP", "Section not found for TOC index %d", tocIndex); 674 672 return 0; 675 673 } 676 674 ··· 688 686 689 687 int Epub::getSpineIndexForTextReference() const { 690 688 if (!bookMetadataCache || !bookMetadataCache->isLoaded()) { 691 - Serial.printf("[%lu] [EBP] getSpineIndexForTextReference called but cache not loaded\n", millis()); 689 + LOG_ERR("EBP", "getSpineIndexForTextReference called but cache not loaded"); 692 690 return 0; 693 691 } 694 - Serial.printf("[%lu] [ERS] Core Metadata: cover(%d)=%s, textReference(%d)=%s\n", millis(), 695 - bookMetadataCache->coreMetadata.coverItemHref.size(), 696 - bookMetadataCache->coreMetadata.coverItemHref.c_str(), 697 - bookMetadataCache->coreMetadata.textReferenceHref.size(), 698 - bookMetadataCache->coreMetadata.textReferenceHref.c_str()); 692 + LOG_DBG("EBP", "Core Metadata: cover(%d)=%s, textReference(%d)=%s", 693 + bookMetadataCache->coreMetadata.coverItemHref.size(), bookMetadataCache->coreMetadata.coverItemHref.c_str(), 694 + bookMetadataCache->coreMetadata.textReferenceHref.size(), 695 + bookMetadataCache->coreMetadata.textReferenceHref.c_str()); 699 696 700 697 if (bookMetadataCache->coreMetadata.textReferenceHref.empty()) { 701 698 // there was no textReference in epub, so we return 0 (the first chapter) ··· 705 702 // loop through spine items to get the correct index matching the text href 706 703 for (size_t i = 0; i < getSpineItemsCount(); i++) { 707 704 if (getSpineItem(i).href == bookMetadataCache->coreMetadata.textReferenceHref) { 708 - Serial.printf("[%lu] [ERS] Text reference %s found at index %d\n", millis(), 709 - bookMetadataCache->coreMetadata.textReferenceHref.c_str(), i); 705 + LOG_DBG("EBP", "Text reference %s found at index %d", bookMetadataCache->coreMetadata.textReferenceHref.c_str(), 706 + i); 710 707 return i; 711 708 } 712 709 } 713 710 // This should not happen, as we checked for empty textReferenceHref earlier 714 - Serial.printf("[%lu] [EBP] Section not found for text reference\n", millis()); 711 + LOG_DBG("EBP", "Section not found for text reference"); 715 712 return 0; 716 713 } 717 714
+25 -26
lib/Epub/Epub/BookMetadataCache.cpp
··· 1 1 #include "BookMetadataCache.h" 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 #include <Serialization.h> 5 5 #include <ZipFile.h> 6 6 ··· 21 21 buildMode = true; 22 22 spineCount = 0; 23 23 tocCount = 0; 24 - Serial.printf("[%lu] [BMC] Entering write mode\n", millis()); 24 + LOG_DBG("BMC", "Entering write mode"); 25 25 return true; 26 26 } 27 27 28 28 bool BookMetadataCache::beginContentOpfPass() { 29 - Serial.printf("[%lu] [BMC] Beginning content opf pass\n", millis()); 29 + LOG_DBG("BMC", "Beginning content opf pass"); 30 30 31 31 // Open spine file for writing 32 32 return Storage.openFileForWrite("BMC", cachePath + tmpSpineBinFile, spineFile); ··· 38 38 } 39 39 40 40 bool BookMetadataCache::beginTocPass() { 41 - Serial.printf("[%lu] [BMC] Beginning toc pass\n", millis()); 41 + LOG_DBG("BMC", "Beginning toc pass"); 42 42 43 43 if (!Storage.openFileForRead("BMC", cachePath + tmpSpineBinFile, spineFile)) { 44 44 return false; ··· 66 66 }); 67 67 spineFile.seek(0); 68 68 useSpineHrefIndex = true; 69 - Serial.printf("[%lu] [BMC] Using fast index for %d spine items\n", millis(), spineCount); 69 + LOG_DBG("BMC", "Using fast index for %d spine items", spineCount); 70 70 } else { 71 71 useSpineHrefIndex = false; 72 72 } ··· 87 87 88 88 bool BookMetadataCache::endWrite() { 89 89 if (!buildMode) { 90 - Serial.printf("[%lu] [BMC] endWrite called but not in build mode\n", millis()); 90 + LOG_DBG("BMC", "endWrite called but not in build mode"); 91 91 return false; 92 92 } 93 93 94 94 buildMode = false; 95 - Serial.printf("[%lu] [BMC] Wrote %d spine, %d TOC entries\n", millis(), spineCount, tocCount); 95 + LOG_DBG("BMC", "Wrote %d spine, %d TOC entries", spineCount, tocCount); 96 96 return true; 97 97 } 98 98 ··· 167 167 ZipFile zip(epubPath); 168 168 // Pre-open zip file to speed up size calculations 169 169 if (!zip.open()) { 170 - Serial.printf("[%lu] [BMC] Could not open EPUB zip for size calculations\n", millis()); 170 + LOG_ERR("BMC", "Could not open EPUB zip for size calculations"); 171 171 bookFile.close(); 172 172 spineFile.close(); 173 173 tocFile.close(); ··· 185 185 bool useBatchSizes = false; 186 186 187 187 if (spineCount >= LARGE_SPINE_THRESHOLD) { 188 - Serial.printf("[%lu] [BMC] Using batch size lookup for %d spine items\n", millis(), spineCount); 188 + LOG_DBG("BMC", "Using batch size lookup for %d spine items", spineCount); 189 189 190 190 std::vector<ZipFile::SizeTarget> targets; 191 191 targets.reserve(spineCount); ··· 208 208 209 209 spineSizes.resize(spineCount, 0); 210 210 int matched = zip.fillUncompressedSizes(targets, spineSizes); 211 - Serial.printf("[%lu] [BMC] Batch lookup matched %d/%d spine items\n", millis(), matched, spineCount); 211 + LOG_DBG("BMC", "Batch lookup matched %d/%d spine items", matched, spineCount); 212 212 213 213 targets.clear(); 214 214 targets.shrink_to_fit(); ··· 227 227 // Not a huge deal if we don't fine a TOC entry for the spine entry, this is expected behaviour for EPUBs 228 228 // Logging here is for debugging 229 229 if (spineEntry.tocIndex == -1) { 230 - Serial.printf( 231 - "[%lu] [BMC] Warning: Could not find TOC entry for spine item %d: %s, using title from last section\n", 232 - millis(), i, spineEntry.href.c_str()); 230 + LOG_DBG("BMC", "Warning: Could not find TOC entry for spine item %d: %s, using title from last section", i, 231 + spineEntry.href.c_str()); 233 232 spineEntry.tocIndex = lastSpineTocIndex; 234 233 } 235 234 lastSpineTocIndex = spineEntry.tocIndex; ··· 240 239 if (itemSize == 0) { 241 240 const std::string path = FsHelpers::normalisePath(spineEntry.href); 242 241 if (!zip.getInflatedFileSize(path.c_str(), &itemSize)) { 243 - Serial.printf("[%lu] [BMC] Warning: Could not get size for spine item: %s\n", millis(), path.c_str()); 242 + LOG_ERR("BMC", "Warning: Could not get size for spine item: %s", path.c_str()); 244 243 } 245 244 } 246 245 } else { 247 246 const std::string path = FsHelpers::normalisePath(spineEntry.href); 248 247 if (!zip.getInflatedFileSize(path.c_str(), &itemSize)) { 249 - Serial.printf("[%lu] [BMC] Warning: Could not get size for spine item: %s\n", millis(), path.c_str()); 248 + LOG_ERR("BMC", "Warning: Could not get size for spine item: %s", path.c_str()); 250 249 } 251 250 } 252 251 ··· 270 269 spineFile.close(); 271 270 tocFile.close(); 272 271 273 - Serial.printf("[%lu] [BMC] Successfully built book.bin\n", millis()); 272 + LOG_DBG("BMC", "Successfully built book.bin"); 274 273 return true; 275 274 } 276 275 ··· 306 305 // this is because in this function we're marking positions of the items 307 306 void BookMetadataCache::createSpineEntry(const std::string& href) { 308 307 if (!buildMode || !spineFile) { 309 - Serial.printf("[%lu] [BMC] createSpineEntry called but not in build mode\n", millis()); 308 + LOG_DBG("BMC", "createSpineEntry called but not in build mode"); 310 309 return; 311 310 } 312 311 ··· 318 317 void BookMetadataCache::createTocEntry(const std::string& title, const std::string& href, const std::string& anchor, 319 318 const uint8_t level) { 320 319 if (!buildMode || !tocFile || !spineFile) { 321 - Serial.printf("[%lu] [BMC] createTocEntry called but not in build mode\n", millis()); 320 + LOG_DBG("BMC", "createTocEntry called but not in build mode"); 322 321 return; 323 322 } 324 323 ··· 340 339 } 341 340 342 341 if (spineIndex == -1) { 343 - Serial.printf("[%lu] [BMC] createTocEntry: Could not find spine item for TOC href %s\n", millis(), href.c_str()); 342 + LOG_DBG("BMC", "createTocEntry: Could not find spine item for TOC href %s", href.c_str()); 344 343 } 345 344 } else { 346 345 spineFile.seek(0); ··· 352 351 } 353 352 } 354 353 if (spineIndex == -1) { 355 - Serial.printf("[%lu] [BMC] createTocEntry: Could not find spine item for TOC href %s\n", millis(), href.c_str()); 354 + LOG_DBG("BMC", "createTocEntry: Could not find spine item for TOC href %s", href.c_str()); 356 355 } 357 356 } 358 357 ··· 371 370 uint8_t version; 372 371 serialization::readPod(bookFile, version); 373 372 if (version != BOOK_CACHE_VERSION) { 374 - Serial.printf("[%lu] [BMC] Cache version mismatch: expected %d, got %d\n", millis(), BOOK_CACHE_VERSION, version); 373 + LOG_DBG("BMC", "Cache version mismatch: expected %d, got %d", BOOK_CACHE_VERSION, version); 375 374 bookFile.close(); 376 375 return false; 377 376 } ··· 387 386 serialization::readString(bookFile, coreMetadata.textReferenceHref); 388 387 389 388 loaded = true; 390 - Serial.printf("[%lu] [BMC] Loaded cache data: %d spine, %d TOC entries\n", millis(), spineCount, tocCount); 389 + LOG_DBG("BMC", "Loaded cache data: %d spine, %d TOC entries", spineCount, tocCount); 391 390 return true; 392 391 } 393 392 394 393 BookMetadataCache::SpineEntry BookMetadataCache::getSpineEntry(const int index) { 395 394 if (!loaded) { 396 - Serial.printf("[%lu] [BMC] getSpineEntry called but cache not loaded\n", millis()); 395 + LOG_ERR("BMC", "getSpineEntry called but cache not loaded"); 397 396 return {}; 398 397 } 399 398 400 399 if (index < 0 || index >= static_cast<int>(spineCount)) { 401 - Serial.printf("[%lu] [BMC] getSpineEntry index %d out of range\n", millis(), index); 400 + LOG_ERR("BMC", "getSpineEntry index %d out of range", index); 402 401 return {}; 403 402 } 404 403 ··· 412 411 413 412 BookMetadataCache::TocEntry BookMetadataCache::getTocEntry(const int index) { 414 413 if (!loaded) { 415 - Serial.printf("[%lu] [BMC] getTocEntry called but cache not loaded\n", millis()); 414 + LOG_ERR("BMC", "getTocEntry called but cache not loaded"); 416 415 return {}; 417 416 } 418 417 419 418 if (index < 0 || index >= static_cast<int>(tocCount)) { 420 - Serial.printf("[%lu] [BMC] getTocEntry index %d out of range\n", millis(), index); 419 + LOG_ERR("BMC", "getTocEntry index %d out of range", index); 421 420 return {}; 422 421 } 423 422
+2 -2
lib/Epub/Epub/Page.cpp
··· 1 1 #include "Page.h" 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 #include <Serialization.h> 5 5 6 6 void PageLine::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) { ··· 60 60 auto pl = PageLine::deserialize(file); 61 61 page->elements.push_back(std::move(pl)); 62 62 } else { 63 - Serial.printf("[%lu] [PGE] Deserialization failed: Unknown tag %u\n", millis(), tag); 63 + LOG_ERR("PGE", "Deserialization failed: Unknown tag %u", tag); 64 64 return nullptr; 65 65 } 66 66 }
+17 -16
lib/Epub/Epub/Section.cpp
··· 1 1 #include "Section.h" 2 2 3 3 #include <HalStorage.h> 4 + #include <Logging.h> 4 5 #include <Serialization.h> 5 6 6 7 #include "Page.h" ··· 16 17 17 18 uint32_t Section::onPageComplete(std::unique_ptr<Page> page) { 18 19 if (!file) { 19 - Serial.printf("[%lu] [SCT] File not open for writing page %d\n", millis(), pageCount); 20 + LOG_ERR("SCT", "File not open for writing page %d", pageCount); 20 21 return 0; 21 22 } 22 23 23 24 const uint32_t position = file.position(); 24 25 if (!page->serialize(file)) { 25 - Serial.printf("[%lu] [SCT] Failed to serialize page %d\n", millis(), pageCount); 26 + LOG_ERR("SCT", "Failed to serialize page %d", pageCount); 26 27 return 0; 27 28 } 28 - Serial.printf("[%lu] [SCT] Page %d processed\n", millis(), pageCount); 29 + LOG_DBG("SCT", "Page %d processed", pageCount); 29 30 30 31 pageCount++; 31 32 return position; ··· 36 37 const uint16_t viewportHeight, const bool hyphenationEnabled, 37 38 const bool embeddedStyle) { 38 39 if (!file) { 39 - Serial.printf("[%lu] [SCT] File not open for writing header\n", millis()); 40 + LOG_DBG("SCT", "File not open for writing header"); 40 41 return; 41 42 } 42 43 static_assert(HEADER_SIZE == sizeof(SECTION_FILE_VERSION) + sizeof(fontId) + sizeof(lineCompression) + ··· 70 71 serialization::readPod(file, version); 71 72 if (version != SECTION_FILE_VERSION) { 72 73 file.close(); 73 - Serial.printf("[%lu] [SCT] Deserialization failed: Unknown version %u\n", millis(), version); 74 + LOG_ERR("SCT", "Deserialization failed: Unknown version %u", version); 74 75 clearCache(); 75 76 return false; 76 77 } ··· 96 97 viewportWidth != fileViewportWidth || viewportHeight != fileViewportHeight || 97 98 hyphenationEnabled != fileHyphenationEnabled || embeddedStyle != fileEmbeddedStyle) { 98 99 file.close(); 99 - Serial.printf("[%lu] [SCT] Deserialization failed: Parameters do not match\n", millis()); 100 + LOG_ERR("SCT", "Deserialization failed: Parameters do not match"); 100 101 clearCache(); 101 102 return false; 102 103 } ··· 104 105 105 106 serialization::readPod(file, pageCount); 106 107 file.close(); 107 - Serial.printf("[%lu] [SCT] Deserialization succeeded: %d pages\n", millis(), pageCount); 108 + LOG_DBG("SCT", "Deserialization succeeded: %d pages", pageCount); 108 109 return true; 109 110 } 110 111 111 112 // Your updated class method (assuming you are using the 'SD' object, which is a wrapper for a specific filesystem) 112 113 bool Section::clearCache() const { 113 114 if (!Storage.exists(filePath.c_str())) { 114 - Serial.printf("[%lu] [SCT] Cache does not exist, no action needed\n", millis()); 115 + LOG_DBG("SCT", "Cache does not exist, no action needed"); 115 116 return true; 116 117 } 117 118 118 119 if (!Storage.remove(filePath.c_str())) { 119 - Serial.printf("[%lu] [SCT] Failed to clear cache\n", millis()); 120 + LOG_ERR("SCT", "Failed to clear cache"); 120 121 return false; 121 122 } 122 123 123 - Serial.printf("[%lu] [SCT] Cache cleared successfully\n", millis()); 124 + LOG_DBG("SCT", "Cache cleared successfully"); 124 125 return true; 125 126 } 126 127 ··· 142 143 uint32_t fileSize = 0; 143 144 for (int attempt = 0; attempt < 3 && !success; attempt++) { 144 145 if (attempt > 0) { 145 - Serial.printf("[%lu] [SCT] Retrying stream (attempt %d)...\n", millis(), attempt + 1); 146 + LOG_DBG("SCT", "Retrying stream (attempt %d)...", attempt + 1); 146 147 delay(50); // Brief delay before retry 147 148 } 148 149 ··· 162 163 // If streaming failed, remove the incomplete file immediately 163 164 if (!success && Storage.exists(tmpHtmlPath.c_str())) { 164 165 Storage.remove(tmpHtmlPath.c_str()); 165 - Serial.printf("[%lu] [SCT] Removed incomplete temp file after failed attempt\n", millis()); 166 + LOG_DBG("SCT", "Removed incomplete temp file after failed attempt"); 166 167 } 167 168 } 168 169 169 170 if (!success) { 170 - Serial.printf("[%lu] [SCT] Failed to stream item contents to temp file after retries\n", millis()); 171 + LOG_ERR("SCT", "Failed to stream item contents to temp file after retries"); 171 172 return false; 172 173 } 173 174 174 - Serial.printf("[%lu] [SCT] Streamed temp HTML to %s (%d bytes)\n", millis(), tmpHtmlPath.c_str(), fileSize); 175 + LOG_DBG("SCT", "Streamed temp HTML to %s (%d bytes)", tmpHtmlPath.c_str(), fileSize); 175 176 176 177 if (!Storage.openFileForWrite("SCT", filePath, file)) { 177 178 return false; ··· 190 191 191 192 Storage.remove(tmpHtmlPath.c_str()); 192 193 if (!success) { 193 - Serial.printf("[%lu] [SCT] Failed to parse XML and build pages\n", millis()); 194 + LOG_ERR("SCT", "Failed to parse XML and build pages"); 194 195 file.close(); 195 196 Storage.remove(filePath.c_str()); 196 197 return false; ··· 208 209 } 209 210 210 211 if (hasFailedLutRecords) { 211 - Serial.printf("[%lu] [SCT] Failed to write LUT due to invalid page positions\n", millis()); 212 + LOG_ERR("SCT", "Failed to write LUT due to invalid page positions"); 212 213 file.close(); 213 214 Storage.remove(filePath.c_str()); 214 215 return false;
+6 -5
lib/Epub/Epub/blocks/TextBlock.cpp
··· 1 1 #include "TextBlock.h" 2 2 3 3 #include <GfxRenderer.h> 4 + #include <Logging.h> 4 5 #include <Serialization.h> 5 6 6 7 void TextBlock::render(const GfxRenderer& renderer, const int fontId, const int x, const int y) const { 7 8 // Validate iterator bounds before rendering 8 9 if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) { 9 - Serial.printf("[%lu] [TXB] Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), 10 - (uint32_t)words.size(), (uint32_t)wordXpos.size(), (uint32_t)wordStyles.size()); 10 + LOG_ERR("TXB", "Render skipped: size mismatch (words=%u, xpos=%u, styles=%u)\n", (uint32_t)words.size(), 11 + (uint32_t)wordXpos.size(), (uint32_t)wordStyles.size()); 11 12 return; 12 13 } 13 14 ··· 49 50 50 51 bool TextBlock::serialize(FsFile& file) const { 51 52 if (words.size() != wordXpos.size() || words.size() != wordStyles.size()) { 52 - Serial.printf("[%lu] [TXB] Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", millis(), 53 - words.size(), wordXpos.size(), wordStyles.size()); 53 + LOG_ERR("TXB", "Serialization failed: size mismatch (words=%u, xpos=%u, styles=%u)\n", words.size(), 54 + wordXpos.size(), wordStyles.size()); 54 55 return false; 55 56 } 56 57 ··· 89 90 90 91 // Sanity check: prevent allocation of unreasonably large lists (max 10000 words per block) 91 92 if (wc > 10000) { 92 - Serial.printf("[%lu] [TXB] Deserialization failed: word count %u exceeds maximum\n", millis(), wc); 93 + LOG_ERR("TXB", "Deserialization failed: word count %u exceeds maximum", wc); 93 94 return nullptr; 94 95 } 95 96
+6 -6
lib/Epub/Epub/css/CssParser.cpp
··· 1 1 #include "CssParser.h" 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 5 5 #include <algorithm> 6 6 #include <cctype> ··· 449 449 450 450 bool CssParser::loadFromStream(FsFile& source) { 451 451 if (!source) { 452 - Serial.printf("[%lu] [CSS] Cannot read from invalid file\n", millis()); 452 + LOG_ERR("CSS", "Cannot read from invalid file"); 453 453 return false; 454 454 } 455 455 ··· 470 470 processRuleBlock(selector, body); 471 471 } 472 472 473 - Serial.printf("[%lu] [CSS] Parsed %zu rules\n", millis(), rulesBySelector_.size()); 473 + LOG_DBG("CSS", "Parsed %zu rules", rulesBySelector_.size()); 474 474 return true; 475 475 } 476 476 ··· 582 582 file.write(reinterpret_cast<const uint8_t*>(&definedBits), sizeof(definedBits)); 583 583 } 584 584 585 - Serial.printf("[%lu] [CSS] Saved %u rules to cache\n", millis(), ruleCount); 585 + LOG_DBG("CSS", "Saved %u rules to cache", ruleCount); 586 586 return true; 587 587 } 588 588 ··· 597 597 // Read and verify version 598 598 uint8_t version = 0; 599 599 if (file.read(&version, 1) != 1 || version != CSS_CACHE_VERSION) { 600 - Serial.printf("[%lu] [CSS] Cache version mismatch (got %u, expected %u)\n", millis(), version, CSS_CACHE_VERSION); 600 + LOG_DBG("CSS", "Cache version mismatch (got %u, expected %u)", version, CSS_CACHE_VERSION); 601 601 return false; 602 602 } 603 603 ··· 694 694 rulesBySelector_[selector] = style; 695 695 } 696 696 697 - Serial.printf("[%lu] [CSS] Loaded %u rules from cache\n", millis(), ruleCount); 697 + LOG_DBG("CSS", "Loaded %u rules from cache", ruleCount); 698 698 return true; 699 699 }
+9 -9
lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp
··· 2 2 3 3 #include <GfxRenderer.h> 4 4 #include <HalStorage.h> 5 - #include <HardwareSerial.h> 5 + #include <Logging.h> 6 6 #include <expat.h> 7 7 8 8 #include "../Page.h" ··· 168 168 } 169 169 } 170 170 171 - Serial.printf("[%lu] [EHP] Image alt: %s\n", millis(), alt.c_str()); 171 + LOG_DBG("EHP", "Image alt: %s", alt.c_str()); 172 172 173 173 self->startNewTextBlock(centeredBlockStyle); 174 174 self->italicUntilDepth = min(self->italicUntilDepth, self->depth); ··· 386 386 // memory. 387 387 // Spotted when reading Intermezzo, there are some really long text blocks in there. 388 388 if (self->currentTextBlock->size() > 750) { 389 - Serial.printf("[%lu] [EHP] Text block too long, splitting into multiple pages\n", millis()); 389 + LOG_DBG("EHP", "Text block too long, splitting into multiple pages"); 390 390 self->currentTextBlock->layoutAndExtractLines( 391 391 self->renderer, self->fontId, self->viewportWidth, 392 392 [self](const std::shared_ptr<TextBlock>& textBlock) { self->addLineToPage(textBlock); }, false); ··· 477 477 int done; 478 478 479 479 if (!parser) { 480 - Serial.printf("[%lu] [EHP] Couldn't allocate memory for parser\n", millis()); 480 + LOG_ERR("EHP", "Couldn't allocate memory for parser"); 481 481 return false; 482 482 } 483 483 ··· 499 499 do { 500 500 void* const buf = XML_GetBuffer(parser, 1024); 501 501 if (!buf) { 502 - Serial.printf("[%lu] [EHP] Couldn't allocate memory for buffer\n", millis()); 502 + LOG_ERR("EHP", "Couldn't allocate memory for buffer"); 503 503 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 504 504 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 505 505 XML_SetCharacterDataHandler(parser, nullptr); ··· 511 511 const size_t len = file.read(buf, 1024); 512 512 513 513 if (len == 0 && file.available() > 0) { 514 - Serial.printf("[%lu] [EHP] File read error\n", millis()); 514 + LOG_ERR("EHP", "File read error"); 515 515 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 516 516 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 517 517 XML_SetCharacterDataHandler(parser, nullptr); ··· 523 523 done = file.available() == 0; 524 524 525 525 if (XML_ParseBuffer(parser, static_cast<int>(len), done) == XML_STATUS_ERROR) { 526 - Serial.printf("[%lu] [EHP] Parse error at line %lu:\n%s\n", millis(), XML_GetCurrentLineNumber(parser), 527 - XML_ErrorString(XML_GetErrorCode(parser))); 526 + LOG_ERR("EHP", "Parse error at line %lu:\n%s", XML_GetCurrentLineNumber(parser), 527 + XML_ErrorString(XML_GetErrorCode(parser))); 528 528 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 529 529 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 530 530 XML_SetCharacterDataHandler(parser, nullptr); ··· 568 568 569 569 void ChapterHtmlSlimParser::makePages() { 570 570 if (!currentTextBlock) { 571 - Serial.printf("[%lu] [EHP] !! No text block to make pages for !!\n", millis()); 571 + LOG_ERR("EHP", "!! No text block to make pages for !!"); 572 572 return; 573 573 } 574 574
+4 -4
lib/Epub/Epub/parsers/ContainerParser.cpp
··· 1 1 #include "ContainerParser.h" 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 5 5 bool ContainerParser::setup() { 6 6 parser = XML_ParserCreate(nullptr); 7 7 if (!parser) { 8 - Serial.printf("[%lu] [CTR] Couldn't allocate memory for parser\n", millis()); 8 + LOG_ERR("CTR", "Couldn't allocate memory for parser"); 9 9 return false; 10 10 } 11 11 ··· 34 34 while (remainingInBuffer > 0) { 35 35 void* const buf = XML_GetBuffer(parser, 1024); 36 36 if (!buf) { 37 - Serial.printf("[%lu] [CTR] Couldn't allocate buffer\n", millis()); 37 + LOG_DBG("CTR", "Couldn't allocate buffer"); 38 38 return 0; 39 39 } 40 40 ··· 42 42 memcpy(buf, currentBufferPos, toRead); 43 43 44 44 if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) { 45 - Serial.printf("[%lu] [CTR] Parse error: %s\n", millis(), XML_ErrorString(XML_GetErrorCode(parser))); 45 + LOG_ERR("CTR", "Parse error: %s", XML_ErrorString(XML_GetErrorCode(parser))); 46 46 return 0; 47 47 } 48 48
+14 -21
lib/Epub/Epub/parsers/ContentOpfParser.cpp
··· 1 1 #include "ContentOpfParser.h" 2 2 3 3 #include <FsHelpers.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <Serialization.h> 6 6 7 7 #include "../BookMetadataCache.h" ··· 15 15 bool ContentOpfParser::setup() { 16 16 parser = XML_ParserCreate(nullptr); 17 17 if (!parser) { 18 - Serial.printf("[%lu] [COF] Couldn't allocate memory for parser\n", millis()); 18 + LOG_DBG("COF", "Couldn't allocate memory for parser"); 19 19 return false; 20 20 } 21 21 ··· 56 56 void* const buf = XML_GetBuffer(parser, 1024); 57 57 58 58 if (!buf) { 59 - Serial.printf("[%lu] [COF] Couldn't allocate memory for buffer\n", millis()); 59 + LOG_ERR("COF", "Couldn't allocate memory for buffer"); 60 60 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 61 61 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 62 62 XML_SetCharacterDataHandler(parser, nullptr); ··· 69 69 memcpy(buf, currentBufferPos, toRead); 70 70 71 71 if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) { 72 - Serial.printf("[%lu] [COF] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser), 73 - XML_ErrorString(XML_GetErrorCode(parser))); 72 + LOG_DBG("COF", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser), 73 + XML_ErrorString(XML_GetErrorCode(parser))); 74 74 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 75 75 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 76 76 XML_SetCharacterDataHandler(parser, nullptr); ··· 119 119 if (self->state == IN_PACKAGE && (strcmp(name, "manifest") == 0 || strcmp(name, "opf:manifest") == 0)) { 120 120 self->state = IN_MANIFEST; 121 121 if (!Storage.openFileForWrite("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 122 - Serial.printf( 123 - "[%lu] [COF] Couldn't open temp items file for writing. This is probably going to be a fatal error.\n", 124 - millis()); 122 + LOG_ERR("COF", "Couldn't open temp items file for writing. This is probably going to be a fatal error."); 125 123 } 126 124 return; 127 125 } ··· 129 127 if (self->state == IN_PACKAGE && (strcmp(name, "spine") == 0 || strcmp(name, "opf:spine") == 0)) { 130 128 self->state = IN_SPINE; 131 129 if (!Storage.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 132 - Serial.printf( 133 - "[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n", 134 - millis()); 130 + LOG_ERR("COF", "Couldn't open temp items file for reading. This is probably going to be a fatal error."); 135 131 } 136 132 137 133 // Sort item index for binary search if we have enough items ··· 140 136 return a.idHash < b.idHash || (a.idHash == b.idHash && a.idLen < b.idLen); 141 137 }); 142 138 self->useItemIndex = true; 143 - Serial.printf("[%lu] [COF] Using fast index for %zu manifest items\n", millis(), self->itemIndex.size()); 139 + LOG_DBG("COF", "Using fast index for %zu manifest items", self->itemIndex.size()); 144 140 } 145 141 return; 146 142 } ··· 148 144 if (self->state == IN_PACKAGE && (strcmp(name, "guide") == 0 || strcmp(name, "opf:guide") == 0)) { 149 145 self->state = IN_GUIDE; 150 146 // TODO Remove print 151 - Serial.printf("[%lu] [COF] Entering guide state.\n", millis()); 147 + LOG_DBG("COF", "Entering guide state."); 152 148 if (!Storage.openFileForRead("COF", self->cachePath + itemCacheFile, self->tempItemStore)) { 153 - Serial.printf( 154 - "[%lu] [COF] Couldn't open temp items file for reading. This is probably going to be a fatal error.\n", 155 - millis()); 149 + LOG_ERR("COF", "Couldn't open temp items file for reading. This is probably going to be a fatal error."); 156 150 } 157 151 return; 158 152 } ··· 214 208 if (self->tocNcxPath.empty()) { 215 209 self->tocNcxPath = href; 216 210 } else { 217 - Serial.printf("[%lu] [COF] Warning: Multiple NCX files found in manifest. Ignoring duplicate: %s\n", millis(), 218 - href.c_str()); 211 + LOG_DBG("COF", "Warning: Multiple NCX files found in manifest. Ignoring duplicate: %s", href.c_str()); 219 212 } 220 213 } 221 214 ··· 229 222 // Properties is space-separated, check if "nav" is present as a word 230 223 if (properties == "nav" || properties.find("nav ") == 0 || properties.find(" nav") != std::string::npos) { 231 224 self->tocNavPath = href; 232 - Serial.printf("[%lu] [COF] Found EPUB 3 nav document: %s\n", millis(), href.c_str()); 225 + LOG_DBG("COF", "Found EPUB 3 nav document: %s", href.c_str()); 233 226 } 234 227 } 235 228 ··· 310 303 if (type == "text" || type == "start") { 311 304 continue; 312 305 } else { 313 - Serial.printf("[%lu] [COF] Skipping non-text reference in guide: %s\n", millis(), type.c_str()); 306 + LOG_DBG("COF", "Skipping non-text reference in guide: %s", type.c_str()); 314 307 break; 315 308 } 316 309 } else if (strcmp(atts[i], "href") == 0) { ··· 318 311 } 319 312 } 320 313 if ((type == "text" || (type == "start" && !self->textReferenceHref.empty())) && (textHref.length() > 0)) { 321 - Serial.printf("[%lu] [COF] Found %s reference in guide: %s.\n", millis(), type.c_str(), textHref.c_str()); 314 + LOG_DBG("COF", "Found %s reference in guide: %s.", type.c_str(), textHref.c_str()); 322 315 self->textReferenceHref = textHref; 323 316 } 324 317 return;
+7 -7
lib/Epub/Epub/parsers/TocNavParser.cpp
··· 1 1 #include "TocNavParser.h" 2 2 3 3 #include <FsHelpers.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 6 6 #include "../BookMetadataCache.h" 7 7 8 8 bool TocNavParser::setup() { 9 9 parser = XML_ParserCreate(nullptr); 10 10 if (!parser) { 11 - Serial.printf("[%lu] [NAV] Couldn't allocate memory for parser\n", millis()); 11 + LOG_DBG("NAV", "Couldn't allocate memory for parser"); 12 12 return false; 13 13 } 14 14 ··· 39 39 while (remainingInBuffer > 0) { 40 40 void* const buf = XML_GetBuffer(parser, 1024); 41 41 if (!buf) { 42 - Serial.printf("[%lu] [NAV] Couldn't allocate memory for buffer\n", millis()); 42 + LOG_DBG("NAV", "Couldn't allocate memory for buffer"); 43 43 XML_StopParser(parser, XML_FALSE); 44 44 XML_SetElementHandler(parser, nullptr, nullptr); 45 45 XML_SetCharacterDataHandler(parser, nullptr); ··· 52 52 memcpy(buf, currentBufferPos, toRead); 53 53 54 54 if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) { 55 - Serial.printf("[%lu] [NAV] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser), 56 - XML_ErrorString(XML_GetErrorCode(parser))); 55 + LOG_DBG("NAV", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser), 56 + XML_ErrorString(XML_GetErrorCode(parser))); 57 57 XML_StopParser(parser, XML_FALSE); 58 58 XML_SetElementHandler(parser, nullptr, nullptr); 59 59 XML_SetCharacterDataHandler(parser, nullptr); ··· 88 88 for (int i = 0; atts[i]; i += 2) { 89 89 if ((strcmp(atts[i], "epub:type") == 0 || strcmp(atts[i], "type") == 0) && strcmp(atts[i + 1], "toc") == 0) { 90 90 self->state = IN_NAV_TOC; 91 - Serial.printf("[%lu] [NAV] Found nav toc element\n", millis()); 91 + LOG_DBG("NAV", "Found nav toc element"); 92 92 return; 93 93 } 94 94 } ··· 179 179 180 180 if (strcmp(name, "nav") == 0 && self->state >= IN_NAV_TOC) { 181 181 self->state = IN_BODY; 182 - Serial.printf("[%lu] [NAV] Finished parsing nav toc\n", millis()); 182 + LOG_DBG("NAV", "Finished parsing nav toc"); 183 183 return; 184 184 } 185 185 }
+5 -5
lib/Epub/Epub/parsers/TocNcxParser.cpp
··· 1 1 #include "TocNcxParser.h" 2 2 3 3 #include <FsHelpers.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 6 6 #include "../BookMetadataCache.h" 7 7 8 8 bool TocNcxParser::setup() { 9 9 parser = XML_ParserCreate(nullptr); 10 10 if (!parser) { 11 - Serial.printf("[%lu] [TOC] Couldn't allocate memory for parser\n", millis()); 11 + LOG_DBG("TOC", "Couldn't allocate memory for parser"); 12 12 return false; 13 13 } 14 14 ··· 39 39 while (remainingInBuffer > 0) { 40 40 void* const buf = XML_GetBuffer(parser, 1024); 41 41 if (!buf) { 42 - Serial.printf("[%lu] [TOC] Couldn't allocate memory for buffer\n", millis()); 42 + LOG_DBG("TOC", "Couldn't allocate memory for buffer"); 43 43 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 44 44 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 45 45 XML_SetCharacterDataHandler(parser, nullptr); ··· 52 52 memcpy(buf, currentBufferPos, toRead); 53 53 54 54 if (XML_ParseBuffer(parser, static_cast<int>(toRead), remainingSize == toRead) == XML_STATUS_ERROR) { 55 - Serial.printf("[%lu] [TOC] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser), 56 - XML_ErrorString(XML_GetErrorCode(parser))); 55 + LOG_DBG("TOC", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser), 56 + XML_ErrorString(XML_GetErrorCode(parser))); 57 57 XML_StopParser(parser, XML_FALSE); // Stop any pending processing 58 58 XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks 59 59 XML_SetCharacterDataHandler(parser, nullptr);
+27 -29
lib/GfxRenderer/GfxRenderer.cpp
··· 1 1 #include "GfxRenderer.h" 2 2 3 + #include <Logging.h> 3 4 #include <Utf8.h> 4 5 5 6 void GfxRenderer::begin() { 6 7 frameBuffer = display.getFrameBuffer(); 7 8 if (!frameBuffer) { 8 - Serial.printf("[%lu] [GFX] !! No framebuffer\n", millis()); 9 + LOG_ERR("GFX", "!! No framebuffer"); 9 10 assert(false); 10 11 } 11 12 } ··· 57 58 58 59 // Bounds checking against physical panel dimensions 59 60 if (phyX < 0 || phyX >= HalDisplay::DISPLAY_WIDTH || phyY < 0 || phyY >= HalDisplay::DISPLAY_HEIGHT) { 60 - Serial.printf("[%lu] [GFX] !! Outside range (%d, %d) -> (%d, %d)\n", millis(), x, y, phyX, phyY); 61 + LOG_ERR("GFX", "!! Outside range (%d, %d) -> (%d, %d)", x, y, phyX, phyY); 61 62 return; 62 63 } 63 64 ··· 74 75 75 76 int GfxRenderer::getTextWidth(const int fontId, const char* text, const EpdFontFamily::Style style) const { 76 77 if (fontMap.count(fontId) == 0) { 77 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 78 + LOG_ERR("GFX", "Font %d not found", fontId); 78 79 return 0; 79 80 } 80 81 ··· 100 101 } 101 102 102 103 if (fontMap.count(fontId) == 0) { 103 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 104 + LOG_ERR("GFX", "Font %d not found", fontId); 104 105 return; 105 106 } 106 107 const auto font = fontMap.at(fontId); ··· 133 134 } 134 135 } else { 135 136 // TODO: Implement 136 - Serial.printf("[%lu] [GFX] Line drawing not supported\n", millis()); 137 + LOG_ERR("GFX", "Line drawing not supported"); 137 138 } 138 139 } 139 140 ··· 419 420 bool isScaled = false; 420 421 int cropPixX = std::floor(bitmap.getWidth() * cropX / 2.0f); 421 422 int cropPixY = std::floor(bitmap.getHeight() * cropY / 2.0f); 422 - Serial.printf("[%lu] [GFX] Cropping %dx%d by %dx%d pix, is %s\n", millis(), bitmap.getWidth(), bitmap.getHeight(), 423 - cropPixX, cropPixY, bitmap.isTopDown() ? "top-down" : "bottom-up"); 423 + LOG_DBG("GFX", "Cropping %dx%d by %dx%d pix, is %s", bitmap.getWidth(), bitmap.getHeight(), cropPixX, cropPixY, 424 + bitmap.isTopDown() ? "top-down" : "bottom-up"); 424 425 425 426 if (maxWidth > 0 && (1.0f - cropX) * bitmap.getWidth() > maxWidth) { 426 427 scale = static_cast<float>(maxWidth) / static_cast<float>((1.0f - cropX) * bitmap.getWidth()); ··· 430 431 scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>((1.0f - cropY) * bitmap.getHeight())); 431 432 isScaled = true; 432 433 } 433 - Serial.printf("[%lu] [GFX] Scaling by %f - %s\n", millis(), scale, isScaled ? "scaled" : "not scaled"); 434 + LOG_DBG("GFX", "Scaling by %f - %s", scale, isScaled ? "scaled" : "not scaled"); 434 435 435 436 // Calculate output row size (2 bits per pixel, packed into bytes) 436 437 // IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels wide ··· 439 440 auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes())); 440 441 441 442 if (!outputRow || !rowBytes) { 442 - Serial.printf("[%lu] [GFX] !! Failed to allocate BMP row buffers\n", millis()); 443 + LOG_ERR("GFX", "!! Failed to allocate BMP row buffers"); 443 444 free(outputRow); 444 445 free(rowBytes); 445 446 return; ··· 458 459 } 459 460 460 461 if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) { 461 - Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), bmpY); 462 + LOG_ERR("GFX", "Failed to read row %d from bitmap", bmpY); 462 463 free(outputRow); 463 464 free(rowBytes); 464 465 return; ··· 521 522 auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes())); 522 523 523 524 if (!outputRow || !rowBytes) { 524 - Serial.printf("[%lu] [GFX] !! Failed to allocate 1-bit BMP row buffers\n", millis()); 525 + LOG_ERR("GFX", "!! Failed to allocate 1-bit BMP row buffers"); 525 526 free(outputRow); 526 527 free(rowBytes); 527 528 return; ··· 530 531 for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) { 531 532 // Read rows sequentially using readNextRow 532 533 if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) { 533 - Serial.printf("[%lu] [GFX] Failed to read row %d from 1-bit bitmap\n", millis(), bmpY); 534 + LOG_ERR("GFX", "Failed to read row %d from 1-bit bitmap", bmpY); 534 535 free(outputRow); 535 536 free(rowBytes); 536 537 return; ··· 588 589 // Allocate node buffer for scanline algorithm 589 590 auto* nodeX = static_cast<int*>(malloc(numPoints * sizeof(int))); 590 591 if (!nodeX) { 591 - Serial.printf("[%lu] [GFX] !! Failed to allocate polygon node buffer\n", millis()); 592 + LOG_ERR("GFX", "!! Failed to allocate polygon node buffer"); 592 593 return; 593 594 } 594 595 ··· 655 656 656 657 void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { 657 658 auto elapsed = millis() - start_ms; 658 - Serial.printf("[%lu] [GFX] Time = %lu ms from clearScreen to displayBuffer\n", millis(), elapsed); 659 + LOG_DBG("GFX", "Time = %lu ms from clearScreen to displayBuffer", elapsed); 659 660 display.displayBuffer(refreshMode, fadingFix); 660 661 } 661 662 ··· 709 710 710 711 int GfxRenderer::getSpaceWidth(const int fontId) const { 711 712 if (fontMap.count(fontId) == 0) { 712 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 713 + LOG_ERR("GFX", "Font %d not found", fontId); 713 714 return 0; 714 715 } 715 716 ··· 718 719 719 720 int GfxRenderer::getTextAdvanceX(const int fontId, const char* text) const { 720 721 if (fontMap.count(fontId) == 0) { 721 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 722 + LOG_ERR("GFX", "Font %d not found", fontId); 722 723 return 0; 723 724 } 724 725 ··· 732 733 733 734 int GfxRenderer::getFontAscenderSize(const int fontId) const { 734 735 if (fontMap.count(fontId) == 0) { 735 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 736 + LOG_ERR("GFX", "Font %d not found", fontId); 736 737 return 0; 737 738 } 738 739 ··· 741 742 742 743 int GfxRenderer::getLineHeight(const int fontId) const { 743 744 if (fontMap.count(fontId) == 0) { 744 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 745 + LOG_ERR("GFX", "Font %d not found", fontId); 745 746 return 0; 746 747 } 747 748 ··· 750 751 751 752 int GfxRenderer::getTextHeight(const int fontId) const { 752 753 if (fontMap.count(fontId) == 0) { 753 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 754 + LOG_ERR("GFX", "Font %d not found", fontId); 754 755 return 0; 755 756 } 756 757 return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender; ··· 764 765 } 765 766 766 767 if (fontMap.count(fontId) == 0) { 767 - Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId); 768 + LOG_ERR("GFX", "Font %d not found", fontId); 768 769 return; 769 770 } 770 771 const auto font = fontMap.at(fontId); ··· 872 873 for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) { 873 874 // Check if any chunks are already allocated 874 875 if (bwBufferChunks[i]) { 875 - Serial.printf("[%lu] [GFX] !! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk\n", 876 - millis(), i); 876 + LOG_ERR("GFX", "!! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk", i); 877 877 free(bwBufferChunks[i]); 878 878 bwBufferChunks[i] = nullptr; 879 879 } ··· 882 882 bwBufferChunks[i] = static_cast<uint8_t*>(malloc(BW_BUFFER_CHUNK_SIZE)); 883 883 884 884 if (!bwBufferChunks[i]) { 885 - Serial.printf("[%lu] [GFX] !! Failed to allocate BW buffer chunk %zu (%zu bytes)\n", millis(), i, 886 - BW_BUFFER_CHUNK_SIZE); 885 + LOG_ERR("GFX", "!! Failed to allocate BW buffer chunk %zu (%zu bytes)", i, BW_BUFFER_CHUNK_SIZE); 887 886 // Free previously allocated chunks 888 887 freeBwBufferChunks(); 889 888 return false; ··· 892 891 memcpy(bwBufferChunks[i], frameBuffer + offset, BW_BUFFER_CHUNK_SIZE); 893 892 } 894 893 895 - Serial.printf("[%lu] [GFX] Stored BW buffer in %zu chunks (%zu bytes each)\n", millis(), BW_BUFFER_NUM_CHUNKS, 896 - BW_BUFFER_CHUNK_SIZE); 894 + LOG_DBG("GFX", "Stored BW buffer in %zu chunks (%zu bytes each)", BW_BUFFER_NUM_CHUNKS, BW_BUFFER_CHUNK_SIZE); 897 895 return true; 898 896 } 899 897 ··· 920 918 for (size_t i = 0; i < BW_BUFFER_NUM_CHUNKS; i++) { 921 919 // Check if chunk is missing 922 920 if (!bwBufferChunks[i]) { 923 - Serial.printf("[%lu] [GFX] !! BW buffer chunks not stored - this is likely a bug\n", millis()); 921 + LOG_ERR("GFX", "!! BW buffer chunks not stored - this is likely a bug"); 924 922 freeBwBufferChunks(); 925 923 return; 926 924 } ··· 932 930 display.cleanupGrayscaleBuffers(frameBuffer); 933 931 934 932 freeBwBufferChunks(); 935 - Serial.printf("[%lu] [GFX] Restored and freed BW buffer chunks\n", millis()); 933 + LOG_DBG("GFX", "Restored and freed BW buffer chunks"); 936 934 } 937 935 938 936 /** ··· 954 952 955 953 // no glyph? 956 954 if (!glyph) { 957 - Serial.printf("[%lu] [GFX] No glyph for codepoint %d\n", millis(), cp); 955 + LOG_ERR("GFX", "No glyph for codepoint %d", cp); 958 956 return; 959 957 } 960 958
+15 -18
lib/JpegToBmpConverter/JpegToBmpConverter.cpp
··· 1 1 #include "JpegToBmpConverter.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <picojpeg.h> 6 6 7 7 #include <cstdio> ··· 201 201 // Internal implementation with configurable target size and bit depth 202 202 bool JpegToBmpConverter::jpegFileToBmpStreamInternal(FsFile& jpegFile, Print& bmpOut, int targetWidth, int targetHeight, 203 203 bool oneBit, bool crop) { 204 - Serial.printf("[%lu] [JPG] Converting JPEG to %s BMP (target: %dx%d)\n", millis(), oneBit ? "1-bit" : "2-bit", 205 - targetWidth, targetHeight); 204 + LOG_DBG("JPG", "Converting JPEG to %s BMP (target: %dx%d)", oneBit ? "1-bit" : "2-bit", targetWidth, targetHeight); 206 205 207 206 // Setup context for picojpeg callback 208 207 JpegReadContext context = {.file = jpegFile, .bufferPos = 0, .bufferFilled = 0}; ··· 211 210 pjpeg_image_info_t imageInfo; 212 211 const unsigned char status = pjpeg_decode_init(&imageInfo, jpegReadCallback, &context, 0); 213 212 if (status != 0) { 214 - Serial.printf("[%lu] [JPG] JPEG decode init failed with error code: %d\n", millis(), status); 213 + LOG_ERR("JPG", "JPEG decode init failed with error code: %d", status); 215 214 return false; 216 215 } 217 216 218 - Serial.printf("[%lu] [JPG] JPEG dimensions: %dx%d, components: %d, MCUs: %dx%d\n", millis(), imageInfo.m_width, 219 - imageInfo.m_height, imageInfo.m_comps, imageInfo.m_MCUSPerRow, imageInfo.m_MCUSPerCol); 217 + LOG_DBG("JPG", "JPEG dimensions: %dx%d, components: %d, MCUs: %dx%d", imageInfo.m_width, imageInfo.m_height, 218 + imageInfo.m_comps, imageInfo.m_MCUSPerRow, imageInfo.m_MCUSPerCol); 220 219 221 220 // Safety limits to prevent memory issues on ESP32 222 221 constexpr int MAX_IMAGE_WIDTH = 2048; ··· 224 223 constexpr int MAX_MCU_ROW_BYTES = 65536; 225 224 226 225 if (imageInfo.m_width > MAX_IMAGE_WIDTH || imageInfo.m_height > MAX_IMAGE_HEIGHT) { 227 - Serial.printf("[%lu] [JPG] Image too large (%dx%d), max supported: %dx%d\n", millis(), imageInfo.m_width, 228 - imageInfo.m_height, MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT); 226 + LOG_DBG("JPG", "Image too large (%dx%d), max supported: %dx%d", imageInfo.m_width, imageInfo.m_height, 227 + MAX_IMAGE_WIDTH, MAX_IMAGE_HEIGHT); 229 228 return false; 230 229 } 231 230 ··· 262 261 scaleY_fp = (static_cast<uint32_t>(imageInfo.m_height) << 16) / outHeight; 263 262 needsScaling = true; 264 263 265 - Serial.printf("[%lu] [JPG] Pre-scaling %dx%d -> %dx%d (fit to %dx%d)\n", millis(), imageInfo.m_width, 266 - imageInfo.m_height, outWidth, outHeight, targetWidth, targetHeight); 264 + LOG_DBG("JPG", "Pre-scaling %dx%d -> %dx%d (fit to %dx%d)", imageInfo.m_width, imageInfo.m_height, outWidth, 265 + outHeight, targetWidth, targetHeight); 267 266 } 268 267 269 268 // Write BMP header with output dimensions ··· 282 281 // Allocate row buffer 283 282 auto* rowBuffer = static_cast<uint8_t*>(malloc(bytesPerRow)); 284 283 if (!rowBuffer) { 285 - Serial.printf("[%lu] [JPG] Failed to allocate row buffer\n", millis()); 284 + LOG_ERR("JPG", "Failed to allocate row buffer"); 286 285 return false; 287 286 } 288 287 ··· 293 292 294 293 // Validate MCU row buffer size before allocation 295 294 if (mcuRowPixels > MAX_MCU_ROW_BYTES) { 296 - Serial.printf("[%lu] [JPG] MCU row buffer too large (%d bytes), max: %d\n", millis(), mcuRowPixels, 297 - MAX_MCU_ROW_BYTES); 295 + LOG_DBG("JPG", "MCU row buffer too large (%d bytes), max: %d", mcuRowPixels, MAX_MCU_ROW_BYTES); 298 296 free(rowBuffer); 299 297 return false; 300 298 } 301 299 302 300 auto* mcuRowBuffer = static_cast<uint8_t*>(malloc(mcuRowPixels)); 303 301 if (!mcuRowBuffer) { 304 - Serial.printf("[%lu] [JPG] Failed to allocate MCU row buffer (%d bytes)\n", millis(), mcuRowPixels); 302 + LOG_ERR("JPG", "Failed to allocate MCU row buffer (%d bytes)", mcuRowPixels); 305 303 free(rowBuffer); 306 304 return false; 307 305 } ··· 349 347 const unsigned char mcuStatus = pjpeg_decode_mcu(); 350 348 if (mcuStatus != 0) { 351 349 if (mcuStatus == PJPG_NO_MORE_BLOCKS) { 352 - Serial.printf("[%lu] [JPG] Unexpected end of blocks at MCU (%d, %d)\n", millis(), mcuX, mcuY); 350 + LOG_ERR("JPG", "Unexpected end of blocks at MCU (%d, %d)", mcuX, mcuY); 353 351 } else { 354 - Serial.printf("[%lu] [JPG] JPEG decode MCU failed at (%d, %d) with error code: %d\n", millis(), mcuX, mcuY, 355 - mcuStatus); 352 + LOG_ERR("JPG", "JPEG decode MCU failed at (%d, %d) with error code: %d", mcuX, mcuY, mcuStatus); 356 353 } 357 354 free(mcuRowBuffer); 358 355 free(rowBuffer); ··· 549 546 free(mcuRowBuffer); 550 547 free(rowBuffer); 551 548 552 - Serial.printf("[%lu] [JPG] Successfully converted JPEG to BMP\n", millis()); 549 + LOG_DBG("JPG", "Successfully converted JPEG to BMP"); 553 550 return true; 554 551 } 555 552
+10 -11
lib/KOReaderSync/KOReaderCredentialStore.cpp
··· 1 1 #include "KOReaderCredentialStore.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <MD5Builder.h> 6 6 #include <Serialization.h> 7 7 ··· 44 44 45 45 // Write username (plaintext - not particularly sensitive) 46 46 serialization::writeString(file, username); 47 - Serial.printf("[%lu] [KRS] Saving username: %s\n", millis(), username.c_str()); 47 + LOG_DBG("KRS", "Saving username: %s", username.c_str()); 48 48 49 49 // Write password (obfuscated) 50 50 std::string obfuscatedPwd = password; ··· 58 58 serialization::writePod(file, static_cast<uint8_t>(matchMethod)); 59 59 60 60 file.close(); 61 - Serial.printf("[%lu] [KRS] Saved KOReader credentials to file\n", millis()); 61 + LOG_DBG("KRS", "Saved KOReader credentials to file"); 62 62 return true; 63 63 } 64 64 65 65 bool KOReaderCredentialStore::loadFromFile() { 66 66 FsFile file; 67 67 if (!Storage.openFileForRead("KRS", KOREADER_FILE, file)) { 68 - Serial.printf("[%lu] [KRS] No credentials file found\n", millis()); 68 + LOG_DBG("KRS", "No credentials file found"); 69 69 return false; 70 70 } 71 71 ··· 73 73 uint8_t version; 74 74 serialization::readPod(file, version); 75 75 if (version != KOREADER_FILE_VERSION) { 76 - Serial.printf("[%lu] [KRS] Unknown file version: %u\n", millis(), version); 76 + LOG_DBG("KRS", "Unknown file version: %u", version); 77 77 file.close(); 78 78 return false; 79 79 } ··· 110 110 } 111 111 112 112 file.close(); 113 - Serial.printf("[%lu] [KRS] Loaded KOReader credentials for user: %s\n", millis(), username.c_str()); 113 + LOG_DBG("KRS", "Loaded KOReader credentials for user: %s", username.c_str()); 114 114 return true; 115 115 } 116 116 117 117 void KOReaderCredentialStore::setCredentials(const std::string& user, const std::string& pass) { 118 118 username = user; 119 119 password = pass; 120 - Serial.printf("[%lu] [KRS] Set credentials for user: %s\n", millis(), user.c_str()); 120 + LOG_DBG("KRS", "Set credentials for user: %s", user.c_str()); 121 121 } 122 122 123 123 std::string KOReaderCredentialStore::getMd5Password() const { ··· 140 140 username.clear(); 141 141 password.clear(); 142 142 saveToFile(); 143 - Serial.printf("[%lu] [KRS] Cleared KOReader credentials\n", millis()); 143 + LOG_DBG("KRS", "Cleared KOReader credentials"); 144 144 } 145 145 146 146 void KOReaderCredentialStore::setServerUrl(const std::string& url) { 147 147 serverUrl = url; 148 - Serial.printf("[%lu] [KRS] Set server URL: %s\n", millis(), url.empty() ? "(default)" : url.c_str()); 148 + LOG_DBG("KRS", "Set server URL: %s", url.empty() ? "(default)" : url.c_str()); 149 149 } 150 150 151 151 std::string KOReaderCredentialStore::getBaseUrl() const { ··· 163 163 164 164 void KOReaderCredentialStore::setMatchMethod(DocumentMatchMethod method) { 165 165 matchMethod = method; 166 - Serial.printf("[%lu] [KRS] Set match method: %s\n", millis(), 167 - method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary"); 166 + LOG_DBG("KRS", "Set match method: %s", method == DocumentMatchMethod::FILENAME ? "Filename" : "Binary"); 168 167 }
+6 -6
lib/KOReaderSync/KOReaderDocumentId.cpp
··· 1 1 #include "KOReaderDocumentId.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <MD5Builder.h> 6 6 7 7 namespace { ··· 27 27 md5.calculate(); 28 28 29 29 std::string result = md5.toString().c_str(); 30 - Serial.printf("[%lu] [KODoc] Filename hash: %s (from '%s')\n", millis(), result.c_str(), filename.c_str()); 30 + LOG_DBG("KODoc", "Filename hash: %s (from '%s')", result.c_str(), filename.c_str()); 31 31 return result; 32 32 } 33 33 ··· 44 44 std::string KOReaderDocumentId::calculate(const std::string& filePath) { 45 45 FsFile file; 46 46 if (!Storage.openFileForRead("KODoc", filePath, file)) { 47 - Serial.printf("[%lu] [KODoc] Failed to open file: %s\n", millis(), filePath.c_str()); 47 + LOG_DBG("KODoc", "Failed to open file: %s", filePath.c_str()); 48 48 return ""; 49 49 } 50 50 51 51 const size_t fileSize = file.fileSize(); 52 - Serial.printf("[%lu] [KODoc] Calculating hash for file: %s (size: %zu)\n", millis(), filePath.c_str(), fileSize); 52 + LOG_DBG("KODoc", "Calculating hash for file: %s (size: %zu)", filePath.c_str(), fileSize); 53 53 54 54 // Initialize MD5 builder 55 55 MD5Builder md5; ··· 70 70 71 71 // Seek to offset 72 72 if (!file.seekSet(offset)) { 73 - Serial.printf("[%lu] [KODoc] Failed to seek to offset %zu\n", millis(), offset); 73 + LOG_DBG("KODoc", "Failed to seek to offset %zu", offset); 74 74 continue; 75 75 } 76 76 ··· 90 90 md5.calculate(); 91 91 std::string result = md5.toString().c_str(); 92 92 93 - Serial.printf("[%lu] [KODoc] Hash calculated: %s (from %zu bytes)\n", millis(), result.c_str(), totalBytesRead); 93 + LOG_DBG("KODoc", "Hash calculated: %s (from %zu bytes)", result.c_str(), totalBytesRead); 94 94 95 95 return result; 96 96 }
+13 -14
lib/KOReaderSync/KOReaderSyncClient.cpp
··· 2 2 3 3 #include <ArduinoJson.h> 4 4 #include <HTTPClient.h> 5 - #include <HardwareSerial.h> 5 + #include <Logging.h> 6 6 #include <WiFi.h> 7 7 #include <WiFiClientSecure.h> 8 8 ··· 30 30 31 31 KOReaderSyncClient::Error KOReaderSyncClient::authenticate() { 32 32 if (!KOREADER_STORE.hasCredentials()) { 33 - Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); 33 + LOG_DBG("KOSync", "No credentials configured"); 34 34 return NO_CREDENTIALS; 35 35 } 36 36 37 37 std::string url = KOREADER_STORE.getBaseUrl() + "/users/auth"; 38 - Serial.printf("[%lu] [KOSync] Authenticating: %s\n", millis(), url.c_str()); 38 + LOG_DBG("KOSync", "Authenticating: %s", url.c_str()); 39 39 40 40 HTTPClient http; 41 41 std::unique_ptr<WiFiClientSecure> secureClient; ··· 53 53 const int httpCode = http.GET(); 54 54 http.end(); 55 55 56 - Serial.printf("[%lu] [KOSync] Auth response: %d\n", millis(), httpCode); 56 + LOG_DBG("KOSync", "Auth response: %d", httpCode); 57 57 58 58 if (httpCode == 200) { 59 59 return OK; ··· 68 68 KOReaderSyncClient::Error KOReaderSyncClient::getProgress(const std::string& documentHash, 69 69 KOReaderProgress& outProgress) { 70 70 if (!KOREADER_STORE.hasCredentials()) { 71 - Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); 71 + LOG_DBG("KOSync", "No credentials configured"); 72 72 return NO_CREDENTIALS; 73 73 } 74 74 75 75 std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress/" + documentHash; 76 - Serial.printf("[%lu] [KOSync] Getting progress: %s\n", millis(), url.c_str()); 76 + LOG_DBG("KOSync", "Getting progress: %s", url.c_str()); 77 77 78 78 HTTPClient http; 79 79 std::unique_ptr<WiFiClientSecure> secureClient; ··· 99 99 const DeserializationError error = deserializeJson(doc, responseBody); 100 100 101 101 if (error) { 102 - Serial.printf("[%lu] [KOSync] JSON parse failed: %s\n", millis(), error.c_str()); 102 + LOG_ERR("KOSync", "JSON parse failed: %s", error.c_str()); 103 103 return JSON_ERROR; 104 104 } 105 105 ··· 110 110 outProgress.deviceId = doc["device_id"].as<std::string>(); 111 111 outProgress.timestamp = doc["timestamp"].as<int64_t>(); 112 112 113 - Serial.printf("[%lu] [KOSync] Got progress: %.2f%% at %s\n", millis(), outProgress.percentage * 100, 114 - outProgress.progress.c_str()); 113 + LOG_DBG("KOSync", "Got progress: %.2f%% at %s", outProgress.percentage * 100, outProgress.progress.c_str()); 115 114 return OK; 116 115 } 117 116 118 117 http.end(); 119 118 120 - Serial.printf("[%lu] [KOSync] Get progress response: %d\n", millis(), httpCode); 119 + LOG_DBG("KOSync", "Get progress response: %d", httpCode); 121 120 122 121 if (httpCode == 401) { 123 122 return AUTH_FAILED; ··· 131 130 132 131 KOReaderSyncClient::Error KOReaderSyncClient::updateProgress(const KOReaderProgress& progress) { 133 132 if (!KOREADER_STORE.hasCredentials()) { 134 - Serial.printf("[%lu] [KOSync] No credentials configured\n", millis()); 133 + LOG_DBG("KOSync", "No credentials configured"); 135 134 return NO_CREDENTIALS; 136 135 } 137 136 138 137 std::string url = KOREADER_STORE.getBaseUrl() + "/syncs/progress"; 139 - Serial.printf("[%lu] [KOSync] Updating progress: %s\n", millis(), url.c_str()); 138 + LOG_DBG("KOSync", "Updating progress: %s", url.c_str()); 140 139 141 140 HTTPClient http; 142 141 std::unique_ptr<WiFiClientSecure> secureClient; ··· 163 162 std::string body; 164 163 serializeJson(doc, body); 165 164 166 - Serial.printf("[%lu] [KOSync] Request body: %s\n", millis(), body.c_str()); 165 + LOG_DBG("KOSync", "Request body: %s", body.c_str()); 167 166 168 167 const int httpCode = http.PUT(body.c_str()); 169 168 http.end(); 170 169 171 - Serial.printf("[%lu] [KOSync] Update progress response: %d\n", millis(), httpCode); 170 + LOG_DBG("KOSync", "Update progress response: %d", httpCode); 172 171 173 172 if (httpCode == 200 || httpCode == 202) { 174 173 return OK;
+5 -5
lib/KOReaderSync/ProgressMapper.cpp
··· 1 1 #include "ProgressMapper.h" 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 5 5 #include <cmath> 6 6 ··· 23 23 const int tocIndex = epub->getTocIndexForSpineIndex(pos.spineIndex); 24 24 const std::string chapterName = (tocIndex >= 0) ? epub->getTocItem(tocIndex).title : "unknown"; 25 25 26 - Serial.printf("[%lu] [ProgressMapper] CrossPoint -> KOReader: chapter='%s', page=%d/%d -> %.2f%% at %s\n", millis(), 27 - chapterName.c_str(), pos.pageNumber, pos.totalPages, result.percentage * 100, result.xpath.c_str()); 26 + LOG_DBG("ProgressMapper", "CrossPoint -> KOReader: chapter='%s', page=%d/%d -> %.2f%% at %s", chapterName.c_str(), 27 + pos.pageNumber, pos.totalPages, result.percentage * 100, result.xpath.c_str()); 28 28 29 29 return result; 30 30 } ··· 76 76 } 77 77 } 78 78 79 - Serial.printf("[%lu] [ProgressMapper] KOReader -> CrossPoint: %.2f%% at %s -> spine=%d, page=%d\n", millis(), 80 - koPos.percentage * 100, koPos.xpath.c_str(), result.spineIndex, result.pageNumber); 79 + LOG_DBG("ProgressMapper", "KOReader -> CrossPoint: %.2f%% at %s -> spine=%d, page=%d", koPos.percentage * 100, 80 + koPos.xpath.c_str(), result.spineIndex, result.pageNumber); 81 81 82 82 return result; 83 83 }
+47
lib/Logging/Logging.cpp
··· 1 + #include "Logging.h" 2 + 3 + // Since logging can take a large amount of flash, we want to make the format string as short as possible. 4 + // This logPrintf prepend the timestamp, level and origin to the user-provided message, so that the user only needs to 5 + // provide the format string for the message itself. 6 + void logPrintf(const char* level, const char* origin, const char* format, ...) { 7 + if (!logSerial) { 8 + return; // Serial not initialized, skip logging 9 + } 10 + va_list args; 11 + va_start(args, format); 12 + char buf[256]; 13 + char* c = buf; 14 + // add the timestamp 15 + { 16 + unsigned long ms = millis(); 17 + int len = snprintf(c, sizeof(buf), "[%lu] ", ms); 18 + if (len < 0) { 19 + return; // encoding error, skip logging 20 + } 21 + c += len; 22 + } 23 + // add the level 24 + { 25 + const char* p = level; 26 + size_t remaining = sizeof(buf) - (c - buf); 27 + while (*p && remaining > 1) { 28 + *c++ = *p++; 29 + remaining--; 30 + } 31 + if (remaining > 1) { 32 + *c++ = ' '; 33 + } 34 + } 35 + // add the origin 36 + { 37 + int len = snprintf(c, sizeof(buf) - (c - buf), "[%s] ", origin); 38 + if (len < 0) { 39 + return; // encoding error, skip logging 40 + } 41 + c += len; 42 + } 43 + // add the user message 44 + vsnprintf(c, sizeof(buf) - (c - buf), format, args); 45 + va_end(args); 46 + logSerial.print(buf); 47 + }
+71
lib/Logging/Logging.h
··· 1 + #pragma once 2 + 3 + #include <HardwareSerial.h> 4 + 5 + /* 6 + Define ENABLE_SERIAL_LOG to enable logging 7 + Can be set in platformio.ini build_flags or as a compile definition 8 + 9 + Define LOG_LEVEL to control log verbosity: 10 + 0 = ERR only 11 + 1 = ERR + INF 12 + 2 = ERR + INF + DBG 13 + If not defined, defaults to 0 14 + 15 + If you have a legitimate need for raw Serial access (e.g., binary data, 16 + special formatting), use the underlying logSerial object directly: 17 + logSerial.printf("Special case: %d\n", value); 18 + logSerial.write(binaryData, length); 19 + 20 + The logSerial reference (defined below) points to the real Serial object and 21 + won't trigger deprecation warnings. 22 + */ 23 + 24 + #ifndef LOG_LEVEL 25 + #define LOG_LEVEL 0 26 + #endif 27 + 28 + static HWCDC& logSerial = Serial; 29 + 30 + void logPrintf(const char* level, const char* origin, const char* format, ...); 31 + 32 + #ifdef ENABLE_SERIAL_LOG 33 + #if LOG_LEVEL >= 0 34 + #define LOG_ERR(origin, format, ...) logPrintf("[ERR]", origin, format "\n", ##__VA_ARGS__) 35 + #else 36 + #define LOG_ERR(origin, format, ...) 37 + #endif 38 + 39 + #if LOG_LEVEL >= 1 40 + #define LOG_INF(origin, format, ...) logPrintf("[INF]", origin, format "\n", ##__VA_ARGS__) 41 + #else 42 + #define LOG_INF(origin, format, ...) 43 + #endif 44 + 45 + #if LOG_LEVEL >= 2 46 + #define LOG_DBG(origin, format, ...) logPrintf("[DBG]", origin, format "\n", ##__VA_ARGS__) 47 + #else 48 + #define LOG_DBG(origin, format, ...) 49 + #endif 50 + #else 51 + #define LOG_DBG(origin, format, ...) 52 + #define LOG_ERR(origin, format, ...) 53 + #define LOG_INF(origin, format, ...) 54 + #endif 55 + 56 + class MySerialImpl : public Print { 57 + public: 58 + void begin(unsigned long baud) { logSerial.begin(baud); } 59 + 60 + // Support boolean conversion for compatibility with code like: 61 + // if (Serial) or while (!Serial) 62 + operator bool() const { return logSerial; } 63 + 64 + __attribute__((deprecated("Use LOG_* macro instead"))) size_t printf(const char* format, ...); 65 + size_t write(uint8_t b) override; 66 + size_t write(const uint8_t* buffer, size_t size) override; 67 + void flush() override; 68 + static MySerialImpl instance; 69 + }; 70 + 71 + #define Serial MySerialImpl::instance
+5 -5
lib/OpdsParser/OpdsParser.cpp
··· 1 1 #include "OpdsParser.h" 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 5 5 #include <cstring> 6 6 ··· 8 8 parser = XML_ParserCreate(nullptr); 9 9 if (!parser) { 10 10 errorOccured = true; 11 - Serial.printf("[%lu] [OPDS] Couldn't allocate memory for parser\n", millis()); 11 + LOG_DBG("OPDS", "Couldn't allocate memory for parser"); 12 12 } 13 13 } 14 14 ··· 42 42 void* const buf = XML_GetBuffer(parser, chunkSize); 43 43 if (!buf) { 44 44 errorOccured = true; 45 - Serial.printf("[%lu] [OPDS] Couldn't allocate memory for buffer\n", millis()); 45 + LOG_DBG("OPDS", "Couldn't allocate memory for buffer"); 46 46 XML_ParserFree(parser); 47 47 parser = nullptr; 48 48 return length; ··· 53 53 54 54 if (XML_ParseBuffer(parser, static_cast<int>(toRead), 0) == XML_STATUS_ERROR) { 55 55 errorOccured = true; 56 - Serial.printf("[%lu] [OPDS] Parse error at line %lu: %s\n", millis(), XML_GetCurrentLineNumber(parser), 57 - XML_ErrorString(XML_GetErrorCode(parser))); 56 + LOG_DBG("OPDS", "Parse error at line %lu: %s", XML_GetCurrentLineNumber(parser), 57 + XML_ErrorString(XML_GetErrorCode(parser))); 58 58 XML_ParserFree(parser); 59 59 parser = nullptr; 60 60 return length;
+13 -12
lib/Txt/Txt.cpp
··· 2 2 3 3 #include <FsHelpers.h> 4 4 #include <JpegToBmpConverter.h> 5 + #include <Logging.h> 5 6 6 7 Txt::Txt(std::string path, std::string cacheBasePath) 7 8 : filepath(std::move(path)), cacheBasePath(std::move(cacheBasePath)) { ··· 16 17 } 17 18 18 19 if (!Storage.exists(filepath.c_str())) { 19 - Serial.printf("[%lu] [TXT] File does not exist: %s\n", millis(), filepath.c_str()); 20 + LOG_ERR("TXT", "File does not exist: %s", filepath.c_str()); 20 21 return false; 21 22 } 22 23 23 24 FsFile file; 24 25 if (!Storage.openFileForRead("TXT", filepath, file)) { 25 - Serial.printf("[%lu] [TXT] Failed to open file: %s\n", millis(), filepath.c_str()); 26 + LOG_ERR("TXT", "Failed to open file: %s", filepath.c_str()); 26 27 return false; 27 28 } 28 29 ··· 30 31 file.close(); 31 32 32 33 loaded = true; 33 - Serial.printf("[%lu] [TXT] Loaded TXT file: %s (%zu bytes)\n", millis(), filepath.c_str(), fileSize); 34 + LOG_DBG("TXT", "Loaded TXT file: %s (%zu bytes)", filepath.c_str(), fileSize); 34 35 return true; 35 36 } 36 37 ··· 74 75 for (const auto& ext : extensions) { 75 76 std::string coverPath = folder + "/" + baseName + ext; 76 77 if (Storage.exists(coverPath.c_str())) { 77 - Serial.printf("[%lu] [TXT] Found matching cover image: %s\n", millis(), coverPath.c_str()); 78 + LOG_DBG("TXT", "Found matching cover image: %s", coverPath.c_str()); 78 79 return coverPath; 79 80 } 80 81 } ··· 85 86 for (const auto& ext : extensions) { 86 87 std::string coverPath = folder + "/" + std::string(name) + ext; 87 88 if (Storage.exists(coverPath.c_str())) { 88 - Serial.printf("[%lu] [TXT] Found fallback cover image: %s\n", millis(), coverPath.c_str()); 89 + LOG_DBG("TXT", "Found fallback cover image: %s", coverPath.c_str()); 89 90 return coverPath; 90 91 } 91 92 } ··· 104 105 105 106 std::string coverImagePath = findCoverImage(); 106 107 if (coverImagePath.empty()) { 107 - Serial.printf("[%lu] [TXT] No cover image found for TXT file\n", millis()); 108 + LOG_DBG("TXT", "No cover image found for TXT file"); 108 109 return false; 109 110 } 110 111 ··· 120 121 121 122 if (isBmp) { 122 123 // Copy BMP file to cache 123 - Serial.printf("[%lu] [TXT] Copying BMP cover image to cache\n", millis()); 124 + LOG_DBG("TXT", "Copying BMP cover image to cache"); 124 125 FsFile src, dst; 125 126 if (!Storage.openFileForRead("TXT", coverImagePath, src)) { 126 127 return false; ··· 136 137 } 137 138 src.close(); 138 139 dst.close(); 139 - Serial.printf("[%lu] [TXT] Copied BMP cover to cache\n", millis()); 140 + LOG_DBG("TXT", "Copied BMP cover to cache"); 140 141 return true; 141 142 } 142 143 143 144 if (isJpg) { 144 145 // Convert JPG/JPEG to BMP (same approach as Epub) 145 - Serial.printf("[%lu] [TXT] Generating BMP from JPG cover image\n", millis()); 146 + LOG_DBG("TXT", "Generating BMP from JPG cover image"); 146 147 FsFile coverJpg, coverBmp; 147 148 if (!Storage.openFileForRead("TXT", coverImagePath, coverJpg)) { 148 149 return false; ··· 156 157 coverBmp.close(); 157 158 158 159 if (!success) { 159 - Serial.printf("[%lu] [TXT] Failed to generate BMP from JPG cover image\n", millis()); 160 + LOG_ERR("TXT", "Failed to generate BMP from JPG cover image"); 160 161 Storage.remove(getCoverBmpPath().c_str()); 161 162 } else { 162 - Serial.printf("[%lu] [TXT] Generated BMP from JPG cover image\n", millis()); 163 + LOG_DBG("TXT", "Generated BMP from JPG cover image"); 163 164 } 164 165 return success; 165 166 } 166 167 167 168 // PNG files are not supported (would need a PNG decoder) 168 - Serial.printf("[%lu] [TXT] Cover image format not supported (only BMP/JPG/JPEG)\n", millis()); 169 + LOG_ERR("TXT", "Cover image format not supported (only BMP/JPG/JPEG)"); 169 170 return false; 170 171 } 171 172
+24 -25
lib/Xtc/Xtc.cpp
··· 8 8 #include "Xtc.h" 9 9 10 10 #include <HalStorage.h> 11 - #include <HardwareSerial.h> 11 + #include <Logging.h> 12 12 13 13 bool Xtc::load() { 14 - Serial.printf("[%lu] [XTC] Loading XTC: %s\n", millis(), filepath.c_str()); 14 + LOG_DBG("XTC", "Loading XTC: %s", filepath.c_str()); 15 15 16 16 // Initialize parser 17 17 parser.reset(new xtc::XtcParser()); ··· 19 19 // Open XTC file 20 20 xtc::XtcError err = parser->open(filepath.c_str()); 21 21 if (err != xtc::XtcError::OK) { 22 - Serial.printf("[%lu] [XTC] Failed to load: %s\n", millis(), xtc::errorToString(err)); 22 + LOG_ERR("XTC", "Failed to load: %s", xtc::errorToString(err)); 23 23 parser.reset(); 24 24 return false; 25 25 } 26 26 27 27 loaded = true; 28 - Serial.printf("[%lu] [XTC] Loaded XTC: %s (%lu pages)\n", millis(), filepath.c_str(), parser->getPageCount()); 28 + LOG_DBG("XTC", "Loaded XTC: %s (%lu pages)", filepath.c_str(), parser->getPageCount()); 29 29 return true; 30 30 } 31 31 32 32 bool Xtc::clearCache() const { 33 33 if (!Storage.exists(cachePath.c_str())) { 34 - Serial.printf("[%lu] [XTC] Cache does not exist, no action needed\n", millis()); 34 + LOG_DBG("XTC", "Cache does not exist, no action needed"); 35 35 return true; 36 36 } 37 37 38 38 if (!Storage.removeDir(cachePath.c_str())) { 39 - Serial.printf("[%lu] [XTC] Failed to clear cache\n", millis()); 39 + LOG_ERR("XTC", "Failed to clear cache"); 40 40 return false; 41 41 } 42 42 43 - Serial.printf("[%lu] [XTC] Cache cleared successfully\n", millis()); 43 + LOG_DBG("XTC", "Cache cleared successfully"); 44 44 return true; 45 45 } 46 46 ··· 119 119 } 120 120 121 121 if (!loaded || !parser) { 122 - Serial.printf("[%lu] [XTC] Cannot generate cover BMP, file not loaded\n", millis()); 122 + LOG_ERR("XTC", "Cannot generate cover BMP, file not loaded"); 123 123 return false; 124 124 } 125 125 126 126 if (parser->getPageCount() == 0) { 127 - Serial.printf("[%lu] [XTC] No pages in XTC file\n", millis()); 127 + LOG_ERR("XTC", "No pages in XTC file"); 128 128 return false; 129 129 } 130 130 ··· 134 134 // Get first page info for cover 135 135 xtc::PageInfo pageInfo; 136 136 if (!parser->getPageInfo(0, pageInfo)) { 137 - Serial.printf("[%lu] [XTC] Failed to get first page info\n", millis()); 137 + LOG_DBG("XTC", "Failed to get first page info"); 138 138 return false; 139 139 } 140 140 ··· 152 152 } 153 153 uint8_t* pageBuffer = static_cast<uint8_t*>(malloc(bitmapSize)); 154 154 if (!pageBuffer) { 155 - Serial.printf("[%lu] [XTC] Failed to allocate page buffer (%lu bytes)\n", millis(), bitmapSize); 155 + LOG_ERR("XTC", "Failed to allocate page buffer (%lu bytes)", bitmapSize); 156 156 return false; 157 157 } 158 158 159 159 // Load first page (cover) 160 160 size_t bytesRead = const_cast<xtc::XtcParser*>(parser.get())->loadPage(0, pageBuffer, bitmapSize); 161 161 if (bytesRead == 0) { 162 - Serial.printf("[%lu] [XTC] Failed to load cover page\n", millis()); 162 + LOG_ERR("XTC", "Failed to load cover page"); 163 163 free(pageBuffer); 164 164 return false; 165 165 } ··· 167 167 // Create BMP file 168 168 FsFile coverBmp; 169 169 if (!Storage.openFileForWrite("XTC", getCoverBmpPath(), coverBmp)) { 170 - Serial.printf("[%lu] [XTC] Failed to create cover BMP file\n", millis()); 170 + LOG_DBG("XTC", "Failed to create cover BMP file"); 171 171 free(pageBuffer); 172 172 return false; 173 173 } ··· 297 297 coverBmp.close(); 298 298 free(pageBuffer); 299 299 300 - Serial.printf("[%lu] [XTC] Generated cover BMP: %s\n", millis(), getCoverBmpPath().c_str()); 300 + LOG_DBG("XTC", "Generated cover BMP: %s", getCoverBmpPath().c_str()); 301 301 return true; 302 302 } 303 303 ··· 311 311 } 312 312 313 313 if (!loaded || !parser) { 314 - Serial.printf("[%lu] [XTC] Cannot generate thumb BMP, file not loaded\n", millis()); 314 + LOG_ERR("XTC", "Cannot generate thumb BMP, file not loaded"); 315 315 return false; 316 316 } 317 317 318 318 if (parser->getPageCount() == 0) { 319 - Serial.printf("[%lu] [XTC] No pages in XTC file\n", millis()); 319 + LOG_ERR("XTC", "No pages in XTC file"); 320 320 return false; 321 321 } 322 322 ··· 326 326 // Get first page info for cover 327 327 xtc::PageInfo pageInfo; 328 328 if (!parser->getPageInfo(0, pageInfo)) { 329 - Serial.printf("[%lu] [XTC] Failed to get first page info\n", millis()); 329 + LOG_DBG("XTC", "Failed to get first page info"); 330 330 return false; 331 331 } 332 332 ··· 359 359 } 360 360 src.close(); 361 361 } 362 - Serial.printf("[%lu] [XTC] Copied cover to thumb (no scaling needed)\n", millis()); 362 + LOG_DBG("XTC", "Copied cover to thumb (no scaling needed)"); 363 363 return Storage.exists(getThumbBmpPath(height).c_str()); 364 364 } 365 365 return false; ··· 368 368 uint16_t thumbWidth = static_cast<uint16_t>(pageInfo.width * scale); 369 369 uint16_t thumbHeight = static_cast<uint16_t>(pageInfo.height * scale); 370 370 371 - Serial.printf("[%lu] [XTC] Generating thumb BMP: %dx%d -> %dx%d (scale: %.3f)\n", millis(), pageInfo.width, 372 - pageInfo.height, thumbWidth, thumbHeight, scale); 371 + LOG_DBG("XTC", "Generating thumb BMP: %dx%d -> %dx%d (scale: %.3f)", pageInfo.width, pageInfo.height, thumbWidth, 372 + thumbHeight, scale); 373 373 374 374 // Allocate buffer for page data 375 375 size_t bitmapSize; ··· 380 380 } 381 381 uint8_t* pageBuffer = static_cast<uint8_t*>(malloc(bitmapSize)); 382 382 if (!pageBuffer) { 383 - Serial.printf("[%lu] [XTC] Failed to allocate page buffer (%lu bytes)\n", millis(), bitmapSize); 383 + LOG_ERR("XTC", "Failed to allocate page buffer (%lu bytes)", bitmapSize); 384 384 return false; 385 385 } 386 386 387 387 // Load first page (cover) 388 388 size_t bytesRead = const_cast<xtc::XtcParser*>(parser.get())->loadPage(0, pageBuffer, bitmapSize); 389 389 if (bytesRead == 0) { 390 - Serial.printf("[%lu] [XTC] Failed to load cover page for thumb\n", millis()); 390 + LOG_ERR("XTC", "Failed to load cover page for thumb"); 391 391 free(pageBuffer); 392 392 return false; 393 393 } ··· 395 395 // Create thumbnail BMP file - use 1-bit format for fast home screen rendering (no gray passes) 396 396 FsFile thumbBmp; 397 397 if (!Storage.openFileForWrite("XTC", getThumbBmpPath(height), thumbBmp)) { 398 - Serial.printf("[%lu] [XTC] Failed to create thumb BMP file\n", millis()); 398 + LOG_DBG("XTC", "Failed to create thumb BMP file"); 399 399 free(pageBuffer); 400 400 return false; 401 401 } ··· 558 558 thumbBmp.close(); 559 559 free(pageBuffer); 560 560 561 - Serial.printf("[%lu] [XTC] Generated thumb BMP (%dx%d): %s\n", millis(), thumbWidth, thumbHeight, 562 - getThumbBmpPath(height).c_str()); 561 + LOG_DBG("XTC", "Generated thumb BMP (%dx%d): %s", thumbWidth, thumbHeight, getThumbBmpPath(height).c_str()); 563 562 return true; 564 563 } 565 564
+25 -27
lib/Xtc/Xtc/XtcParser.cpp
··· 9 9 10 10 #include <FsHelpers.h> 11 11 #include <HalStorage.h> 12 - #include <HardwareSerial.h> 12 + #include <Logging.h> 13 13 14 14 #include <cstring> 15 15 ··· 42 42 // Read header 43 43 m_lastError = readHeader(); 44 44 if (m_lastError != XtcError::OK) { 45 - Serial.printf("[%lu] [XTC] Failed to read header: %s\n", millis(), errorToString(m_lastError)); 45 + LOG_DBG("XTC", "Failed to read header: %s", errorToString(m_lastError)); 46 46 m_file.close(); 47 47 return m_lastError; 48 48 } ··· 51 51 if (m_header.hasMetadata) { 52 52 m_lastError = readTitle(); 53 53 if (m_lastError != XtcError::OK) { 54 - Serial.printf("[%lu] [XTC] Failed to read title: %s\n", millis(), errorToString(m_lastError)); 54 + LOG_DBG("XTC", "Failed to read title: %s", errorToString(m_lastError)); 55 55 m_file.close(); 56 56 return m_lastError; 57 57 } 58 58 m_lastError = readAuthor(); 59 59 if (m_lastError != XtcError::OK) { 60 - Serial.printf("[%lu] [XTC] Failed to read author: %s\n", millis(), errorToString(m_lastError)); 60 + LOG_DBG("XTC", "Failed to read author: %s", errorToString(m_lastError)); 61 61 m_file.close(); 62 62 return m_lastError; 63 63 } ··· 66 66 // Read page table 67 67 m_lastError = readPageTable(); 68 68 if (m_lastError != XtcError::OK) { 69 - Serial.printf("[%lu] [XTC] Failed to read page table: %s\n", millis(), errorToString(m_lastError)); 69 + LOG_DBG("XTC", "Failed to read page table: %s", errorToString(m_lastError)); 70 70 m_file.close(); 71 71 return m_lastError; 72 72 } ··· 74 74 // Read chapters if present 75 75 m_lastError = readChapters(); 76 76 if (m_lastError != XtcError::OK) { 77 - Serial.printf("[%lu] [XTC] Failed to read chapters: %s\n", millis(), errorToString(m_lastError)); 77 + LOG_DBG("XTC", "Failed to read chapters: %s", errorToString(m_lastError)); 78 78 m_file.close(); 79 79 return m_lastError; 80 80 } 81 81 82 82 m_isOpen = true; 83 - Serial.printf("[%lu] [XTC] Opened file: %s (%u pages, %dx%d)\n", millis(), filepath, m_header.pageCount, 84 - m_defaultWidth, m_defaultHeight); 83 + LOG_DBG("XTC", "Opened file: %s (%u pages, %dx%d)", filepath, m_header.pageCount, m_defaultWidth, m_defaultHeight); 85 84 return XtcError::OK; 86 85 } 87 86 ··· 106 105 107 106 // Verify magic number (accept both XTC and XTCH) 108 107 if (m_header.magic != XTC_MAGIC && m_header.magic != XTCH_MAGIC) { 109 - Serial.printf("[%lu] [XTC] Invalid magic: 0x%08X (expected 0x%08X or 0x%08X)\n", millis(), m_header.magic, 110 - XTC_MAGIC, XTCH_MAGIC); 108 + LOG_DBG("XTC", "Invalid magic: 0x%08X (expected 0x%08X or 0x%08X)", m_header.magic, XTC_MAGIC, XTCH_MAGIC); 111 109 return XtcError::INVALID_MAGIC; 112 110 } 113 111 ··· 120 118 const bool validVersion = m_header.versionMajor == 1 && m_header.versionMinor == 0 || 121 119 m_header.versionMajor == 0 && m_header.versionMinor == 1; 122 120 if (!validVersion) { 123 - Serial.printf("[%lu] [XTC] Unsupported version: %u.%u\n", millis(), m_header.versionMajor, m_header.versionMinor); 121 + LOG_DBG("XTC", "Unsupported version: %u.%u", m_header.versionMajor, m_header.versionMinor); 124 122 return XtcError::INVALID_VERSION; 125 123 } 126 124 ··· 129 127 return XtcError::CORRUPTED_HEADER; 130 128 } 131 129 132 - Serial.printf("[%lu] [XTC] Header: magic=0x%08X (%s), ver=%u.%u, pages=%u, bitDepth=%u\n", millis(), m_header.magic, 133 - (m_header.magic == XTCH_MAGIC) ? "XTCH" : "XTC", m_header.versionMajor, m_header.versionMinor, 134 - m_header.pageCount, m_bitDepth); 130 + LOG_DBG("XTC", "Header: magic=0x%08X (%s), ver=%u.%u, pages=%u, bitDepth=%u", m_header.magic, 131 + (m_header.magic == XTCH_MAGIC) ? "XTCH" : "XTC", m_header.versionMajor, m_header.versionMinor, 132 + m_header.pageCount, m_bitDepth); 135 133 136 134 return XtcError::OK; 137 135 } ··· 146 144 m_file.read(titleBuf, sizeof(titleBuf) - 1); 147 145 m_title = titleBuf; 148 146 149 - Serial.printf("[%lu] [XTC] Title: %s\n", millis(), m_title.c_str()); 147 + LOG_DBG("XTC", "Title: %s", m_title.c_str()); 150 148 return XtcError::OK; 151 149 } 152 150 ··· 161 159 m_file.read(authorBuf, sizeof(authorBuf) - 1); 162 160 m_author = authorBuf; 163 161 164 - Serial.printf("[%lu] [XTC] Author: %s\n", millis(), m_author.c_str()); 162 + LOG_DBG("XTC", "Author: %s", m_author.c_str()); 165 163 return XtcError::OK; 166 164 } 167 165 168 166 XtcError XtcParser::readPageTable() { 169 167 if (m_header.pageTableOffset == 0) { 170 - Serial.printf("[%lu] [XTC] Page table offset is 0, cannot read\n", millis()); 168 + LOG_DBG("XTC", "Page table offset is 0, cannot read"); 171 169 return XtcError::CORRUPTED_HEADER; 172 170 } 173 171 174 172 // Seek to page table 175 173 if (!m_file.seek(m_header.pageTableOffset)) { 176 - Serial.printf("[%lu] [XTC] Failed to seek to page table at %llu\n", millis(), m_header.pageTableOffset); 174 + LOG_DBG("XTC", "Failed to seek to page table at %llu", m_header.pageTableOffset); 177 175 return XtcError::READ_ERROR; 178 176 } 179 177 ··· 184 182 PageTableEntry entry; 185 183 size_t bytesRead = m_file.read(reinterpret_cast<uint8_t*>(&entry), sizeof(PageTableEntry)); 186 184 if (bytesRead != sizeof(PageTableEntry)) { 187 - Serial.printf("[%lu] [XTC] Failed to read page table entry %u\n", millis(), i); 185 + LOG_DBG("XTC", "Failed to read page table entry %u", i); 188 186 return XtcError::READ_ERROR; 189 187 } 190 188 ··· 201 199 } 202 200 } 203 201 204 - Serial.printf("[%lu] [XTC] Read %u page table entries\n", millis(), m_header.pageCount); 202 + LOG_DBG("XTC", "Read %u page table entries", m_header.pageCount); 205 203 return XtcError::OK; 206 204 } 207 205 ··· 307 305 } 308 306 309 307 m_hasChapters = !m_chapters.empty(); 310 - Serial.printf("[%lu] [XTC] Chapters: %u\n", millis(), static_cast<unsigned int>(m_chapters.size())); 308 + LOG_DBG("XTC", "Chapters: %u", static_cast<unsigned int>(m_chapters.size())); 311 309 return XtcError::OK; 312 310 } 313 311 ··· 334 332 335 333 // Seek to page data 336 334 if (!m_file.seek(page.offset)) { 337 - Serial.printf("[%lu] [XTC] Failed to seek to page %u at offset %lu\n", millis(), pageIndex, page.offset); 335 + LOG_DBG("XTC", "Failed to seek to page %u at offset %lu", pageIndex, page.offset); 338 336 m_lastError = XtcError::READ_ERROR; 339 337 return 0; 340 338 } ··· 343 341 XtgPageHeader pageHeader; 344 342 size_t headerRead = m_file.read(reinterpret_cast<uint8_t*>(&pageHeader), sizeof(XtgPageHeader)); 345 343 if (headerRead != sizeof(XtgPageHeader)) { 346 - Serial.printf("[%lu] [XTC] Failed to read page header for page %u\n", millis(), pageIndex); 344 + LOG_DBG("XTC", "Failed to read page header for page %u", pageIndex); 347 345 m_lastError = XtcError::READ_ERROR; 348 346 return 0; 349 347 } ··· 351 349 // Verify page magic (XTG for 1-bit, XTH for 2-bit) 352 350 const uint32_t expectedMagic = (m_bitDepth == 2) ? XTH_MAGIC : XTG_MAGIC; 353 351 if (pageHeader.magic != expectedMagic) { 354 - Serial.printf("[%lu] [XTC] Invalid page magic for page %u: 0x%08X (expected 0x%08X)\n", millis(), pageIndex, 355 - pageHeader.magic, expectedMagic); 352 + LOG_DBG("XTC", "Invalid page magic for page %u: 0x%08X (expected 0x%08X)", pageIndex, pageHeader.magic, 353 + expectedMagic); 356 354 m_lastError = XtcError::INVALID_MAGIC; 357 355 return 0; 358 356 } ··· 370 368 371 369 // Check buffer size 372 370 if (bufferSize < bitmapSize) { 373 - Serial.printf("[%lu] [XTC] Buffer too small: need %u, have %u\n", millis(), bitmapSize, bufferSize); 371 + LOG_DBG("XTC", "Buffer too small: need %u, have %u", bitmapSize, bufferSize); 374 372 m_lastError = XtcError::MEMORY_ERROR; 375 373 return 0; 376 374 } ··· 378 376 // Read bitmap data 379 377 size_t bytesRead = m_file.read(buffer, bitmapSize); 380 378 if (bytesRead != bitmapSize) { 381 - Serial.printf("[%lu] [XTC] Page read error: expected %u, got %u\n", millis(), bitmapSize, bytesRead); 379 + LOG_DBG("XTC", "Page read error: expected %u, got %u", bitmapSize, bytesRead); 382 380 m_lastError = XtcError::READ_ERROR; 383 381 return 0; 384 382 }
+24 -25
lib/ZipFile/ZipFile.cpp
··· 1 1 #include "ZipFile.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <miniz.h> 6 6 7 7 #include <algorithm> ··· 10 10 // Setup inflator 11 11 const auto inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor))); 12 12 if (!inflator) { 13 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for inflator\n", millis()); 13 + LOG_ERR("ZIP", "Failed to allocate memory for inflator"); 14 14 return false; 15 15 } 16 16 memset(inflator, 0, sizeof(tinfl_decompressor)); ··· 23 23 free(inflator); 24 24 25 25 if (status != TINFL_STATUS_DONE) { 26 - Serial.printf("[%lu] [ZIP] tinfl_decompress() failed with status %d\n", millis(), status); 26 + LOG_ERR("ZIP", "tinfl_decompress() failed with status %d", status); 27 27 return false; 28 28 } 29 29 ··· 195 195 } 196 196 197 197 if (read != localHeaderSize) { 198 - Serial.printf("[%lu] [ZIP] Something went wrong reading the local header\n", millis()); 198 + LOG_ERR("ZIP", "Something went wrong reading the local header"); 199 199 return -1; 200 200 } 201 201 202 202 if (pLocalHeader[0] + (pLocalHeader[1] << 8) + (pLocalHeader[2] << 16) + (pLocalHeader[3] << 24) != 203 203 0x04034b50 /* MZ_ZIP_LOCAL_DIR_HEADER_SIG */) { 204 - Serial.printf("[%lu] [ZIP] Not a valid zip file header\n", millis()); 204 + LOG_ERR("ZIP", "Not a valid zip file header"); 205 205 return -1; 206 206 } 207 207 ··· 222 222 223 223 const size_t fileSize = file.size(); 224 224 if (fileSize < 22) { 225 - Serial.printf("[%lu] [ZIP] File too small to be a valid zip\n", millis()); 225 + LOG_ERR("ZIP", "File too small to be a valid zip"); 226 226 if (!wasOpen) { 227 227 close(); 228 228 } ··· 234 234 const int scanRange = fileSize > 1024 ? 1024 : fileSize; 235 235 const auto buffer = static_cast<uint8_t*>(malloc(scanRange)); 236 236 if (!buffer) { 237 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for EOCD scan buffer\n", millis()); 237 + LOG_ERR("ZIP", "Failed to allocate memory for EOCD scan buffer"); 238 238 if (!wasOpen) { 239 239 close(); 240 240 } ··· 255 255 } 256 256 257 257 if (foundOffset == -1) { 258 - Serial.printf("[%lu] [ZIP] EOCD signature not found in zip file\n", millis()); 258 + LOG_ERR("ZIP", "EOCD signature not found in zip file"); 259 259 free(buffer); 260 260 if (!wasOpen) { 261 261 close(); ··· 407 407 const auto dataSize = trailingNullByte ? inflatedDataSize + 1 : inflatedDataSize; 408 408 const auto data = static_cast<uint8_t*>(malloc(dataSize)); 409 409 if (data == nullptr) { 410 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for output buffer (%zu bytes)\n", millis(), dataSize); 410 + LOG_ERR("ZIP", "Failed to allocate memory for output buffer (%zu bytes)", dataSize); 411 411 if (!wasOpen) { 412 412 close(); 413 413 } ··· 422 422 } 423 423 424 424 if (dataRead != inflatedDataSize) { 425 - Serial.printf("[%lu] [ZIP] Failed to read data\n", millis()); 425 + LOG_ERR("ZIP", "Failed to read data"); 426 426 free(data); 427 427 return nullptr; 428 428 } ··· 432 432 // Read out deflated content from file 433 433 const auto deflatedData = static_cast<uint8_t*>(malloc(deflatedDataSize)); 434 434 if (deflatedData == nullptr) { 435 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for decompression buffer\n", millis()); 435 + LOG_ERR("ZIP", "Failed to allocate memory for decompression buffer"); 436 436 if (!wasOpen) { 437 437 close(); 438 438 } ··· 445 445 } 446 446 447 447 if (dataRead != deflatedDataSize) { 448 - Serial.printf("[%lu] [ZIP] Failed to read data, expected %d got %d\n", millis(), deflatedDataSize, dataRead); 448 + LOG_ERR("ZIP", "Failed to read data, expected %d got %d", deflatedDataSize, dataRead); 449 449 free(deflatedData); 450 450 free(data); 451 451 return nullptr; ··· 455 455 free(deflatedData); 456 456 457 457 if (!success) { 458 - Serial.printf("[%lu] [ZIP] Failed to inflate file\n", millis()); 458 + LOG_ERR("ZIP", "Failed to inflate file"); 459 459 free(data); 460 460 return nullptr; 461 461 } 462 462 463 463 // Continue out of block with data set 464 464 } else { 465 - Serial.printf("[%lu] [ZIP] Unsupported compression method\n", millis()); 465 + LOG_ERR("ZIP", "Unsupported compression method"); 466 466 if (!wasOpen) { 467 467 close(); 468 468 } ··· 498 498 // no deflation, just read content 499 499 const auto buffer = static_cast<uint8_t*>(malloc(chunkSize)); 500 500 if (!buffer) { 501 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for buffer\n", millis()); 501 + LOG_ERR("ZIP", "Failed to allocate memory for buffer"); 502 502 if (!wasOpen) { 503 503 close(); 504 504 } ··· 509 509 while (remaining > 0) { 510 510 const size_t dataRead = file.read(buffer, remaining < chunkSize ? remaining : chunkSize); 511 511 if (dataRead == 0) { 512 - Serial.printf("[%lu] [ZIP] Could not read more bytes\n", millis()); 512 + LOG_ERR("ZIP", "Could not read more bytes"); 513 513 free(buffer); 514 514 if (!wasOpen) { 515 515 close(); ··· 532 532 // Setup inflator 533 533 const auto inflator = static_cast<tinfl_decompressor*>(malloc(sizeof(tinfl_decompressor))); 534 534 if (!inflator) { 535 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for inflator\n", millis()); 535 + LOG_ERR("ZIP", "Failed to allocate memory for inflator"); 536 536 if (!wasOpen) { 537 537 close(); 538 538 } ··· 544 544 // Setup file read buffer 545 545 const auto fileReadBuffer = static_cast<uint8_t*>(malloc(chunkSize)); 546 546 if (!fileReadBuffer) { 547 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for zip file read buffer\n", millis()); 547 + LOG_ERR("ZIP", "Failed to allocate memory for zip file read buffer"); 548 548 free(inflator); 549 549 if (!wasOpen) { 550 550 close(); ··· 554 554 555 555 const auto outputBuffer = static_cast<uint8_t*>(malloc(TINFL_LZ_DICT_SIZE)); 556 556 if (!outputBuffer) { 557 - Serial.printf("[%lu] [ZIP] Failed to allocate memory for dictionary\n", millis()); 557 + LOG_ERR("ZIP", "Failed to allocate memory for dictionary"); 558 558 free(inflator); 559 559 free(fileReadBuffer); 560 560 if (!wasOpen) { ··· 605 605 if (outBytes > 0) { 606 606 processedOutputBytes += outBytes; 607 607 if (out.write(outputBuffer + outputCursor, outBytes) != outBytes) { 608 - Serial.printf("[%lu] [ZIP] Failed to write all output bytes to stream\n", millis()); 608 + LOG_ERR("ZIP", "Failed to write all output bytes to stream"); 609 609 if (!wasOpen) { 610 610 close(); 611 611 } ··· 619 619 } 620 620 621 621 if (status < 0) { 622 - Serial.printf("[%lu] [ZIP] tinfl_decompress() failed with status %d\n", millis(), status); 622 + LOG_ERR("ZIP", "tinfl_decompress() failed with status %d", status); 623 623 if (!wasOpen) { 624 624 close(); 625 625 } ··· 630 630 } 631 631 632 632 if (status == TINFL_STATUS_DONE) { 633 - Serial.printf("[%lu] [ZIP] Decompressed %d bytes into %d bytes\n", millis(), deflatedDataSize, 634 - inflatedDataSize); 633 + LOG_ERR("ZIP", "Decompressed %d bytes into %d bytes", deflatedDataSize, inflatedDataSize); 635 634 if (!wasOpen) { 636 635 close(); 637 636 } ··· 643 642 } 644 643 645 644 // If we get here, EOF reached without TINFL_STATUS_DONE 646 - Serial.printf("[%lu] [ZIP] Unexpected EOF\n", millis()); 645 + LOG_ERR("ZIP", "Unexpected EOF"); 647 646 if (!wasOpen) { 648 647 close(); 649 648 } ··· 657 656 close(); 658 657 } 659 658 660 - Serial.printf("[%lu] [ZIP] Unsupported compression method\n", millis()); 659 + LOG_ERR("ZIP", "Unsupported compression method"); 661 660 return false; 662 661 }
+16
platformio.ini
··· 54 54 build_flags = 55 55 ${base.build_flags} 56 56 -DCROSSPOINT_VERSION=\"${crosspoint.version}-dev\" 57 + -DENABLE_SERIAL_LOG 58 + -DLOG_LEVEL=2 ; Set log level to debug for development builds 59 + 57 60 58 61 [env:gh_release] 59 62 extends = base 60 63 build_flags = 61 64 ${base.build_flags} 62 65 -DCROSSPOINT_VERSION=\"${crosspoint.version}\" 66 + -DENABLE_SERIAL_LOG 67 + -DLOG_LEVEL=0 ; Set log level to error for release builds 63 68 64 69 [env:gh_release_rc] 65 70 extends = base 66 71 build_flags = 67 72 ${base.build_flags} 68 73 -DCROSSPOINT_VERSION=\"${crosspoint.version}-rc+${sysenv.CROSSPOINT_RC_HASH}\" 74 + -DENABLE_SERIAL_LOG 75 + -DLOG_LEVEL=1 ; Set log level to info for release candidate builds 76 + 77 + [env:slim] 78 + extends = base 79 + build_flags = 80 + ${base.build_flags} 81 + -DCROSSPOINT_VERSION=\"${crosspoint.version}-slim\" 82 + ; serial output is disabled in slim builds to save space 83 + -UENABLE_SERIAL_LOG 84 +
+4 -4
src/CrossPointSettings.cpp
··· 1 1 #include "CrossPointSettings.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <Serialization.h> 6 6 7 7 #include <cstring> ··· 121 121 // New fields added at end for backward compatibility 122 122 outputFile.close(); 123 123 124 - Serial.printf("[%lu] [CPS] Settings saved to file\n", millis()); 124 + LOG_DBG("CPS", "Settings saved to file"); 125 125 return true; 126 126 } 127 127 ··· 134 134 uint8_t version; 135 135 serialization::readPod(inputFile, version); 136 136 if (version != SETTINGS_FILE_VERSION) { 137 - Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version); 137 + LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version); 138 138 inputFile.close(); 139 139 return false; 140 140 } ··· 233 233 } 234 234 235 235 inputFile.close(); 236 - Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis()); 236 + LOG_DBG("CPS", "Settings loaded from file"); 237 237 return true; 238 238 } 239 239
+2 -2
src/CrossPointState.cpp
··· 1 1 #include "CrossPointState.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <Serialization.h> 6 6 7 7 namespace { ··· 35 35 uint8_t version; 36 36 serialization::readPod(inputFile, version); 37 37 if (version > STATE_FILE_VERSION) { 38 - Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version); 38 + LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version); 39 39 inputFile.close(); 40 40 return false; 41 41 }
+5 -5
src/RecentBooksStore.cpp
··· 2 2 3 3 #include <Epub.h> 4 4 #include <HalStorage.h> 5 - #include <HardwareSerial.h> 5 + #include <Logging.h> 6 6 #include <Serialization.h> 7 7 #include <Xtc.h> 8 8 ··· 72 72 } 73 73 74 74 outputFile.close(); 75 - Serial.printf("[%lu] [RBS] Recent books saved to file (%d entries)\n", millis(), count); 75 + LOG_DBG("RBS", "Recent books saved to file (%d entries)", count); 76 76 return true; 77 77 } 78 78 ··· 83 83 lastBookFileName = path.substr(lastSlash + 1); 84 84 } 85 85 86 - Serial.printf("[%lu] [RBS] Loading recent book: %s\n", millis(), path.c_str()); 86 + LOG_DBG("RBS", "Loading recent book: %s", path.c_str()); 87 87 88 88 // If epub, try to load the metadata for title/author and cover 89 89 if (StringUtils::checkFileExtension(lastBookFileName, ".epub")) { ··· 136 136 } 137 137 } 138 138 } else { 139 - Serial.printf("[%lu] [RBS] Deserialization failed: Unknown version %u\n", millis(), version); 139 + LOG_ERR("RBS", "Deserialization failed: Unknown version %u", version); 140 140 inputFile.close(); 141 141 return false; 142 142 } ··· 158 158 } 159 159 160 160 inputFile.close(); 161 - Serial.printf("[%lu] [RBS] Recent books loaded from file (%d entries)\n", millis(), recentBooks.size()); 161 + LOG_DBG("RBS", "Recent books loaded from file (%d entries)", recentBooks.size()); 162 162 return true; 163 163 }
+13 -15
src/WifiCredentialStore.cpp
··· 1 1 #include "WifiCredentialStore.h" 2 2 3 3 #include <HalStorage.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <Serialization.h> 6 6 7 7 // Initialize the static instance ··· 21 21 } // namespace 22 22 23 23 void WifiCredentialStore::obfuscate(std::string& data) const { 24 - Serial.printf("[%lu] [WCS] Obfuscating/deobfuscating %zu bytes\n", millis(), data.size()); 24 + LOG_DBG("WCS", "Obfuscating/deobfuscating %zu bytes", data.size()); 25 25 for (size_t i = 0; i < data.size(); i++) { 26 26 data[i] ^= OBFUSCATION_KEY[i % KEY_LENGTH]; 27 27 } ··· 45 45 for (const auto& cred : credentials) { 46 46 // Write SSID (plaintext - not sensitive) 47 47 serialization::writeString(file, cred.ssid); 48 - Serial.printf("[%lu] [WCS] Saving SSID: %s, password length: %zu\n", millis(), cred.ssid.c_str(), 49 - cred.password.size()); 48 + LOG_DBG("WCS", "Saving SSID: %s, password length: %zu", cred.ssid.c_str(), cred.password.size()); 50 49 51 50 // Write password (obfuscated) 52 51 std::string obfuscatedPwd = cred.password; ··· 55 54 } 56 55 57 56 file.close(); 58 - Serial.printf("[%lu] [WCS] Saved %zu WiFi credentials to file\n", millis(), credentials.size()); 57 + LOG_DBG("WCS", "Saved %zu WiFi credentials to file", credentials.size()); 59 58 return true; 60 59 } 61 60 ··· 69 68 uint8_t version; 70 69 serialization::readPod(file, version); 71 70 if (version > WIFI_FILE_VERSION) { 72 - Serial.printf("[%lu] [WCS] Unknown file version: %u\n", millis(), version); 71 + LOG_DBG("WCS", "Unknown file version: %u", version); 73 72 file.close(); 74 73 return false; 75 74 } ··· 94 93 95 94 // Read and deobfuscate password 96 95 serialization::readString(file, cred.password); 97 - Serial.printf("[%lu] [WCS] Loaded SSID: %s, obfuscated password length: %zu\n", millis(), cred.ssid.c_str(), 98 - cred.password.size()); 96 + LOG_DBG("WCS", "Loaded SSID: %s, obfuscated password length: %zu", cred.ssid.c_str(), cred.password.size()); 99 97 obfuscate(cred.password); // XOR is symmetric, so same function deobfuscates 100 - Serial.printf("[%lu] [WCS] After deobfuscation, password length: %zu\n", millis(), cred.password.size()); 98 + LOG_DBG("WCS", "After deobfuscation, password length: %zu", cred.password.size()); 101 99 102 100 credentials.push_back(cred); 103 101 } 104 102 105 103 file.close(); 106 - Serial.printf("[%lu] [WCS] Loaded %zu WiFi credentials from file\n", millis(), credentials.size()); 104 + LOG_DBG("WCS", "Loaded %zu WiFi credentials from file", credentials.size()); 107 105 return true; 108 106 } 109 107 ··· 113 111 [&ssid](const WifiCredential& cred) { return cred.ssid == ssid; }); 114 112 if (cred != credentials.end()) { 115 113 cred->password = password; 116 - Serial.printf("[%lu] [WCS] Updated credentials for: %s\n", millis(), ssid.c_str()); 114 + LOG_DBG("WCS", "Updated credentials for: %s", ssid.c_str()); 117 115 return saveToFile(); 118 116 } 119 117 120 118 // Check if we've reached the limit 121 119 if (credentials.size() >= MAX_NETWORKS) { 122 - Serial.printf("[%lu] [WCS] Cannot add more networks, limit of %zu reached\n", millis(), MAX_NETWORKS); 120 + LOG_DBG("WCS", "Cannot add more networks, limit of %zu reached", MAX_NETWORKS); 123 121 return false; 124 122 } 125 123 126 124 // Add new credential 127 125 credentials.push_back({ssid, password}); 128 - Serial.printf("[%lu] [WCS] Added credentials for: %s\n", millis(), ssid.c_str()); 126 + LOG_DBG("WCS", "Added credentials for: %s", ssid.c_str()); 129 127 return saveToFile(); 130 128 } 131 129 ··· 134 132 [&ssid](const WifiCredential& cred) { return cred.ssid == ssid; }); 135 133 if (cred != credentials.end()) { 136 134 credentials.erase(cred); 137 - Serial.printf("[%lu] [WCS] Removed credentials for: %s\n", millis(), ssid.c_str()); 135 + LOG_DBG("WCS", "Removed credentials for: %s", ssid.c_str()); 138 136 if (ssid == lastConnectedSsid) { 139 137 clearLastConnectedSsid(); 140 138 } ··· 176 174 credentials.clear(); 177 175 lastConnectedSsid.clear(); 178 176 saveToFile(); 179 - Serial.printf("[%lu] [WCS] Cleared all WiFi credentials\n", millis()); 177 + LOG_DBG("WCS", "Cleared all WiFi credentials"); 180 178 }
+3 -3
src/activities/Activity.h
··· 1 1 #pragma once 2 2 3 - #include <HardwareSerial.h> 3 + #include <Logging.h> 4 4 5 5 #include <string> 6 6 #include <utility> ··· 18 18 explicit Activity(std::string name, GfxRenderer& renderer, MappedInputManager& mappedInput) 19 19 : name(std::move(name)), renderer(renderer), mappedInput(mappedInput) {} 20 20 virtual ~Activity() = default; 21 - virtual void onEnter() { Serial.printf("[%lu] [ACT] Entering activity: %s\n", millis(), name.c_str()); } 22 - virtual void onExit() { Serial.printf("[%lu] [ACT] Exiting activity: %s\n", millis(), name.c_str()); } 21 + virtual void onEnter() { LOG_DBG("ACT", "Entering activity: %s", name.c_str()); } 22 + virtual void onExit() { LOG_DBG("ACT", "Exiting activity: %s", name.c_str()); } 23 23 virtual void loop() {} 24 24 virtual bool skipLoopDelay() { return false; } 25 25 virtual bool preventAutoSleep() { return false; }
+18 -19
src/activities/boot_sleep/SleepActivity.cpp
··· 50 50 } 51 51 52 52 if (filename.substr(filename.length() - 4) != ".bmp") { 53 - Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), name); 53 + LOG_DBG("SLP", "Skipping non-.bmp file name: %s", name); 54 54 file.close(); 55 55 continue; 56 56 } 57 57 Bitmap bitmap(file); 58 58 if (bitmap.parseHeaders() != BmpReaderError::Ok) { 59 - Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), name); 59 + LOG_DBG("SLP", "Skipping invalid BMP file: %s", name); 60 60 file.close(); 61 61 continue; 62 62 } ··· 76 76 const auto filename = "/sleep/" + files[randomFileIndex]; 77 77 FsFile file; 78 78 if (Storage.openFileForRead("SLP", filename, file)) { 79 - Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str()); 79 + LOG_DBG("SLP", "Randomly loading: /sleep/%s", files[randomFileIndex].c_str()); 80 80 delay(100); 81 81 Bitmap bitmap(file, true); 82 82 if (bitmap.parseHeaders() == BmpReaderError::Ok) { ··· 95 95 if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) { 96 96 Bitmap bitmap(file, true); 97 97 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 98 - Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis()); 98 + LOG_DBG("SLP", "Loading: /sleep.bmp"); 99 99 renderBitmapSleepScreen(bitmap); 100 100 return; 101 101 } ··· 127 127 const auto pageHeight = renderer.getScreenHeight(); 128 128 float cropX = 0, cropY = 0; 129 129 130 - Serial.printf("[%lu] [SLP] bitmap %d x %d, screen %d x %d\n", millis(), bitmap.getWidth(), bitmap.getHeight(), 131 - pageWidth, pageHeight); 130 + LOG_DBG("SLP", "bitmap %d x %d, screen %d x %d", bitmap.getWidth(), bitmap.getHeight(), pageWidth, pageHeight); 132 131 if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) { 133 132 // image will scale, make sure placement is right 134 133 float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight()); 135 134 const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight); 136 135 137 - Serial.printf("[%lu] [SLP] bitmap ratio: %f, screen ratio: %f\n", millis(), ratio, screenRatio); 136 + LOG_DBG("SLP", "bitmap ratio: %f, screen ratio: %f", ratio, screenRatio); 138 137 if (ratio > screenRatio) { 139 138 // image wider than viewport ratio, scaled down image needs to be centered vertically 140 139 if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) { 141 140 cropX = 1.0f - (screenRatio / ratio); 142 - Serial.printf("[%lu] [SLP] Cropping bitmap x: %f\n", millis(), cropX); 141 + LOG_DBG("SLP", "Cropping bitmap x: %f", cropX); 143 142 ratio = (1.0f - cropX) * static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight()); 144 143 } 145 144 x = 0; 146 145 y = std::round((static_cast<float>(pageHeight) - static_cast<float>(pageWidth) / ratio) / 2); 147 - Serial.printf("[%lu] [SLP] Centering with ratio %f to y=%d\n", millis(), ratio, y); 146 + LOG_DBG("SLP", "Centering with ratio %f to y=%d", ratio, y); 148 147 } else { 149 148 // image taller than viewport ratio, scaled down image needs to be centered horizontally 150 149 if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) { 151 150 cropY = 1.0f - (ratio / screenRatio); 152 - Serial.printf("[%lu] [SLP] Cropping bitmap y: %f\n", millis(), cropY); 151 + LOG_DBG("SLP", "Cropping bitmap y: %f", cropY); 153 152 ratio = static_cast<float>(bitmap.getWidth()) / ((1.0f - cropY) * static_cast<float>(bitmap.getHeight())); 154 153 } 155 154 x = std::round((static_cast<float>(pageWidth) - static_cast<float>(pageHeight) * ratio) / 2); 156 155 y = 0; 157 - Serial.printf("[%lu] [SLP] Centering with ratio %f to x=%d\n", millis(), ratio, x); 156 + LOG_DBG("SLP", "Centering with ratio %f to x=%d", ratio, x); 158 157 } 159 158 } else { 160 159 // center the image ··· 162 161 y = (pageHeight - bitmap.getHeight()) / 2; 163 162 } 164 163 165 - Serial.printf("[%lu] [SLP] drawing to %d x %d\n", millis(), x, y); 164 + LOG_DBG("SLP", "drawing to %d x %d", x, y); 166 165 renderer.clearScreen(); 167 166 168 167 const bool hasGreyscale = bitmap.hasGreyscale() && ··· 218 217 // Handle XTC file 219 218 Xtc lastXtc(APP_STATE.openEpubPath, "/.crosspoint"); 220 219 if (!lastXtc.load()) { 221 - Serial.printf("[%lu] [SLP] Failed to load last XTC\n", millis()); 220 + LOG_ERR("SLP", "Failed to load last XTC"); 222 221 return (this->*renderNoCoverSleepScreen)(); 223 222 } 224 223 225 224 if (!lastXtc.generateCoverBmp()) { 226 - Serial.printf("[%lu] [SLP] Failed to generate XTC cover bmp\n", millis()); 225 + LOG_ERR("SLP", "Failed to generate XTC cover bmp"); 227 226 return (this->*renderNoCoverSleepScreen)(); 228 227 } 229 228 ··· 232 231 // Handle TXT file - looks for cover image in the same folder 233 232 Txt lastTxt(APP_STATE.openEpubPath, "/.crosspoint"); 234 233 if (!lastTxt.load()) { 235 - Serial.printf("[%lu] [SLP] Failed to load last TXT\n", millis()); 234 + LOG_ERR("SLP", "Failed to load last TXT"); 236 235 return (this->*renderNoCoverSleepScreen)(); 237 236 } 238 237 239 238 if (!lastTxt.generateCoverBmp()) { 240 - Serial.printf("[%lu] [SLP] No cover image found for TXT file\n", millis()); 239 + LOG_ERR("SLP", "No cover image found for TXT file"); 241 240 return (this->*renderNoCoverSleepScreen)(); 242 241 } 243 242 ··· 247 246 Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint"); 248 247 // Skip loading css since we only need metadata here 249 248 if (!lastEpub.load(true, true)) { 250 - Serial.printf("[%lu] [SLP] Failed to load last epub\n", millis()); 249 + LOG_ERR("SLP", "Failed to load last epub"); 251 250 return (this->*renderNoCoverSleepScreen)(); 252 251 } 253 252 254 253 if (!lastEpub.generateCoverBmp(cropped)) { 255 - Serial.printf("[%lu] [SLP] Failed to generate cover bmp\n", millis()); 254 + LOG_ERR("SLP", "Failed to generate cover bmp"); 256 255 return (this->*renderNoCoverSleepScreen)(); 257 256 } 258 257 ··· 265 264 if (Storage.openFileForRead("SLP", coverBmpPath, file)) { 266 265 Bitmap bitmap(file); 267 266 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 268 - Serial.printf("[%lu] [SLP] Rendering sleep cover: %s\n", millis(), coverBmpPath.c_str()); 267 + LOG_DBG("SLP", "Rendering sleep cover: %s", coverBmpPath.c_str()); 269 268 renderBitmapSleepScreen(bitmap); 270 269 return; 271 270 }
+10 -10
src/activities/browser/OpdsBookBrowserActivity.cpp
··· 2 2 3 3 #include <Epub.h> 4 4 #include <GfxRenderer.h> 5 - #include <HardwareSerial.h> 5 + #include <Logging.h> 6 6 #include <OpdsStream.h> 7 7 #include <WiFi.h> 8 8 ··· 78 78 // Check if WiFi is still connected 79 79 if (WiFi.status() == WL_CONNECTED && WiFi.localIP() != IPAddress(0, 0, 0, 0)) { 80 80 // WiFi connected - just retry fetching the feed 81 - Serial.printf("[%lu] [OPDS] Retry: WiFi connected, retrying fetch\n", millis()); 81 + LOG_DBG("OPDS", "Retry: WiFi connected, retrying fetch"); 82 82 state = BrowserState::LOADING; 83 83 statusMessage = "Loading..."; 84 84 updateRequired = true; 85 85 fetchFeed(currentPath); 86 86 } else { 87 87 // WiFi not connected - launch WiFi selection 88 - Serial.printf("[%lu] [OPDS] Retry: WiFi not connected, launching selection\n", millis()); 88 + LOG_DBG("OPDS", "Retry: WiFi not connected, launching selection"); 89 89 launchWifiSelection(); 90 90 } 91 91 } else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) { ··· 265 265 } 266 266 267 267 std::string url = UrlUtils::buildUrl(serverUrl, path); 268 - Serial.printf("[%lu] [OPDS] Fetching: %s\n", millis(), url.c_str()); 268 + LOG_DBG("OPDS", "Fetching: %s", url.c_str()); 269 269 270 270 OpdsParser parser; 271 271 ··· 287 287 } 288 288 289 289 entries = std::move(parser).getEntries(); 290 - Serial.printf("[%lu] [OPDS] Found %d entries\n", millis(), entries.size()); 290 + LOG_DBG("OPDS", "Found %d entries", entries.size()); 291 291 selectorIndex = 0; 292 292 293 293 if (entries.empty()) { ··· 351 351 } 352 352 std::string filename = "/" + StringUtils::sanitizeFilename(baseName) + ".epub"; 353 353 354 - Serial.printf("[%lu] [OPDS] Downloading: %s -> %s\n", millis(), downloadUrl.c_str(), filename.c_str()); 354 + LOG_DBG("OPDS", "Downloading: %s -> %s", downloadUrl.c_str(), filename.c_str()); 355 355 356 356 const auto result = 357 357 HttpDownloader::downloadToFile(downloadUrl, filename, [this](const size_t downloaded, const size_t total) { ··· 361 361 }); 362 362 363 363 if (result == HttpDownloader::OK) { 364 - Serial.printf("[%lu] [OPDS] Download complete: %s\n", millis(), filename.c_str()); 364 + LOG_DBG("OPDS", "Download complete: %s", filename.c_str()); 365 365 366 366 // Invalidate any existing cache for this file to prevent stale metadata issues 367 367 Epub epub(filename, "/.crosspoint"); 368 368 epub.clearCache(); 369 - Serial.printf("[%lu] [OPDS] Cleared cache for: %s\n", millis(), filename.c_str()); 369 + LOG_DBG("OPDS", "Cleared cache for: %s", filename.c_str()); 370 370 371 371 state = BrowserState::BROWSING; 372 372 updateRequired = true; ··· 403 403 exitActivity(); 404 404 405 405 if (connected) { 406 - Serial.printf("[%lu] [OPDS] WiFi connected via selection, fetching feed\n", millis()); 406 + LOG_DBG("OPDS", "WiFi connected via selection, fetching feed"); 407 407 state = BrowserState::LOADING; 408 408 statusMessage = "Loading..."; 409 409 updateRequired = true; 410 410 fetchFeed(currentPath); 411 411 } else { 412 - Serial.printf("[%lu] [OPDS] WiFi selection cancelled/failed\n", millis()); 412 + LOG_DBG("OPDS", "WiFi selection cancelled/failed"); 413 413 // Force disconnect to ensure clean state for next retry 414 414 // This prevents stale connection status from interfering 415 415 WiFi.disconnect();
+1 -1
src/activities/home/RecentBooksActivity.cpp
··· 73 73 74 74 if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) { 75 75 if (!recentBooks.empty() && selectorIndex < static_cast<int>(recentBooks.size())) { 76 - Serial.printf("[%lu] [RBA] Selected recent book: %s\n", millis(), recentBooks[selectorIndex].path.c_str()); 76 + LOG_DBG("RBA", "Selected recent book: %s", recentBooks[selectorIndex].path.c_str()); 77 77 onSelectBook(recentBooks[selectorIndex].path); 78 78 return; 79 79 }
+2 -2
src/activities/network/CalibreConnectActivity.cpp
··· 96 96 97 97 if (MDNS.begin(HOSTNAME)) { 98 98 // mDNS is optional for the Calibre plugin but still helpful for users. 99 - Serial.printf("[%lu] [CAL] mDNS started: http://%s.local/\n", millis(), HOSTNAME); 99 + LOG_DBG("CAL", "mDNS started: http://%s.local/", HOSTNAME); 100 100 } 101 101 102 102 webServer.reset(new CrossPointWebServer()); ··· 131 131 if (webServer && webServer->isRunning()) { 132 132 const unsigned long timeSinceLastHandleClient = millis() - lastHandleClientTime; 133 133 if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) { 134 - Serial.printf("[%lu] [CAL] WARNING: %lu ms gap since last handleClient\n", millis(), timeSinceLastHandleClient); 134 + LOG_DBG("CAL", "WARNING: %lu ms gap since last handleClient", timeSinceLastHandleClient); 135 135 } 136 136 137 137 esp_task_wdt_reset();
+39 -40
src/activities/network/CrossPointWebServerActivity.cpp
··· 37 37 void CrossPointWebServerActivity::onEnter() { 38 38 ActivityWithSubactivity::onEnter(); 39 39 40 - Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onEnter: %d bytes\n", millis(), ESP.getFreeHeap()); 40 + LOG_DBG("WEBACT] [MEM", "Free heap at onEnter: %d bytes", ESP.getFreeHeap()); 41 41 42 42 renderingMutex = xSemaphoreCreateMutex(); 43 43 ··· 58 58 ); 59 59 60 60 // Launch network mode selection subactivity 61 - Serial.printf("[%lu] [WEBACT] Launching NetworkModeSelectionActivity...\n", millis()); 61 + LOG_DBG("WEBACT", "Launching NetworkModeSelectionActivity..."); 62 62 enterNewActivity(new NetworkModeSelectionActivity( 63 63 renderer, mappedInput, [this](const NetworkMode mode) { onNetworkModeSelected(mode); }, 64 64 [this]() { onGoBack(); } // Cancel goes back to home ··· 68 68 void CrossPointWebServerActivity::onExit() { 69 69 ActivityWithSubactivity::onExit(); 70 70 71 - Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap()); 71 + LOG_DBG("WEBACT] [MEM", "Free heap at onExit start: %d bytes", ESP.getFreeHeap()); 72 72 73 73 state = WebServerActivityState::SHUTTING_DOWN; 74 74 ··· 80 80 81 81 // Stop DNS server if running (AP mode) 82 82 if (dnsServer) { 83 - Serial.printf("[%lu] [WEBACT] Stopping DNS server...\n", millis()); 83 + LOG_DBG("WEBACT", "Stopping DNS server..."); 84 84 dnsServer->stop(); 85 85 delete dnsServer; 86 86 dnsServer = nullptr; ··· 91 91 92 92 // Disconnect WiFi gracefully 93 93 if (isApMode) { 94 - Serial.printf("[%lu] [WEBACT] Stopping WiFi AP...\n", millis()); 94 + LOG_DBG("WEBACT", "Stopping WiFi AP..."); 95 95 WiFi.softAPdisconnect(true); 96 96 } else { 97 - Serial.printf("[%lu] [WEBACT] Disconnecting WiFi (graceful)...\n", millis()); 97 + LOG_DBG("WEBACT", "Disconnecting WiFi (graceful)..."); 98 98 WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame 99 99 } 100 100 delay(30); // Allow disconnect frame to be sent 101 101 102 - Serial.printf("[%lu] [WEBACT] Setting WiFi mode OFF...\n", millis()); 102 + LOG_DBG("WEBACT", "Setting WiFi mode OFF..."); 103 103 WiFi.mode(WIFI_OFF); 104 104 delay(30); // Allow WiFi hardware to power down 105 105 106 - Serial.printf("[%lu] [WEBACT] [MEM] Free heap after WiFi disconnect: %d bytes\n", millis(), ESP.getFreeHeap()); 106 + LOG_DBG("WEBACT] [MEM", "Free heap after WiFi disconnect: %d bytes", ESP.getFreeHeap()); 107 107 108 108 // Acquire mutex before deleting task 109 - Serial.printf("[%lu] [WEBACT] Acquiring rendering mutex before task deletion...\n", millis()); 109 + LOG_DBG("WEBACT", "Acquiring rendering mutex before task deletion..."); 110 110 xSemaphoreTake(renderingMutex, portMAX_DELAY); 111 111 112 112 // Delete the display task 113 - Serial.printf("[%lu] [WEBACT] Deleting display task...\n", millis()); 113 + LOG_DBG("WEBACT", "Deleting display task..."); 114 114 if (displayTaskHandle) { 115 115 vTaskDelete(displayTaskHandle); 116 116 displayTaskHandle = nullptr; 117 - Serial.printf("[%lu] [WEBACT] Display task deleted\n", millis()); 117 + LOG_DBG("WEBACT", "Display task deleted"); 118 118 } 119 119 120 120 // Delete the mutex 121 - Serial.printf("[%lu] [WEBACT] Deleting mutex...\n", millis()); 121 + LOG_DBG("WEBACT", "Deleting mutex..."); 122 122 vSemaphoreDelete(renderingMutex); 123 123 renderingMutex = nullptr; 124 - Serial.printf("[%lu] [WEBACT] Mutex deleted\n", millis()); 124 + LOG_DBG("WEBACT", "Mutex deleted"); 125 125 126 - Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap()); 126 + LOG_DBG("WEBACT] [MEM", "Free heap at onExit end: %d bytes", ESP.getFreeHeap()); 127 127 } 128 128 129 129 void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode) { ··· 133 133 } else if (mode == NetworkMode::CREATE_HOTSPOT) { 134 134 modeName = "Create Hotspot"; 135 135 } 136 - Serial.printf("[%lu] [WEBACT] Network mode selected: %s\n", millis(), modeName); 136 + LOG_DBG("WEBACT", "Network mode selected: %s", modeName); 137 137 138 138 networkMode = mode; 139 139 isApMode = (mode == NetworkMode::CREATE_HOTSPOT); ··· 155 155 156 156 if (mode == NetworkMode::JOIN_NETWORK) { 157 157 // STA mode - launch WiFi selection 158 - Serial.printf("[%lu] [WEBACT] Turning on WiFi (STA mode)...\n", millis()); 158 + LOG_DBG("WEBACT", "Turning on WiFi (STA mode)..."); 159 159 WiFi.mode(WIFI_STA); 160 160 161 161 state = WebServerActivityState::WIFI_SELECTION; 162 - Serial.printf("[%lu] [WEBACT] Launching WifiSelectionActivity...\n", millis()); 162 + LOG_DBG("WEBACT", "Launching WifiSelectionActivity..."); 163 163 enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, 164 164 [this](const bool connected) { onWifiSelectionComplete(connected); })); 165 165 } else { ··· 171 171 } 172 172 173 173 void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected) { 174 - Serial.printf("[%lu] [WEBACT] WifiSelectionActivity completed, connected=%d\n", millis(), connected); 174 + LOG_DBG("WEBACT", "WifiSelectionActivity completed, connected=%d", connected); 175 175 176 176 if (connected) { 177 177 // Get connection info before exiting subactivity ··· 183 183 184 184 // Start mDNS for hostname resolution 185 185 if (MDNS.begin(AP_HOSTNAME)) { 186 - Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME); 186 + LOG_DBG("WEBACT", "mDNS started: http://%s.local/", AP_HOSTNAME); 187 187 } 188 188 189 189 // Start the web server ··· 199 199 } 200 200 201 201 void CrossPointWebServerActivity::startAccessPoint() { 202 - Serial.printf("[%lu] [WEBACT] Starting Access Point mode...\n", millis()); 203 - Serial.printf("[%lu] [WEBACT] [MEM] Free heap before AP start: %d bytes\n", millis(), ESP.getFreeHeap()); 202 + LOG_DBG("WEBACT", "Starting Access Point mode..."); 203 + LOG_DBG("WEBACT] [MEM", "Free heap before AP start: %d bytes", ESP.getFreeHeap()); 204 204 205 205 // Configure and start the AP 206 206 WiFi.mode(WIFI_AP); ··· 216 216 } 217 217 218 218 if (!apStarted) { 219 - Serial.printf("[%lu] [WEBACT] ERROR: Failed to start Access Point!\n", millis()); 219 + LOG_ERR("WEBACT", "ERROR: Failed to start Access Point!"); 220 220 onGoBack(); 221 221 return; 222 222 } ··· 230 230 connectedIP = ipStr; 231 231 connectedSSID = AP_SSID; 232 232 233 - Serial.printf("[%lu] [WEBACT] Access Point started!\n", millis()); 234 - Serial.printf("[%lu] [WEBACT] SSID: %s\n", millis(), AP_SSID); 235 - Serial.printf("[%lu] [WEBACT] IP: %s\n", millis(), connectedIP.c_str()); 233 + LOG_DBG("WEBACT", "Access Point started!"); 234 + LOG_DBG("WEBACT", "SSID: %s", AP_SSID); 235 + LOG_DBG("WEBACT", "IP: %s", connectedIP.c_str()); 236 236 237 237 // Start mDNS for hostname resolution 238 238 if (MDNS.begin(AP_HOSTNAME)) { 239 - Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME); 239 + LOG_DBG("WEBACT", "mDNS started: http://%s.local/", AP_HOSTNAME); 240 240 } else { 241 - Serial.printf("[%lu] [WEBACT] WARNING: mDNS failed to start\n", millis()); 241 + LOG_DBG("WEBACT", "WARNING: mDNS failed to start"); 242 242 } 243 243 244 244 // Start DNS server for captive portal behavior ··· 246 246 dnsServer = new DNSServer(); 247 247 dnsServer->setErrorReplyCode(DNSReplyCode::NoError); 248 248 dnsServer->start(DNS_PORT, "*", apIP); 249 - Serial.printf("[%lu] [WEBACT] DNS server started for captive portal\n", millis()); 249 + LOG_DBG("WEBACT", "DNS server started for captive portal"); 250 250 251 - Serial.printf("[%lu] [WEBACT] [MEM] Free heap after AP start: %d bytes\n", millis(), ESP.getFreeHeap()); 251 + LOG_DBG("WEBACT] [MEM", "Free heap after AP start: %d bytes", ESP.getFreeHeap()); 252 252 253 253 // Start the web server 254 254 startWebServer(); 255 255 } 256 256 257 257 void CrossPointWebServerActivity::startWebServer() { 258 - Serial.printf("[%lu] [WEBACT] Starting web server...\n", millis()); 258 + LOG_DBG("WEBACT", "Starting web server..."); 259 259 260 260 // Create the web server instance 261 261 webServer.reset(new CrossPointWebServer()); ··· 263 263 264 264 if (webServer->isRunning()) { 265 265 state = WebServerActivityState::SERVER_RUNNING; 266 - Serial.printf("[%lu] [WEBACT] Web server started successfully\n", millis()); 266 + LOG_DBG("WEBACT", "Web server started successfully"); 267 267 268 268 // Force an immediate render since we're transitioning from a subactivity 269 269 // that had its own rendering task. We need to make sure our display is shown. 270 270 xSemaphoreTake(renderingMutex, portMAX_DELAY); 271 271 render(); 272 272 xSemaphoreGive(renderingMutex); 273 - Serial.printf("[%lu] [WEBACT] Rendered File Transfer screen\n", millis()); 273 + LOG_DBG("WEBACT", "Rendered File Transfer screen"); 274 274 } else { 275 - Serial.printf("[%lu] [WEBACT] ERROR: Failed to start web server!\n", millis()); 275 + LOG_ERR("WEBACT", "ERROR: Failed to start web server!"); 276 276 webServer.reset(); 277 277 // Go back on error 278 278 onGoBack(); ··· 281 281 282 282 void CrossPointWebServerActivity::stopWebServer() { 283 283 if (webServer && webServer->isRunning()) { 284 - Serial.printf("[%lu] [WEBACT] Stopping web server...\n", millis()); 284 + LOG_DBG("WEBACT", "Stopping web server..."); 285 285 webServer->stop(); 286 - Serial.printf("[%lu] [WEBACT] Web server stopped\n", millis()); 286 + LOG_DBG("WEBACT", "Web server stopped"); 287 287 } 288 288 webServer.reset(); 289 289 } ··· 309 309 lastWifiCheck = millis(); 310 310 const wl_status_t wifiStatus = WiFi.status(); 311 311 if (wifiStatus != WL_CONNECTED) { 312 - Serial.printf("[%lu] [WEBACT] WiFi disconnected! Status: %d\n", millis(), wifiStatus); 312 + LOG_DBG("WEBACT", "WiFi disconnected! Status: %d", wifiStatus); 313 313 // Show error and exit gracefully 314 314 state = WebServerActivityState::SHUTTING_DOWN; 315 315 updateRequired = true; ··· 318 318 // Log weak signal warnings 319 319 const int rssi = WiFi.RSSI(); 320 320 if (rssi < -75) { 321 - Serial.printf("[%lu] [WEBACT] Warning: Weak WiFi signal: %d dBm\n", millis(), rssi); 321 + LOG_DBG("WEBACT", "Warning: Weak WiFi signal: %d dBm", rssi); 322 322 } 323 323 } 324 324 } ··· 329 329 330 330 // Log if there's a significant gap between handleClient calls (>100ms) 331 331 if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) { 332 - Serial.printf("[%lu] [WEBACT] WARNING: %lu ms gap since last handleClient\n", millis(), 333 - timeSinceLastHandleClient); 332 + LOG_DBG("WEBACT", "WARNING: %lu ms gap since last handleClient", timeSinceLastHandleClient); 334 333 } 335 334 336 335 // Reset watchdog BEFORE processing - HTTP header parsing can be slow ··· 401 400 // The structure to manage the QR code 402 401 QRCode qrcode; 403 402 uint8_t qrcodeBytes[qrcode_getBufferSize(4)]; 404 - Serial.printf("[%lu] [WEBACT] QR Code (%lu): %s\n", millis(), data.length(), data.c_str()); 403 + LOG_DBG("WEBACT", "QR Code (%lu): %s", data.length(), data.c_str()); 405 404 406 405 qrcode_initText(&qrcode, qrcodeBytes, 4, ECC_LOW, data.c_str()); 407 406 const uint8_t px = 6; // pixels per module
+15 -16
src/activities/network/WifiSelectionActivity.cpp
··· 1 1 #include "WifiSelectionActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 + #include <Logging.h> 4 5 #include <WiFi.h> 5 6 6 7 #include <map> ··· 62 63 if (!lastSsid.empty()) { 63 64 const auto* cred = WIFI_STORE.findCredential(lastSsid); 64 65 if (cred) { 65 - Serial.printf("[%lu] [WIFI] Attempting to auto-connect to %s\n", millis(), lastSsid.c_str()); 66 + LOG_DBG("WIFI", "Attempting to auto-connect to %s", lastSsid.c_str()); 66 67 selectedSSID = cred->ssid; 67 68 enteredPassword = cred->password; 68 69 selectedRequiresPassword = !cred->password.empty(); ··· 82 83 void WifiSelectionActivity::onExit() { 83 84 Activity::onExit(); 84 85 85 - Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap()); 86 + LOG_DBG("WIFI] [MEM", "Free heap at onExit start: %d bytes", ESP.getFreeHeap()); 86 87 87 88 // Stop any ongoing WiFi scan 88 - Serial.printf("[%lu] [WIFI] Deleting WiFi scan...\n", millis()); 89 + LOG_DBG("WIFI", "Deleting WiFi scan..."); 89 90 WiFi.scanDelete(); 90 - Serial.printf("[%lu] [WIFI] [MEM] Free heap after scanDelete: %d bytes\n", millis(), ESP.getFreeHeap()); 91 + LOG_DBG("WIFI] [MEM", "Free heap after scanDelete: %d bytes", ESP.getFreeHeap()); 91 92 92 93 // Note: We do NOT disconnect WiFi here - the parent activity 93 94 // (CrossPointWebServerActivity) manages WiFi connection state. We just clean ··· 95 96 96 97 // Acquire mutex before deleting task to ensure task isn't using it 97 98 // This prevents hangs/crashes if the task holds the mutex when deleted 98 - Serial.printf("[%lu] [WIFI] Acquiring rendering mutex before task deletion...\n", millis()); 99 + LOG_DBG("WIFI", "Acquiring rendering mutex before task deletion..."); 99 100 xSemaphoreTake(renderingMutex, portMAX_DELAY); 100 101 101 102 // Delete the display task (we now hold the mutex, so task is blocked if it 102 103 // needs it) 103 - Serial.printf("[%lu] [WIFI] Deleting display task...\n", millis()); 104 + LOG_DBG("WIFI", "Deleting display task..."); 104 105 if (displayTaskHandle) { 105 106 vTaskDelete(displayTaskHandle); 106 107 displayTaskHandle = nullptr; 107 - Serial.printf("[%lu] [WIFI] Display task deleted\n", millis()); 108 + LOG_DBG("WIFI", "Display task deleted"); 108 109 } 109 110 110 111 // Now safe to delete the mutex since we own it 111 - Serial.printf("[%lu] [WIFI] Deleting mutex...\n", millis()); 112 + LOG_DBG("WIFI", "Deleting mutex..."); 112 113 vSemaphoreDelete(renderingMutex); 113 114 renderingMutex = nullptr; 114 - Serial.printf("[%lu] [WIFI] Mutex deleted\n", millis()); 115 + LOG_DBG("WIFI", "Mutex deleted"); 115 116 116 - Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap()); 117 + LOG_DBG("WIFI] [MEM", "Free heap at onExit end: %d bytes", ESP.getFreeHeap()); 117 118 } 118 119 119 120 void WifiSelectionActivity::startWifiScan() { ··· 211 212 // Use saved password - connect directly 212 213 enteredPassword = savedCred->password; 213 214 usedSavedPassword = true; 214 - Serial.printf("[%lu] [WiFi] Using saved password for %s, length: %zu\n", millis(), selectedSSID.c_str(), 215 - enteredPassword.size()); 215 + LOG_DBG("WiFi", "Using saved password for %s, length: %zu", selectedSSID.c_str(), enteredPassword.size()); 216 216 attemptConnection(); 217 217 return; 218 218 } ··· 290 290 updateRequired = true; 291 291 } else { 292 292 // Using saved password or open network - complete immediately 293 - Serial.printf( 294 - "[%lu] [WIFI] Connected with saved/open credentials, " 295 - "completing immediately\n", 296 - millis()); 293 + LOG_DBG("WIFI", 294 + "Connected with saved/open credentials, " 295 + "completing immediately"); 297 296 onComplete(true); 298 297 } 299 298 return;
+13 -13
src/activities/reader/EpubReaderActivity.cpp
··· 4 4 #include <FsHelpers.h> 5 5 #include <GfxRenderer.h> 6 6 #include <HalStorage.h> 7 + #include <Logging.h> 7 8 8 9 #include "CrossPointSettings.h" 9 10 #include "CrossPointState.h" ··· 84 85 currentSpineIndex = data[0] + (data[1] << 8); 85 86 nextPageNumber = data[2] + (data[3] << 8); 86 87 cachedSpineIndex = currentSpineIndex; 87 - Serial.printf("[%lu] [ERS] Loaded cache: %d, %d\n", millis(), currentSpineIndex, nextPageNumber); 88 + LOG_DBG("ERS", "Loaded cache: %d, %d", currentSpineIndex, nextPageNumber); 88 89 } 89 90 if (dataSize == 6) { 90 91 cachedChapterTotalPageCount = data[4] + (data[5] << 8); ··· 97 98 int textSpineIndex = epub->getSpineIndexForTextReference(); 98 99 if (textSpineIndex != 0) { 99 100 currentSpineIndex = textSpineIndex; 100 - Serial.printf("[%lu] [ERS] Opened for first time, navigating to text reference at index %d\n", millis(), 101 - textSpineIndex); 101 + LOG_DBG("ERS", "Opened for first time, navigating to text reference at index %d", textSpineIndex); 102 102 } 103 103 } 104 104 ··· 567 567 568 568 if (!section) { 569 569 const auto filepath = epub->getSpineItem(currentSpineIndex).href; 570 - Serial.printf("[%lu] [ERS] Loading file: %s, index: %d\n", millis(), filepath.c_str(), currentSpineIndex); 570 + LOG_DBG("ERS", "Loading file: %s, index: %d", filepath.c_str(), currentSpineIndex); 571 571 section = std::unique_ptr<Section>(new Section(epub, currentSpineIndex, renderer)); 572 572 573 573 const uint16_t viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight; ··· 576 576 if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(), 577 577 SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth, 578 578 viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) { 579 - Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis()); 579 + LOG_DBG("ERS", "Cache not found, building..."); 580 580 581 581 const auto popupFn = [this]() { GUI.drawPopup(renderer, "Indexing..."); }; 582 582 583 583 if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(), 584 584 SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth, 585 585 viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, popupFn)) { 586 - Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis()); 586 + LOG_ERR("ERS", "Failed to persist page data to SD"); 587 587 section.reset(); 588 588 return; 589 589 } 590 590 } else { 591 - Serial.printf("[%lu] [ERS] Cache found, skipping build...\n", millis()); 591 + LOG_DBG("ERS", "Cache found, skipping build..."); 592 592 } 593 593 594 594 if (nextPageNumber == UINT16_MAX) { ··· 622 622 renderer.clearScreen(); 623 623 624 624 if (section->pageCount == 0) { 625 - Serial.printf("[%lu] [ERS] No pages to render\n", millis()); 625 + LOG_DBG("ERS", "No pages to render"); 626 626 renderer.drawCenteredText(UI_12_FONT_ID, 300, "Empty chapter", true, EpdFontFamily::BOLD); 627 627 renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); 628 628 renderer.displayBuffer(); ··· 630 630 } 631 631 632 632 if (section->currentPage < 0 || section->currentPage >= section->pageCount) { 633 - Serial.printf("[%lu] [ERS] Page out of bounds: %d (max %d)\n", millis(), section->currentPage, section->pageCount); 633 + LOG_DBG("ERS", "Page out of bounds: %d (max %d)", section->currentPage, section->pageCount); 634 634 renderer.drawCenteredText(UI_12_FONT_ID, 300, "Out of bounds", true, EpdFontFamily::BOLD); 635 635 renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft); 636 636 renderer.displayBuffer(); ··· 640 640 { 641 641 auto p = section->loadPageFromSectionFile(); 642 642 if (!p) { 643 - Serial.printf("[%lu] [ERS] Failed to load page from SD - clearing section cache\n", millis()); 643 + LOG_ERR("ERS", "Failed to load page from SD - clearing section cache"); 644 644 section->clearCache(); 645 645 section.reset(); 646 646 return renderScreen(); 647 647 } 648 648 const auto start = millis(); 649 649 renderContents(std::move(p), orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft); 650 - Serial.printf("[%lu] [ERS] Rendered page in %dms\n", millis(), millis() - start); 650 + LOG_DBG("ERS", "Rendered page in %dms", millis() - start); 651 651 } 652 652 saveProgress(currentSpineIndex, section->currentPage, section->pageCount); 653 653 } ··· 664 664 data[5] = (pageCount >> 8) & 0xFF; 665 665 f.write(data, 6); 666 666 f.close(); 667 - Serial.printf("[%lu] [ERS] Progress saved: Chapter %d, Page %d\n", millis(), spineIndex, currentPage); 667 + LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d", spineIndex, currentPage); 668 668 } else { 669 - Serial.printf("[%lu] [ERS] Could not save progress!\n", millis()); 669 + LOG_ERR("ERS", "Could not save progress!"); 670 670 } 671 671 } 672 672 void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int orientedMarginTop,
+9 -8
src/activities/reader/KOReaderSyncActivity.cpp
··· 1 1 #include "KOReaderSyncActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 + #include <Logging.h> 4 5 #include <WiFi.h> 5 6 #include <esp_sntp.h> 6 7 ··· 32 33 } 33 34 34 35 if (retry < maxRetries) { 35 - Serial.printf("[%lu] [KOSync] NTP time synced\n", millis()); 36 + LOG_DBG("KOSync", "NTP time synced"); 36 37 } else { 37 - Serial.printf("[%lu] [KOSync] NTP sync timeout, using fallback\n", millis()); 38 + LOG_DBG("KOSync", "NTP sync timeout, using fallback"); 38 39 } 39 40 } 40 41 } // namespace ··· 48 49 exitActivity(); 49 50 50 51 if (!success) { 51 - Serial.printf("[%lu] [KOSync] WiFi connection failed, exiting\n", millis()); 52 + LOG_DBG("KOSync", "WiFi connection failed, exiting"); 52 53 onCancel(); 53 54 return; 54 55 } 55 56 56 - Serial.printf("[%lu] [KOSync] WiFi connected, starting sync\n", millis()); 57 + LOG_DBG("KOSync", "WiFi connected, starting sync"); 57 58 58 59 xSemaphoreTake(renderingMutex, portMAX_DELAY); 59 60 state = SYNCING; ··· 88 89 return; 89 90 } 90 91 91 - Serial.printf("[%lu] [KOSync] Document hash: %s\n", millis(), documentHash.c_str()); 92 + LOG_DBG("KOSync", "Document hash: %s", documentHash.c_str()); 92 93 93 94 xSemaphoreTake(renderingMutex, portMAX_DELAY); 94 95 statusMessage = "Fetching remote progress..."; ··· 188 189 } 189 190 190 191 // Turn on WiFi 191 - Serial.printf("[%lu] [KOSync] Turning on WiFi...\n", millis()); 192 + LOG_DBG("KOSync", "Turning on WiFi..."); 192 193 WiFi.mode(WIFI_STA); 193 194 194 195 // Check if already connected 195 196 if (WiFi.status() == WL_CONNECTED) { 196 - Serial.printf("[%lu] [KOSync] Already connected to WiFi\n", millis()); 197 + LOG_DBG("KOSync", "Already connected to WiFi"); 197 198 state = SYNCING; 198 199 statusMessage = "Syncing time..."; 199 200 updateRequired = true; ··· 216 217 } 217 218 218 219 // Launch WiFi selection subactivity 219 - Serial.printf("[%lu] [KOSync] Launching WifiSelectionActivity...\n", millis()); 220 + LOG_DBG("KOSync", "Launching WifiSelectionActivity..."); 220 221 enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, 221 222 [this](const bool connected) { onWifiSelectionComplete(connected); })); 222 223 }
+6 -6
src/activities/reader/ReaderActivity.cpp
··· 30 30 31 31 std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) { 32 32 if (!Storage.exists(path.c_str())) { 33 - Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); 33 + LOG_ERR("READER", "File does not exist: %s", path.c_str()); 34 34 return nullptr; 35 35 } 36 36 ··· 39 39 return epub; 40 40 } 41 41 42 - Serial.printf("[%lu] [ ] Failed to load epub\n", millis()); 42 + LOG_ERR("READER", "Failed to load epub"); 43 43 return nullptr; 44 44 } 45 45 46 46 std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) { 47 47 if (!Storage.exists(path.c_str())) { 48 - Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); 48 + LOG_ERR("READER", "File does not exist: %s", path.c_str()); 49 49 return nullptr; 50 50 } 51 51 ··· 54 54 return xtc; 55 55 } 56 56 57 - Serial.printf("[%lu] [ ] Failed to load XTC\n", millis()); 57 + LOG_ERR("READER", "Failed to load XTC"); 58 58 return nullptr; 59 59 } 60 60 61 61 std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) { 62 62 if (!Storage.exists(path.c_str())) { 63 - Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str()); 63 + LOG_ERR("READER", "File does not exist: %s", path.c_str()); 64 64 return nullptr; 65 65 } 66 66 ··· 69 69 return txt; 70 70 } 71 71 72 - Serial.printf("[%lu] [ ] Failed to load TXT\n", millis()); 72 + LOG_ERR("READER", "Failed to load TXT"); 73 73 return nullptr; 74 74 } 75 75
+17 -18
src/activities/reader/TxtReaderActivity.cpp
··· 191 191 linesPerPage = viewportHeight / lineHeight; 192 192 if (linesPerPage < 1) linesPerPage = 1; 193 193 194 - Serial.printf("[%lu] [TRS] Viewport: %dx%d, lines per page: %d\n", millis(), viewportWidth, viewportHeight, 195 - linesPerPage); 194 + LOG_DBG("TRS", "Viewport: %dx%d, lines per page: %d", viewportWidth, viewportHeight, linesPerPage); 196 195 197 196 // Try to load cached page index first 198 197 if (!loadPageIndexCache()) { ··· 215 214 size_t offset = 0; 216 215 const size_t fileSize = txt->getFileSize(); 217 216 218 - Serial.printf("[%lu] [TRS] Building page index for %zu bytes...\n", millis(), fileSize); 217 + LOG_DBG("TRS", "Building page index for %zu bytes...", fileSize); 219 218 220 219 GUI.drawPopup(renderer, "Indexing..."); 221 220 ··· 244 243 } 245 244 246 245 totalPages = pageOffsets.size(); 247 - Serial.printf("[%lu] [TRS] Built page index: %d pages\n", millis(), totalPages); 246 + LOG_DBG("TRS", "Built page index: %d pages", totalPages); 248 247 } 249 248 250 249 bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>& outLines, size_t& nextOffset) { ··· 259 258 size_t chunkSize = std::min(CHUNK_SIZE, fileSize - offset); 260 259 auto* buffer = static_cast<uint8_t*>(malloc(chunkSize + 1)); 261 260 if (!buffer) { 262 - Serial.printf("[%lu] [TRS] Failed to allocate %zu bytes\n", millis(), chunkSize); 261 + LOG_ERR("TRS", "Failed to allocate %zu bytes", chunkSize); 263 262 return false; 264 263 } 265 264 ··· 588 587 if (currentPage < 0) { 589 588 currentPage = 0; 590 589 } 591 - Serial.printf("[%lu] [TRS] Loaded progress: page %d/%d\n", millis(), currentPage, totalPages); 590 + LOG_DBG("TRS", "Loaded progress: page %d/%d", currentPage, totalPages); 592 591 } 593 592 f.close(); 594 593 } ··· 610 609 std::string cachePath = txt->getCachePath() + "/index.bin"; 611 610 FsFile f; 612 611 if (!Storage.openFileForRead("TRS", cachePath, f)) { 613 - Serial.printf("[%lu] [TRS] No page index cache found\n", millis()); 612 + LOG_DBG("TRS", "No page index cache found"); 614 613 return false; 615 614 } 616 615 ··· 618 617 uint32_t magic; 619 618 serialization::readPod(f, magic); 620 619 if (magic != CACHE_MAGIC) { 621 - Serial.printf("[%lu] [TRS] Cache magic mismatch, rebuilding\n", millis()); 620 + LOG_DBG("TRS", "Cache magic mismatch, rebuilding"); 622 621 f.close(); 623 622 return false; 624 623 } ··· 626 625 uint8_t version; 627 626 serialization::readPod(f, version); 628 627 if (version != CACHE_VERSION) { 629 - Serial.printf("[%lu] [TRS] Cache version mismatch (%d != %d), rebuilding\n", millis(), version, CACHE_VERSION); 628 + LOG_DBG("TRS", "Cache version mismatch (%d != %d), rebuilding", version, CACHE_VERSION); 630 629 f.close(); 631 630 return false; 632 631 } ··· 634 633 uint32_t fileSize; 635 634 serialization::readPod(f, fileSize); 636 635 if (fileSize != txt->getFileSize()) { 637 - Serial.printf("[%lu] [TRS] Cache file size mismatch, rebuilding\n", millis()); 636 + LOG_DBG("TRS", "Cache file size mismatch, rebuilding"); 638 637 f.close(); 639 638 return false; 640 639 } ··· 642 641 int32_t cachedWidth; 643 642 serialization::readPod(f, cachedWidth); 644 643 if (cachedWidth != viewportWidth) { 645 - Serial.printf("[%lu] [TRS] Cache viewport width mismatch, rebuilding\n", millis()); 644 + LOG_DBG("TRS", "Cache viewport width mismatch, rebuilding"); 646 645 f.close(); 647 646 return false; 648 647 } ··· 650 649 int32_t cachedLines; 651 650 serialization::readPod(f, cachedLines); 652 651 if (cachedLines != linesPerPage) { 653 - Serial.printf("[%lu] [TRS] Cache lines per page mismatch, rebuilding\n", millis()); 652 + LOG_DBG("TRS", "Cache lines per page mismatch, rebuilding"); 654 653 f.close(); 655 654 return false; 656 655 } ··· 658 657 int32_t fontId; 659 658 serialization::readPod(f, fontId); 660 659 if (fontId != cachedFontId) { 661 - Serial.printf("[%lu] [TRS] Cache font ID mismatch (%d != %d), rebuilding\n", millis(), fontId, cachedFontId); 660 + LOG_DBG("TRS", "Cache font ID mismatch (%d != %d), rebuilding", fontId, cachedFontId); 662 661 f.close(); 663 662 return false; 664 663 } ··· 666 665 int32_t margin; 667 666 serialization::readPod(f, margin); 668 667 if (margin != cachedScreenMargin) { 669 - Serial.printf("[%lu] [TRS] Cache screen margin mismatch, rebuilding\n", millis()); 668 + LOG_DBG("TRS", "Cache screen margin mismatch, rebuilding"); 670 669 f.close(); 671 670 return false; 672 671 } ··· 674 673 uint8_t alignment; 675 674 serialization::readPod(f, alignment); 676 675 if (alignment != cachedParagraphAlignment) { 677 - Serial.printf("[%lu] [TRS] Cache paragraph alignment mismatch, rebuilding\n", millis()); 676 + LOG_DBG("TRS", "Cache paragraph alignment mismatch, rebuilding"); 678 677 f.close(); 679 678 return false; 680 679 } ··· 694 693 695 694 f.close(); 696 695 totalPages = pageOffsets.size(); 697 - Serial.printf("[%lu] [TRS] Loaded page index cache: %d pages\n", millis(), totalPages); 696 + LOG_DBG("TRS", "Loaded page index cache: %d pages", totalPages); 698 697 return true; 699 698 } 700 699 ··· 702 701 std::string cachePath = txt->getCachePath() + "/index.bin"; 703 702 FsFile f; 704 703 if (!Storage.openFileForWrite("TRS", cachePath, f)) { 705 - Serial.printf("[%lu] [TRS] Failed to save page index cache\n", millis()); 704 + LOG_ERR("TRS", "Failed to save page index cache"); 706 705 return; 707 706 } 708 707 ··· 723 722 } 724 723 725 724 f.close(); 726 - Serial.printf("[%lu] [TRS] Saved page index cache: %d pages\n", millis(), totalPages); 725 + LOG_DBG("TRS", "Saved page index cache: %d pages", totalPages); 727 726 }
+7 -9
src/activities/reader/XtcReaderActivity.cpp
··· 206 206 // Allocate page buffer 207 207 uint8_t* pageBuffer = static_cast<uint8_t*>(malloc(pageBufferSize)); 208 208 if (!pageBuffer) { 209 - Serial.printf("[%lu] [XTR] Failed to allocate page buffer (%lu bytes)\n", millis(), pageBufferSize); 209 + LOG_ERR("XTR", "Failed to allocate page buffer (%lu bytes)", pageBufferSize); 210 210 renderer.clearScreen(); 211 211 renderer.drawCenteredText(UI_12_FONT_ID, 300, "Memory error", true, EpdFontFamily::BOLD); 212 212 renderer.displayBuffer(); ··· 216 216 // Load page data 217 217 size_t bytesRead = xtc->loadPage(currentPage, pageBuffer, pageBufferSize); 218 218 if (bytesRead == 0) { 219 - Serial.printf("[%lu] [XTR] Failed to load page %lu\n", millis(), currentPage); 219 + LOG_ERR("XTR", "Failed to load page %lu", currentPage); 220 220 free(pageBuffer); 221 221 renderer.clearScreen(); 222 222 renderer.drawCenteredText(UI_12_FONT_ID, 300, "Page load error", true, EpdFontFamily::BOLD); ··· 265 265 pixelCounts[getPixelValue(x, y)]++; 266 266 } 267 267 } 268 - Serial.printf("[%lu] [XTR] Pixel distribution: White=%lu, DarkGrey=%lu, LightGrey=%lu, Black=%lu\n", millis(), 269 - pixelCounts[0], pixelCounts[1], pixelCounts[2], pixelCounts[3]); 268 + LOG_DBG("XTR", "Pixel distribution: White=%lu, DarkGrey=%lu, LightGrey=%lu, Black=%lu", pixelCounts[0], 269 + pixelCounts[1], pixelCounts[2], pixelCounts[3]); 270 270 271 271 // Pass 1: BW buffer - draw all non-white pixels as black 272 272 for (uint16_t y = 0; y < pageHeight; y++) { ··· 329 329 330 330 free(pageBuffer); 331 331 332 - Serial.printf("[%lu] [XTR] Rendered page %lu/%lu (2-bit grayscale)\n", millis(), currentPage + 1, 333 - xtc->getPageCount()); 332 + LOG_DBG("XTR", "Rendered page %lu/%lu (2-bit grayscale)", currentPage + 1, xtc->getPageCount()); 334 333 return; 335 334 } else { 336 335 // 1-bit mode: 8 pixels per byte, MSB first ··· 366 365 pagesUntilFullRefresh--; 367 366 } 368 367 369 - Serial.printf("[%lu] [XTR] Rendered page %lu/%lu (%u-bit)\n", millis(), currentPage + 1, xtc->getPageCount(), 370 - bitDepth); 368 + LOG_DBG("XTR", "Rendered page %lu/%lu (%u-bit)", currentPage + 1, xtc->getPageCount(), bitDepth); 371 369 } 372 370 373 371 void XtcReaderActivity::saveProgress() const { ··· 389 387 uint8_t data[4]; 390 388 if (f.read(data, 4) == 4) { 391 389 currentPage = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); 392 - Serial.printf("[%lu] [XTR] Loaded progress: page %lu\n", millis(), currentPage); 390 + LOG_DBG("XTR", "Loaded progress: page %lu", currentPage); 393 391 394 392 // Validate page number 395 393 if (currentPage >= xtc->getPageCount()) {
+8 -8
src/activities/settings/ClearCacheActivity.cpp
··· 2 2 3 3 #include <GfxRenderer.h> 4 4 #include <HalStorage.h> 5 - #include <HardwareSerial.h> 5 + #include <Logging.h> 6 6 7 7 #include "MappedInputManager.h" 8 8 #include "components/UITheme.h" ··· 104 104 } 105 105 106 106 void ClearCacheActivity::clearCache() { 107 - Serial.printf("[%lu] [CLEAR_CACHE] Clearing cache...\n", millis()); 107 + LOG_DBG("CLEAR_CACHE", "Clearing cache..."); 108 108 109 109 // Open .crosspoint directory 110 110 auto root = Storage.open("/.crosspoint"); 111 111 if (!root || !root.isDirectory()) { 112 - Serial.printf("[%lu] [CLEAR_CACHE] Failed to open cache directory\n", millis()); 112 + LOG_DBG("CLEAR_CACHE", "Failed to open cache directory"); 113 113 if (root) root.close(); 114 114 state = FAILED; 115 115 updateRequired = true; ··· 128 128 // Only delete directories starting with epub_ or xtc_ 129 129 if (file.isDirectory() && (itemName.startsWith("epub_") || itemName.startsWith("xtc_"))) { 130 130 String fullPath = "/.crosspoint/" + itemName; 131 - Serial.printf("[%lu] [CLEAR_CACHE] Removing cache: %s\n", millis(), fullPath.c_str()); 131 + LOG_DBG("CLEAR_CACHE", "Removing cache: %s", fullPath.c_str()); 132 132 133 133 file.close(); // Close before attempting to delete 134 134 135 135 if (Storage.removeDir(fullPath.c_str())) { 136 136 clearedCount++; 137 137 } else { 138 - Serial.printf("[%lu] [CLEAR_CACHE] Failed to remove: %s\n", millis(), fullPath.c_str()); 138 + LOG_ERR("CLEAR_CACHE", "Failed to remove: %s", fullPath.c_str()); 139 139 failedCount++; 140 140 } 141 141 } else { ··· 144 144 } 145 145 root.close(); 146 146 147 - Serial.printf("[%lu] [CLEAR_CACHE] Cache cleared: %d removed, %d failed\n", millis(), clearedCount, failedCount); 147 + LOG_DBG("CLEAR_CACHE", "Cache cleared: %d removed, %d failed", clearedCount, failedCount); 148 148 149 149 state = SUCCESS; 150 150 updateRequired = true; ··· 153 153 void ClearCacheActivity::loop() { 154 154 if (state == WARNING) { 155 155 if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { 156 - Serial.printf("[%lu] [CLEAR_CACHE] User confirmed, starting cache clear\n", millis()); 156 + LOG_DBG("CLEAR_CACHE", "User confirmed, starting cache clear"); 157 157 xSemaphoreTake(renderingMutex, portMAX_DELAY); 158 158 state = CLEARING; 159 159 xSemaphoreGive(renderingMutex); ··· 164 164 } 165 165 166 166 if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { 167 - Serial.printf("[%lu] [CLEAR_CACHE] User cancelled\n", millis()); 167 + LOG_DBG("CLEAR_CACHE", "User cancelled"); 168 168 goBack(); 169 169 } 170 170 return;
+9 -10
src/activities/settings/OtaUpdateActivity.cpp
··· 18 18 exitActivity(); 19 19 20 20 if (!success) { 21 - Serial.printf("[%lu] [OTA] WiFi connection failed, exiting\n", millis()); 21 + LOG_ERR("OTA", "WiFi connection failed, exiting"); 22 22 goBack(); 23 23 return; 24 24 } 25 25 26 - Serial.printf("[%lu] [OTA] WiFi connected, checking for update\n", millis()); 26 + LOG_DBG("OTA", "WiFi connected, checking for update"); 27 27 28 28 xSemaphoreTake(renderingMutex, portMAX_DELAY); 29 29 state = CHECKING_FOR_UPDATE; ··· 32 32 vTaskDelay(10 / portTICK_PERIOD_MS); 33 33 const auto res = updater.checkForUpdate(); 34 34 if (res != OtaUpdater::OK) { 35 - Serial.printf("[%lu] [OTA] Update check failed: %d\n", millis(), res); 35 + LOG_DBG("OTA", "Update check failed: %d", res); 36 36 xSemaphoreTake(renderingMutex, portMAX_DELAY); 37 37 state = FAILED; 38 38 xSemaphoreGive(renderingMutex); ··· 41 41 } 42 42 43 43 if (!updater.isUpdateNewer()) { 44 - Serial.printf("[%lu] [OTA] No new update available\n", millis()); 44 + LOG_DBG("OTA", "No new update available"); 45 45 xSemaphoreTake(renderingMutex, portMAX_DELAY); 46 46 state = NO_UPDATE; 47 47 xSemaphoreGive(renderingMutex); ··· 68 68 ); 69 69 70 70 // Turn on WiFi immediately 71 - Serial.printf("[%lu] [OTA] Turning on WiFi...\n", millis()); 71 + LOG_DBG("OTA", "Turning on WiFi..."); 72 72 WiFi.mode(WIFI_STA); 73 73 74 74 // Launch WiFi selection subactivity 75 - Serial.printf("[%lu] [OTA] Launching WifiSelectionActivity...\n", millis()); 75 + LOG_DBG("OTA", "Launching WifiSelectionActivity..."); 76 76 enterNewActivity(new WifiSelectionActivity(renderer, mappedInput, 77 77 [this](const bool connected) { onWifiSelectionComplete(connected); })); 78 78 } ··· 116 116 117 117 float updaterProgress = 0; 118 118 if (state == UPDATE_IN_PROGRESS) { 119 - Serial.printf("[%lu] [OTA] Update progress: %d / %d\n", millis(), updater.getProcessedSize(), 120 - updater.getTotalSize()); 119 + LOG_DBG("OTA", "Update progress: %d / %d", updater.getProcessedSize(), updater.getTotalSize()); 121 120 updaterProgress = static_cast<float>(updater.getProcessedSize()) / static_cast<float>(updater.getTotalSize()); 122 121 // Only update every 2% at the most 123 122 if (static_cast<int>(updaterProgress * 50) == lastUpdaterPercentage / 2) { ··· 190 189 191 190 if (state == WAITING_CONFIRMATION) { 192 191 if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { 193 - Serial.printf("[%lu] [OTA] New update available, starting download...\n", millis()); 192 + LOG_DBG("OTA", "New update available, starting download..."); 194 193 xSemaphoreTake(renderingMutex, portMAX_DELAY); 195 194 state = UPDATE_IN_PROGRESS; 196 195 xSemaphoreGive(renderingMutex); ··· 199 198 const auto res = updater.installUpdate(); 200 199 201 200 if (res != OtaUpdater::OK) { 202 - Serial.printf("[%lu] [OTA] Update failed: %d\n", millis(), res); 201 + LOG_DBG("OTA", "Update failed: %d", res); 203 202 xSemaphoreTake(renderingMutex, portMAX_DELAY); 204 203 state = FAILED; 205 204 xSemaphoreGive(renderingMutex);
+1 -1
src/activities/settings/SettingsActivity.cpp
··· 1 1 #include "SettingsActivity.h" 2 2 3 3 #include <GfxRenderer.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 6 6 #include "ButtonRemapActivity.h" 7 7 #include "CalibreSettingsActivity.h"
+3 -2
src/components/UITheme.cpp
··· 1 1 #include "UITheme.h" 2 2 3 3 #include <GfxRenderer.h> 4 + #include <Logging.h> 4 5 5 6 #include <memory> 6 7 ··· 23 24 void UITheme::setTheme(CrossPointSettings::UI_THEME type) { 24 25 switch (type) { 25 26 case CrossPointSettings::UI_THEME::CLASSIC: 26 - Serial.printf("[%lu] [UI] Using Classic theme\n", millis()); 27 + LOG_DBG("UI", "Using Classic theme"); 27 28 currentTheme = new BaseTheme(); 28 29 currentMetrics = &BaseMetrics::values; 29 30 break; 30 31 case CrossPointSettings::UI_THEME::LYRA: 31 - Serial.printf("[%lu] [UI] Using Lyra theme\n", millis()); 32 + LOG_DBG("UI", "Using Lyra theme"); 32 33 currentTheme = new LyraTheme(); 33 34 currentMetrics = &LyraMetrics::values; 34 35 break;
+3 -2
src/components/themes/BaseTheme.cpp
··· 2 2 3 3 #include <GfxRenderer.h> 4 4 #include <HalStorage.h> 5 + #include <Logging.h> 5 6 #include <Utf8.h> 6 7 7 8 #include <cstdint> ··· 311 312 if (Storage.openFileForRead("HOME", coverBmpPath, file)) { 312 313 Bitmap bitmap(file); 313 314 if (bitmap.parseHeaders() == BmpReaderError::Ok) { 314 - Serial.printf("Rendering bmp\n"); 315 + LOG_DBG("THEME", "Rendering bmp"); 315 316 // Calculate position to center image within the book card 316 317 int coverX, coverY; 317 318 ··· 345 346 346 347 // First render: if selected, draw selection indicators now 347 348 if (bookSelected) { 348 - Serial.printf("Drawing selection\n"); 349 + LOG_DBG("THEME", "Drawing selection"); 349 350 renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2); 350 351 renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4); 351 352 }
+20 -19
src/main.cpp
··· 4 4 #include <HalDisplay.h> 5 5 #include <HalGPIO.h> 6 6 #include <HalStorage.h> 7 + #include <Logging.h> 7 8 #include <SPI.h> 8 9 #include <builtinFonts/all.h> 9 10 ··· 201 202 enterNewActivity(new SleepActivity(renderer, mappedInputManager)); 202 203 203 204 display.deepSleep(); 204 - Serial.printf("[%lu] [ ] Power button press calibration value: %lu ms\n", millis(), t2 - t1); 205 - Serial.printf("[%lu] [ ] Entering deep sleep.\n", millis()); 205 + LOG_DBG("MAIN", "Power button press calibration value: %lu ms", t2 - t1); 206 + LOG_DBG("MAIN", "Entering deep sleep"); 206 207 207 208 gpio.startDeepSleep(); 208 209 } ··· 255 256 void setupDisplayAndFonts() { 256 257 display.begin(); 257 258 renderer.begin(); 258 - Serial.printf("[%lu] [ ] Display initialized\n", millis()); 259 + LOG_DBG("MAIN", "Display initialized"); 259 260 renderer.insertFont(BOOKERLY_14_FONT_ID, bookerly14FontFamily); 260 261 #ifndef OMIT_FONTS 261 262 renderer.insertFont(BOOKERLY_12_FONT_ID, bookerly12FontFamily); ··· 274 275 renderer.insertFont(UI_10_FONT_ID, ui10FontFamily); 275 276 renderer.insertFont(UI_12_FONT_ID, ui12FontFamily); 276 277 renderer.insertFont(SMALL_FONT_ID, smallFontFamily); 277 - Serial.printf("[%lu] [ ] Fonts setup\n", millis()); 278 + LOG_DBG("MAIN", "Fonts setup"); 278 279 } 279 280 280 281 void setup() { ··· 295 296 // SD Card Initialization 296 297 // We need 6 open files concurrently when parsing a new chapter 297 298 if (!Storage.begin()) { 298 - Serial.printf("[%lu] [ ] SD card initialization failed\n", millis()); 299 + LOG_ERR("MAIN", "SD card initialization failed"); 299 300 setupDisplayAndFonts(); 300 301 exitActivity(); 301 302 enterNewActivity(new FullScreenMessageActivity(renderer, mappedInputManager, "SD card error", EpdFontFamily::BOLD)); ··· 310 311 switch (gpio.getWakeupReason()) { 311 312 case HalGPIO::WakeupReason::PowerButton: 312 313 // For normal wakeups, verify power button press duration 313 - Serial.printf("[%lu] [ ] Verifying power button press duration\n", millis()); 314 + LOG_DBG("MAIN", "Verifying power button press duration"); 314 315 verifyPowerButtonDuration(); 315 316 break; 316 317 case HalGPIO::WakeupReason::AfterUSBPower: 317 318 // If USB power caused a cold boot, go back to sleep 318 - Serial.printf("[%lu] [ ] Wakeup reason: After USB Power\n", millis()); 319 + LOG_DBG("MAIN", "Wakeup reason: After USB Power"); 319 320 gpio.startDeepSleep(); 320 321 break; 321 322 case HalGPIO::WakeupReason::AfterFlash: ··· 326 327 } 327 328 328 329 // First serial output only here to avoid timing inconsistencies for power button press duration verification 329 - Serial.printf("[%lu] [ ] Starting CrossPoint version " CROSSPOINT_VERSION "\n", millis()); 330 + LOG_DBG("MAIN", "Starting CrossPoint version " CROSSPOINT_VERSION); 330 331 331 332 setupDisplayAndFonts(); 332 333 ··· 364 365 renderer.setFadingFix(SETTINGS.fadingFix); 365 366 366 367 if (Serial && millis() - lastMemPrint >= 10000) { 367 - Serial.printf("[%lu] [MEM] Free: %d bytes, Total: %d bytes, Min Free: %d bytes\n", millis(), ESP.getFreeHeap(), 368 - ESP.getHeapSize(), ESP.getMinFreeHeap()); 368 + LOG_INF("MEM", "Free: %d bytes, Total: %d bytes, Min Free: %d bytes", ESP.getFreeHeap(), ESP.getHeapSize(), 369 + ESP.getMinFreeHeap()); 369 370 lastMemPrint = millis(); 370 371 } 371 372 372 - // Handle incoming serial commands 373 - if (Serial.available() > 0) { 374 - String line = Serial.readStringUntil('\n'); 373 + // Handle incoming serial commands, 374 + // nb: we use logSerial from logging to avoid deprecation warnings 375 + if (logSerial.available() > 0) { 376 + String line = logSerial.readStringUntil('\n'); 375 377 if (line.startsWith("CMD:")) { 376 378 String cmd = line.substring(4); 377 379 cmd.trim(); 378 380 if (cmd == "SCREENSHOT") { 379 - Serial.printf("SCREENSHOT_START:%d\n", HalDisplay::BUFFER_SIZE); 381 + logSerial.printf("SCREENSHOT_START:%d\n", HalDisplay::BUFFER_SIZE); 380 382 uint8_t* buf = display.getFrameBuffer(); 381 - Serial.write(buf, HalDisplay::BUFFER_SIZE); 382 - Serial.printf("SCREENSHOT_END\n"); 383 + logSerial.write(buf, HalDisplay::BUFFER_SIZE); 384 + logSerial.printf("SCREENSHOT_END\n"); 383 385 } 384 386 } 385 387 } ··· 392 394 393 395 const unsigned long sleepTimeoutMs = SETTINGS.getSleepTimeoutMs(); 394 396 if (millis() - lastActivityTime >= sleepTimeoutMs) { 395 - Serial.printf("[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n", millis(), sleepTimeoutMs); 397 + LOG_DBG("SLP", "Auto-sleep triggered after %lu ms of inactivity", sleepTimeoutMs); 396 398 enterDeepSleep(); 397 399 // This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start 398 400 return; ··· 414 416 if (loopDuration > maxLoopDuration) { 415 417 maxLoopDuration = loopDuration; 416 418 if (maxLoopDuration > 50) { 417 - Serial.printf("[%lu] [LOOP] New max loop duration: %lu ms (activity: %lu ms)\n", millis(), maxLoopDuration, 418 - activityDuration); 419 + LOG_DBG("LOOP", "New max loop duration: %lu ms (activity: %lu ms)", maxLoopDuration, activityDuration); 419 420 } 420 421 } 421 422
+75 -78
src/network/CrossPointWebServer.cpp
··· 4 4 #include <Epub.h> 5 5 #include <FsHelpers.h> 6 6 #include <HalStorage.h> 7 + #include <Logging.h> 7 8 #include <WiFi.h> 8 9 #include <esp_task_wdt.h> 9 10 ··· 44 45 // Only clear cache for .epub files 45 46 if (StringUtils::checkFileExtension(filePath, ".epub")) { 46 47 Epub(filePath.c_str(), "/.crosspoint").clearCache(); 47 - Serial.printf("[%lu] [WEB] Cleared epub cache for: %s\n", millis(), filePath.c_str()); 48 + LOG_DBG("WEB", "Cleared epub cache for: %s", filePath.c_str()); 48 49 } 49 50 } 50 51 ··· 89 90 90 91 void CrossPointWebServer::begin() { 91 92 if (running) { 92 - Serial.printf("[%lu] [WEB] Web server already running\n", millis()); 93 + LOG_DBG("WEB", "Web server already running"); 93 94 return; 94 95 } 95 96 ··· 99 100 const bool isInApMode = (wifiMode & WIFI_MODE_AP) && (WiFi.softAPgetStationNum() >= 0); // AP is running 100 101 101 102 if (!isStaConnected && !isInApMode) { 102 - Serial.printf("[%lu] [WEB] Cannot start webserver - no valid network (mode=%d, status=%d)\n", millis(), wifiMode, 103 - WiFi.status()); 103 + LOG_DBG("WEB", "Cannot start webserver - no valid network (mode=%d, status=%d)", wifiMode, WiFi.status()); 104 104 return; 105 105 } 106 106 107 107 // Store AP mode flag for later use (e.g., in handleStatus) 108 108 apMode = isInApMode; 109 109 110 - Serial.printf("[%lu] [WEB] [MEM] Free heap before begin: %d bytes\n", millis(), ESP.getFreeHeap()); 111 - Serial.printf("[%lu] [WEB] Network mode: %s\n", millis(), apMode ? "AP" : "STA"); 110 + LOG_DBG("WEB", "[MEM] Free heap before begin: %d bytes", ESP.getFreeHeap()); 111 + LOG_DBG("WEB", "Network mode: %s", apMode ? "AP" : "STA"); 112 112 113 - Serial.printf("[%lu] [WEB] Creating web server on port %d...\n", millis(), port); 113 + LOG_DBG("WEB", "Creating web server on port %d...", port); 114 114 server.reset(new WebServer(port)); 115 115 116 116 // Disable WiFi sleep to improve responsiveness and prevent 'unreachable' errors. ··· 120 120 // Note: WebServer class doesn't have setNoDelay() in the standard ESP32 library. 121 121 // We rely on disabling WiFi sleep for responsiveness. 122 122 123 - Serial.printf("[%lu] [WEB] [MEM] Free heap after WebServer allocation: %d bytes\n", millis(), ESP.getFreeHeap()); 123 + LOG_DBG("WEB", "[MEM] Free heap after WebServer allocation: %d bytes", ESP.getFreeHeap()); 124 124 125 125 if (!server) { 126 - Serial.printf("[%lu] [WEB] Failed to create WebServer!\n", millis()); 126 + LOG_ERR("WEB", "Failed to create WebServer!"); 127 127 return; 128 128 } 129 129 130 130 // Setup routes 131 - Serial.printf("[%lu] [WEB] Setting up routes...\n", millis()); 131 + LOG_DBG("WEB", "Setting up routes..."); 132 132 server->on("/", HTTP_GET, [this] { handleRoot(); }); 133 133 server->on("/files", HTTP_GET, [this] { handleFileList(); }); 134 134 ··· 157 157 server->on("/api/settings", HTTP_POST, [this] { handlePostSettings(); }); 158 158 159 159 server->onNotFound([this] { handleNotFound(); }); 160 - Serial.printf("[%lu] [WEB] [MEM] Free heap after route setup: %d bytes\n", millis(), ESP.getFreeHeap()); 160 + LOG_DBG("WEB", "[MEM] Free heap after route setup: %d bytes", ESP.getFreeHeap()); 161 161 162 162 server->begin(); 163 163 164 164 // Start WebSocket server for fast binary uploads 165 - Serial.printf("[%lu] [WEB] Starting WebSocket server on port %d...\n", millis(), wsPort); 165 + LOG_DBG("WEB", "Starting WebSocket server on port %d...", wsPort); 166 166 wsServer.reset(new WebSocketsServer(wsPort)); 167 167 wsInstance = const_cast<CrossPointWebServer*>(this); 168 168 wsServer->begin(); 169 169 wsServer->onEvent(wsEventCallback); 170 - Serial.printf("[%lu] [WEB] WebSocket server started\n", millis()); 170 + LOG_DBG("WEB", "WebSocket server started"); 171 171 172 172 udpActive = udp.begin(LOCAL_UDP_PORT); 173 - Serial.printf("[%lu] [WEB] Discovery UDP %s on port %d\n", millis(), udpActive ? "enabled" : "failed", 174 - LOCAL_UDP_PORT); 173 + LOG_DBG("WEB", "Discovery UDP %s on port %d", udpActive ? "enabled" : "failed", LOCAL_UDP_PORT); 175 174 176 175 running = true; 177 176 178 - Serial.printf("[%lu] [WEB] Web server started on port %d\n", millis(), port); 177 + LOG_DBG("WEB", "Web server started on port %d", port); 179 178 // Show the correct IP based on network mode 180 179 const String ipAddr = apMode ? WiFi.softAPIP().toString() : WiFi.localIP().toString(); 181 - Serial.printf("[%lu] [WEB] Access at http://%s/\n", millis(), ipAddr.c_str()); 182 - Serial.printf("[%lu] [WEB] WebSocket at ws://%s:%d/\n", millis(), ipAddr.c_str(), wsPort); 183 - Serial.printf("[%lu] [WEB] [MEM] Free heap after server.begin(): %d bytes\n", millis(), ESP.getFreeHeap()); 180 + LOG_DBG("WEB", "Access at http://%s/", ipAddr.c_str()); 181 + LOG_DBG("WEB", "WebSocket at ws://%s:%d/", ipAddr.c_str(), wsPort); 182 + LOG_DBG("WEB", "[MEM] Free heap after server.begin(): %d bytes", ESP.getFreeHeap()); 184 183 } 185 184 186 185 void CrossPointWebServer::stop() { 187 186 if (!running || !server) { 188 - Serial.printf("[%lu] [WEB] stop() called but already stopped (running=%d, server=%p)\n", millis(), running, 189 - server.get()); 187 + LOG_DBG("WEB", "stop() called but already stopped (running=%d, server=%p)", running, server.get()); 190 188 return; 191 189 } 192 190 193 - Serial.printf("[%lu] [WEB] STOP INITIATED - setting running=false first\n", millis()); 191 + LOG_DBG("WEB", "STOP INITIATED - setting running=false first"); 194 192 running = false; // Set this FIRST to prevent handleClient from using server 195 193 196 - Serial.printf("[%lu] [WEB] [MEM] Free heap before stop: %d bytes\n", millis(), ESP.getFreeHeap()); 194 + LOG_DBG("WEB", "[MEM] Free heap before stop: %d bytes", ESP.getFreeHeap()); 197 195 198 196 // Close any in-progress WebSocket upload 199 197 if (wsUploadInProgress && wsUploadFile) { ··· 203 201 204 202 // Stop WebSocket server 205 203 if (wsServer) { 206 - Serial.printf("[%lu] [WEB] Stopping WebSocket server...\n", millis()); 204 + LOG_DBG("WEB", "Stopping WebSocket server..."); 207 205 wsServer->close(); 208 206 wsServer.reset(); 209 207 wsInstance = nullptr; 210 - Serial.printf("[%lu] [WEB] WebSocket server stopped\n", millis()); 208 + LOG_DBG("WEB", "WebSocket server stopped"); 211 209 } 212 210 213 211 if (udpActive) { ··· 219 217 delay(20); 220 218 221 219 server->stop(); 222 - Serial.printf("[%lu] [WEB] [MEM] Free heap after server->stop(): %d bytes\n", millis(), ESP.getFreeHeap()); 220 + LOG_DBG("WEB", "[MEM] Free heap after server->stop(): %d bytes", ESP.getFreeHeap()); 223 221 224 222 // Brief delay before deletion 225 223 delay(10); 226 224 227 225 server.reset(); 228 - Serial.printf("[%lu] [WEB] Web server stopped and deleted\n", millis()); 229 - Serial.printf("[%lu] [WEB] [MEM] Free heap after delete server: %d bytes\n", millis(), ESP.getFreeHeap()); 226 + LOG_DBG("WEB", "Web server stopped and deleted"); 227 + LOG_DBG("WEB", "[MEM] Free heap after delete server: %d bytes", ESP.getFreeHeap()); 230 228 231 229 // Note: Static upload variables (uploadFileName, uploadPath, uploadError) are declared 232 230 // later in the file and will be cleared when they go out of scope or on next upload 233 - Serial.printf("[%lu] [WEB] [MEM] Free heap final: %d bytes\n", millis(), ESP.getFreeHeap()); 231 + LOG_DBG("WEB", "[MEM] Free heap final: %d bytes", ESP.getFreeHeap()); 234 232 } 235 233 236 234 void CrossPointWebServer::handleClient() { ··· 243 241 244 242 // Double-check server pointer is valid 245 243 if (!server) { 246 - Serial.printf("[%lu] [WEB] WARNING: handleClient called with null server!\n", millis()); 244 + LOG_DBG("WEB", "WARNING: handleClient called with null server!"); 247 245 return; 248 246 } 249 247 250 248 // Print debug every 10 seconds to confirm handleClient is being called 251 249 if (millis() - lastDebugPrint > 10000) { 252 - Serial.printf("[%lu] [WEB] handleClient active, server running on port %d\n", millis(), port); 250 + LOG_DBG("WEB", "handleClient active, server running on port %d", port); 253 251 lastDebugPrint = millis(); 254 252 } 255 253 ··· 297 295 298 296 void CrossPointWebServer::handleRoot() const { 299 297 server->send(200, "text/html", HomePageHtml); 300 - Serial.printf("[%lu] [WEB] Served root page\n", millis()); 298 + LOG_DBG("WEB", "Served root page"); 301 299 } 302 300 303 301 void CrossPointWebServer::handleNotFound() const { ··· 326 324 void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const { 327 325 FsFile root = Storage.open(path); 328 326 if (!root) { 329 - Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path); 327 + LOG_DBG("WEB", "Failed to open directory: %s", path); 330 328 return; 331 329 } 332 330 333 331 if (!root.isDirectory()) { 334 - Serial.printf("[%lu] [WEB] Not a directory: %s\n", millis(), path); 332 + LOG_DBG("WEB", "Not a directory: %s", path); 335 333 root.close(); 336 334 return; 337 335 } 338 336 339 - Serial.printf("[%lu] [WEB] Scanning files in: %s\n", millis(), path); 337 + LOG_DBG("WEB", "Scanning files in: %s", path); 340 338 341 339 FsFile file = root.openNextFile(); 342 340 char name[500]; ··· 422 420 const size_t written = serializeJson(doc, output, outputSize); 423 421 if (written >= outputSize) { 424 422 // JSON output truncated; skip this entry to avoid sending malformed JSON 425 - Serial.printf("[%lu] [WEB] Skipping file entry with oversized JSON for name: %s\n", millis(), info.name.c_str()); 423 + LOG_DBG("WEB", "Skipping file entry with oversized JSON for name: %s", info.name.c_str()); 426 424 return; 427 425 } 428 426 ··· 436 434 server->sendContent("]"); 437 435 // End of streamed response, empty chunk to signal client 438 436 server->sendContent(""); 439 - Serial.printf("[%lu] [WEB] Served file listing page for path: %s\n", millis(), currentPath.c_str()); 437 + LOG_DBG("WEB", "Served file listing page for path: %s", currentPath.c_str()); 440 438 } 441 439 442 440 void CrossPointWebServer::handleDownload() const { ··· 517 515 esp_task_wdt_reset(); // Reset watchdog after SD write 518 516 519 517 if (written != state.bufferPos) { 520 - Serial.printf("[%lu] [WEB] [UPLOAD] Buffer flush failed: expected %d, wrote %d\n", millis(), state.bufferPos, 521 - written); 518 + LOG_DBG("WEB", "[UPLOAD] Buffer flush failed: expected %d, wrote %d", state.bufferPos, written); 522 519 state.bufferPos = 0; 523 520 return false; 524 521 } ··· 535 532 536 533 // Safety check: ensure server is still valid 537 534 if (!running || !server) { 538 - Serial.printf("[%lu] [WEB] [UPLOAD] ERROR: handleUpload called but server not running!\n", millis()); 535 + LOG_DBG("WEB", "[UPLOAD] ERROR: handleUpload called but server not running!"); 539 536 return; 540 537 } 541 538 ··· 572 569 state.path = "/"; 573 570 } 574 571 575 - Serial.printf("[%lu] [WEB] [UPLOAD] START: %s to path: %s\n", millis(), state.fileName.c_str(), state.path.c_str()); 576 - Serial.printf("[%lu] [WEB] [UPLOAD] Free heap: %d bytes\n", millis(), ESP.getFreeHeap()); 572 + LOG_DBG("WEB", "[UPLOAD] START: %s to path: %s", state.fileName.c_str(), state.path.c_str()); 573 + LOG_DBG("WEB", "[UPLOAD] Free heap: %d bytes", ESP.getFreeHeap()); 577 574 578 575 // Create file path 579 576 String filePath = state.path; ··· 583 580 // Check if file already exists - SD operations can be slow 584 581 esp_task_wdt_reset(); 585 582 if (Storage.exists(filePath.c_str())) { 586 - Serial.printf("[%lu] [WEB] [UPLOAD] Overwriting existing file: %s\n", millis(), filePath.c_str()); 583 + LOG_DBG("WEB", "[UPLOAD] Overwriting existing file: %s", filePath.c_str()); 587 584 esp_task_wdt_reset(); 588 585 Storage.remove(filePath.c_str()); 589 586 } ··· 592 589 esp_task_wdt_reset(); 593 590 if (!Storage.openFileForWrite("WEB", filePath, state.file)) { 594 591 state.error = "Failed to create file on SD card"; 595 - Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str()); 592 + LOG_DBG("WEB", "[UPLOAD] FAILED to create file: %s", filePath.c_str()); 596 593 return; 597 594 } 598 595 esp_task_wdt_reset(); 599 596 600 - Serial.printf("[%lu] [WEB] [UPLOAD] File created successfully: %s\n", millis(), filePath.c_str()); 597 + LOG_DBG("WEB", "[UPLOAD] File created successfully: %s", filePath.c_str()); 601 598 } else if (upload.status == UPLOAD_FILE_WRITE) { 602 599 if (state.file && state.error.isEmpty()) { 603 600 // Buffer incoming data and flush when buffer is full ··· 630 627 if (state.size - lastLoggedSize >= 102400) { 631 628 const unsigned long elapsed = millis() - uploadStartTime; 632 629 const float kbps = (elapsed > 0) ? (state.size / 1024.0) / (elapsed / 1000.0) : 0; 633 - Serial.printf("[%lu] [WEB] [UPLOAD] %d bytes (%.1f KB), %.1f KB/s, %d writes\n", millis(), state.size, 634 - state.size / 1024.0, kbps, writeCount); 630 + LOG_DBG("WEB", "[UPLOAD] %d bytes (%.1f KB), %.1f KB/s, %d writes", state.size, state.size / 1024.0, kbps, 631 + writeCount); 635 632 lastLoggedSize = state.size; 636 633 } 637 634 } ··· 648 645 const unsigned long elapsed = millis() - uploadStartTime; 649 646 const float avgKbps = (elapsed > 0) ? (state.size / 1024.0) / (elapsed / 1000.0) : 0; 650 647 const float writePercent = (elapsed > 0) ? (totalWriteTime * 100.0 / elapsed) : 0; 651 - Serial.printf("[%lu] [WEB] [UPLOAD] Complete: %s (%d bytes in %lu ms, avg %.1f KB/s)\n", millis(), 652 - state.fileName.c_str(), state.size, elapsed, avgKbps); 653 - Serial.printf("[%lu] [WEB] [UPLOAD] Diagnostics: %d writes, total write time: %lu ms (%.1f%%)\n", millis(), 654 - writeCount, totalWriteTime, writePercent); 648 + LOG_DBG("WEB", "[UPLOAD] Complete: %s (%d bytes in %lu ms, avg %.1f KB/s)", state.fileName.c_str(), state.size, 649 + elapsed, avgKbps); 650 + LOG_DBG("WEB", "[UPLOAD] Diagnostics: %d writes, total write time: %lu ms (%.1f%%)", writeCount, totalWriteTime, 651 + writePercent); 655 652 656 653 // Clear epub cache to prevent stale metadata issues when overwriting files 657 654 String filePath = state.path; ··· 671 668 Storage.remove(filePath.c_str()); 672 669 } 673 670 state.error = "Upload aborted"; 674 - Serial.printf("[%lu] [WEB] Upload aborted\n", millis()); 671 + LOG_DBG("WEB", "Upload aborted"); 675 672 } 676 673 } 677 674 ··· 716 713 if (!folderPath.endsWith("/")) folderPath += "/"; 717 714 folderPath += folderName; 718 715 719 - Serial.printf("[%lu] [WEB] Creating folder: %s\n", millis(), folderPath.c_str()); 716 + LOG_DBG("WEB", "Creating folder: %s", folderPath.c_str()); 720 717 721 718 // Check if already exists 722 719 if (Storage.exists(folderPath.c_str())) { ··· 726 723 727 724 // Create the folder 728 725 if (Storage.mkdir(folderPath.c_str())) { 729 - Serial.printf("[%lu] [WEB] Folder created successfully: %s\n", millis(), folderPath.c_str()); 726 + LOG_DBG("WEB", "Folder created successfully: %s", folderPath.c_str()); 730 727 server->send(200, "text/plain", "Folder created: " + folderName); 731 728 } else { 732 - Serial.printf("[%lu] [WEB] Failed to create folder: %s\n", millis(), folderPath.c_str()); 729 + LOG_DBG("WEB", "Failed to create folder: %s", folderPath.c_str()); 733 730 server->send(500, "text/plain", "Failed to create folder"); 734 731 } 735 732 } ··· 808 805 file.close(); 809 806 810 807 if (success) { 811 - Serial.printf("[%lu] [WEB] Renamed file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str()); 808 + LOG_DBG("WEB", "Renamed file: %s -> %s", itemPath.c_str(), newPath.c_str()); 812 809 server->send(200, "text/plain", "Renamed successfully"); 813 810 } else { 814 - Serial.printf("[%lu] [WEB] Failed to rename file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str()); 811 + LOG_ERR("WEB", "Failed to rename file: %s -> %s", itemPath.c_str(), newPath.c_str()); 815 812 server->send(500, "text/plain", "Failed to rename file"); 816 813 } 817 814 } ··· 901 898 file.close(); 902 899 903 900 if (success) { 904 - Serial.printf("[%lu] [WEB] Moved file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str()); 901 + LOG_DBG("WEB", "Moved file: %s -> %s", itemPath.c_str(), newPath.c_str()); 905 902 server->send(200, "text/plain", "Moved successfully"); 906 903 } else { 907 - Serial.printf("[%lu] [WEB] Failed to move file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str()); 904 + LOG_ERR("WEB", "Failed to move file: %s -> %s", itemPath.c_str(), newPath.c_str()); 908 905 server->send(500, "text/plain", "Failed to move file"); 909 906 } 910 907 } ··· 935 932 936 933 // Check if item starts with a dot (hidden/system file) 937 934 if (itemName.startsWith(".")) { 938 - Serial.printf("[%lu] [WEB] Delete rejected - hidden/system item: %s\n", millis(), itemPath.c_str()); 935 + LOG_DBG("WEB", "Delete rejected - hidden/system item: %s", itemPath.c_str()); 939 936 server->send(403, "text/plain", "Cannot delete system files"); 940 937 return; 941 938 } ··· 943 940 // Check against explicitly protected items 944 941 for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) { 945 942 if (itemName.equals(HIDDEN_ITEMS[i])) { 946 - Serial.printf("[%lu] [WEB] Delete rejected - protected item: %s\n", millis(), itemPath.c_str()); 943 + LOG_DBG("WEB", "Delete rejected - protected item: %s", itemPath.c_str()); 947 944 server->send(403, "text/plain", "Cannot delete protected items"); 948 945 return; 949 946 } ··· 951 948 952 949 // Check if item exists 953 950 if (!Storage.exists(itemPath.c_str())) { 954 - Serial.printf("[%lu] [WEB] Delete failed - item not found: %s\n", millis(), itemPath.c_str()); 951 + LOG_DBG("WEB", "Delete failed - item not found: %s", itemPath.c_str()); 955 952 server->send(404, "text/plain", "Item not found"); 956 953 return; 957 954 } 958 955 959 - Serial.printf("[%lu] [WEB] Attempting to delete %s: %s\n", millis(), itemType.c_str(), itemPath.c_str()); 956 + LOG_DBG("WEB", "Attempting to delete %s: %s", itemType.c_str(), itemPath.c_str()); 960 957 961 958 bool success = false; 962 959 ··· 970 967 // Folder is not empty 971 968 entry.close(); 972 969 dir.close(); 973 - Serial.printf("[%lu] [WEB] Delete failed - folder not empty: %s\n", millis(), itemPath.c_str()); 970 + LOG_DBG("WEB", "Delete failed - folder not empty: %s", itemPath.c_str()); 974 971 server->send(400, "text/plain", "Folder is not empty. Delete contents first."); 975 972 return; 976 973 } ··· 983 980 } 984 981 985 982 if (success) { 986 - Serial.printf("[%lu] [WEB] Successfully deleted: %s\n", millis(), itemPath.c_str()); 983 + LOG_DBG("WEB", "Successfully deleted: %s", itemPath.c_str()); 987 984 server->send(200, "text/plain", "Deleted successfully"); 988 985 } else { 989 - Serial.printf("[%lu] [WEB] Failed to delete: %s\n", millis(), itemPath.c_str()); 986 + LOG_ERR("WEB", "Failed to delete: %s", itemPath.c_str()); 990 987 server->send(500, "text/plain", "Failed to delete item"); 991 988 } 992 989 } 993 990 994 991 void CrossPointWebServer::handleSettingsPage() const { 995 992 server->send(200, "text/html", SettingsPageHtml); 996 - Serial.printf("[%lu] [WEB] Served settings page\n", millis()); 993 + LOG_DBG("WEB", "Served settings page"); 997 994 } 998 995 999 996 void CrossPointWebServer::handleGetSettings() const { ··· 1062 1059 1063 1060 const size_t written = serializeJson(doc, output, outputSize); 1064 1061 if (written >= outputSize) { 1065 - Serial.printf("[%lu] [WEB] Skipping oversized setting JSON for: %s\n", millis(), s.key); 1062 + LOG_DBG("WEB", "Skipping oversized setting JSON for: %s", s.key); 1066 1063 continue; 1067 1064 } 1068 1065 ··· 1076 1073 1077 1074 server->sendContent("]"); 1078 1075 server->sendContent(""); 1079 - Serial.printf("[%lu] [WEB] Served settings API\n", millis()); 1076 + LOG_DBG("WEB", "Served settings API"); 1080 1077 } 1081 1078 1082 1079 void CrossPointWebServer::handlePostSettings() { ··· 1149 1146 1150 1147 SETTINGS.saveToFile(); 1151 1148 1152 - Serial.printf("[%lu] [WEB] Applied %d setting(s)\n", millis(), applied); 1149 + LOG_DBG("WEB", "Applied %d setting(s)", applied); 1153 1150 server->send(200, "text/plain", String("Applied ") + String(applied) + " setting(s)"); 1154 1151 } 1155 1152 ··· 1169 1166 void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) { 1170 1167 switch (type) { 1171 1168 case WStype_DISCONNECTED: 1172 - Serial.printf("[%lu] [WS] Client %u disconnected\n", millis(), num); 1169 + LOG_DBG("WS", "Client %u disconnected", num); 1173 1170 // Clean up any in-progress upload 1174 1171 if (wsUploadInProgress && wsUploadFile) { 1175 1172 wsUploadFile.close(); ··· 1178 1175 if (!filePath.endsWith("/")) filePath += "/"; 1179 1176 filePath += wsUploadFileName; 1180 1177 Storage.remove(filePath.c_str()); 1181 - Serial.printf("[%lu] [WS] Deleted incomplete upload: %s\n", millis(), filePath.c_str()); 1178 + LOG_DBG("WS", "Deleted incomplete upload: %s", filePath.c_str()); 1182 1179 } 1183 1180 wsUploadInProgress = false; 1184 1181 break; 1185 1182 1186 1183 case WStype_CONNECTED: { 1187 - Serial.printf("[%lu] [WS] Client %u connected\n", millis(), num); 1184 + LOG_DBG("WS", "Client %u connected", num); 1188 1185 break; 1189 1186 } 1190 1187 1191 1188 case WStype_TEXT: { 1192 1189 // Parse control messages 1193 1190 String msg = String((char*)payload); 1194 - Serial.printf("[%lu] [WS] Text from client %u: %s\n", millis(), num, msg.c_str()); 1191 + LOG_DBG("WS", "Text from client %u: %s", num, msg.c_str()); 1195 1192 1196 1193 if (msg.startsWith("START:")) { 1197 1194 // Parse: START:<filename>:<size>:<path> ··· 1216 1213 if (!filePath.endsWith("/")) filePath += "/"; 1217 1214 filePath += wsUploadFileName; 1218 1215 1219 - Serial.printf("[%lu] [WS] Starting upload: %s (%d bytes) to %s\n", millis(), wsUploadFileName.c_str(), 1220 - wsUploadSize, filePath.c_str()); 1216 + LOG_DBG("WS", "Starting upload: %s (%d bytes) to %s", wsUploadFileName.c_str(), wsUploadSize, 1217 + filePath.c_str()); 1221 1218 1222 1219 // Check if file exists and remove it 1223 1220 esp_task_wdt_reset(); ··· 1283 1280 unsigned long elapsed = millis() - wsUploadStartTime; 1284 1281 float kbps = (elapsed > 0) ? (wsUploadSize / 1024.0) / (elapsed / 1000.0) : 0; 1285 1282 1286 - Serial.printf("[%lu] [WS] Upload complete: %s (%d bytes in %lu ms, %.1f KB/s)\n", millis(), 1287 - wsUploadFileName.c_str(), wsUploadSize, elapsed, kbps); 1283 + LOG_DBG("WS", "Upload complete: %s (%d bytes in %lu ms, %.1f KB/s)", wsUploadFileName.c_str(), wsUploadSize, 1284 + elapsed, kbps); 1288 1285 1289 1286 // Clear epub cache to prevent stale metadata issues when overwriting files 1290 1287 String filePath = wsUploadPath;
+13 -13
src/network/HttpDownloader.cpp
··· 1 1 #include "HttpDownloader.h" 2 2 3 3 #include <HTTPClient.h> 4 - #include <HardwareSerial.h> 4 + #include <Logging.h> 5 5 #include <StreamString.h> 6 6 #include <WiFiClient.h> 7 7 #include <WiFiClientSecure.h> ··· 25 25 } 26 26 HTTPClient http; 27 27 28 - Serial.printf("[%lu] [HTTP] Fetching: %s\n", millis(), url.c_str()); 28 + LOG_DBG("HTTP", "Fetching: %s", url.c_str()); 29 29 30 30 http.begin(*client, url.c_str()); 31 31 http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); ··· 40 40 41 41 const int httpCode = http.GET(); 42 42 if (httpCode != HTTP_CODE_OK) { 43 - Serial.printf("[%lu] [HTTP] Fetch failed: %d\n", millis(), httpCode); 43 + LOG_ERR("HTTP", "Fetch failed: %d", httpCode); 44 44 http.end(); 45 45 return false; 46 46 } ··· 49 49 50 50 http.end(); 51 51 52 - Serial.printf("[%lu] [HTTP] Fetch success\n", millis()); 52 + LOG_DBG("HTTP", "Fetch success"); 53 53 return true; 54 54 } 55 55 ··· 75 75 } 76 76 HTTPClient http; 77 77 78 - Serial.printf("[%lu] [HTTP] Downloading: %s\n", millis(), url.c_str()); 79 - Serial.printf("[%lu] [HTTP] Destination: %s\n", millis(), destPath.c_str()); 78 + LOG_DBG("HTTP", "Downloading: %s", url.c_str()); 79 + LOG_DBG("HTTP", "Destination: %s", destPath.c_str()); 80 80 81 81 http.begin(*client, url.c_str()); 82 82 http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS); ··· 91 91 92 92 const int httpCode = http.GET(); 93 93 if (httpCode != HTTP_CODE_OK) { 94 - Serial.printf("[%lu] [HTTP] Download failed: %d\n", millis(), httpCode); 94 + LOG_ERR("HTTP", "Download failed: %d", httpCode); 95 95 http.end(); 96 96 return HTTP_ERROR; 97 97 } 98 98 99 99 const size_t contentLength = http.getSize(); 100 - Serial.printf("[%lu] [HTTP] Content-Length: %zu\n", millis(), contentLength); 100 + LOG_DBG("HTTP", "Content-Length: %zu", contentLength); 101 101 102 102 // Remove existing file if present 103 103 if (Storage.exists(destPath.c_str())) { ··· 107 107 // Open file for writing 108 108 FsFile file; 109 109 if (!Storage.openFileForWrite("HTTP", destPath.c_str(), file)) { 110 - Serial.printf("[%lu] [HTTP] Failed to open file for writing\n", millis()); 110 + LOG_ERR("HTTP", "Failed to open file for writing"); 111 111 http.end(); 112 112 return FILE_ERROR; 113 113 } ··· 115 115 // Get the stream for chunked reading 116 116 WiFiClient* stream = http.getStreamPtr(); 117 117 if (!stream) { 118 - Serial.printf("[%lu] [HTTP] Failed to get stream\n", millis()); 118 + LOG_ERR("HTTP", "Failed to get stream"); 119 119 file.close(); 120 120 Storage.remove(destPath.c_str()); 121 121 http.end(); ··· 143 143 144 144 const size_t written = file.write(buffer, bytesRead); 145 145 if (written != bytesRead) { 146 - Serial.printf("[%lu] [HTTP] Write failed: wrote %zu of %zu bytes\n", millis(), written, bytesRead); 146 + LOG_ERR("HTTP", "Write failed: wrote %zu of %zu bytes", written, bytesRead); 147 147 file.close(); 148 148 Storage.remove(destPath.c_str()); 149 149 http.end(); ··· 160 160 file.close(); 161 161 http.end(); 162 162 163 - Serial.printf("[%lu] [HTTP] Downloaded %zu bytes\n", millis(), downloaded); 163 + LOG_DBG("HTTP", "Downloaded %zu bytes", downloaded); 164 164 165 165 // Verify download size if known 166 166 if (contentLength > 0 && downloaded != contentLength) { 167 - Serial.printf("[%lu] [HTTP] Size mismatch: got %zu, expected %zu\n", millis(), downloaded, contentLength); 167 + LOG_ERR("HTTP", "Size mismatch: got %zu, expected %zu", downloaded, contentLength); 168 168 Storage.remove(destPath.c_str()); 169 169 return HTTP_ERROR; 170 170 }
+17 -17
src/network/OtaUpdater.cpp
··· 1 1 #include "OtaUpdater.h" 2 2 3 3 #include <ArduinoJson.h> 4 + #include <Logging.h> 4 5 5 6 #include "esp_http_client.h" 6 7 #include "esp_https_ota.h" ··· 39 40 local_buf = static_cast<char*>(calloc(content_len + 1, sizeof(char))); 40 41 output_len = 0; 41 42 if (local_buf == NULL) { 42 - Serial.printf("[%lu] [OTA] HTTP Client Out of Memory Failed, Allocation %d\n", millis(), content_len); 43 + LOG_ERR("OTA", "HTTP Client Out of Memory Failed, Allocation %d", content_len); 43 44 return ESP_ERR_NO_MEM; 44 45 } 45 46 } ··· 52 53 /* Code might be hits here, It happened once (for version checking) but I need more logs to handle that */ 53 54 int chunked_len; 54 55 esp_http_client_get_chunk_length(event->client, &chunked_len); 55 - Serial.printf("[%lu] [OTA] esp_http_client_is_chunked_response failed, chunked_len: %d\n", millis(), chunked_len); 56 + LOG_DBG("OTA", "esp_http_client_is_chunked_response failed, chunked_len: %d", chunked_len); 56 57 } 57 58 58 59 return ESP_OK; ··· 88 89 89 90 esp_http_client_handle_t client_handle = esp_http_client_init(&client_config); 90 91 if (!client_handle) { 91 - Serial.printf("[%lu] [OTA] HTTP Client Handle Failed\n", millis()); 92 + LOG_ERR("OTA", "HTTP Client Handle Failed"); 92 93 return INTERNAL_UPDATE_ERROR; 93 94 } 94 95 95 96 esp_err = esp_http_client_set_header(client_handle, "User-Agent", "CrossPoint-ESP32-" CROSSPOINT_VERSION); 96 97 if (esp_err != ESP_OK) { 97 - Serial.printf("[%lu] [OTA] esp_http_client_set_header Failed : %s\n", millis(), esp_err_to_name(esp_err)); 98 + LOG_ERR("OTA", "esp_http_client_set_header Failed : %s", esp_err_to_name(esp_err)); 98 99 esp_http_client_cleanup(client_handle); 99 100 return INTERNAL_UPDATE_ERROR; 100 101 } 101 102 102 103 esp_err = esp_http_client_perform(client_handle); 103 104 if (esp_err != ESP_OK) { 104 - Serial.printf("[%lu] [OTA] esp_http_client_perform Failed : %s\n", millis(), esp_err_to_name(esp_err)); 105 + LOG_ERR("OTA", "esp_http_client_perform Failed : %s", esp_err_to_name(esp_err)); 105 106 esp_http_client_cleanup(client_handle); 106 107 return HTTP_ERROR; 107 108 } ··· 109 110 /* esp_http_client_close will be called inside cleanup as well*/ 110 111 esp_err = esp_http_client_cleanup(client_handle); 111 112 if (esp_err != ESP_OK) { 112 - Serial.printf("[%lu] [OTA] esp_http_client_cleanupp Failed : %s\n", millis(), esp_err_to_name(esp_err)); 113 + LOG_ERR("OTA", "esp_http_client_cleanup Failed : %s", esp_err_to_name(esp_err)); 113 114 return INTERNAL_UPDATE_ERROR; 114 115 } 115 116 ··· 119 120 filter["assets"][0]["size"] = true; 120 121 const DeserializationError error = deserializeJson(doc, local_buf, DeserializationOption::Filter(filter)); 121 122 if (error) { 122 - Serial.printf("[%lu] [OTA] JSON parse failed: %s\n", millis(), error.c_str()); 123 + LOG_ERR("OTA", "JSON parse failed: %s", error.c_str()); 123 124 return JSON_PARSE_ERROR; 124 125 } 125 126 126 127 if (!doc["tag_name"].is<std::string>()) { 127 - Serial.printf("[%lu] [OTA] No tag_name found\n", millis()); 128 + LOG_ERR("OTA", "No tag_name found"); 128 129 return JSON_PARSE_ERROR; 129 130 } 130 131 131 132 if (!doc["assets"].is<JsonArray>()) { 132 - Serial.printf("[%lu] [OTA] No assets found\n", millis()); 133 + LOG_ERR("OTA", "No assets found"); 133 134 return JSON_PARSE_ERROR; 134 135 } 135 136 ··· 146 147 } 147 148 148 149 if (!updateAvailable) { 149 - Serial.printf("[%lu] [OTA] No firmware.bin asset found\n", millis()); 150 + LOG_ERR("OTA", "No firmware.bin asset found"); 150 151 return NO_UPDATE; 151 152 } 152 153 153 - Serial.printf("[%lu] [OTA] Found update: %s\n", millis(), latestVersion.c_str()); 154 + LOG_DBG("OTA", "Found update: %s", latestVersion.c_str()); 154 155 return OK; 155 156 } 156 157 ··· 233 234 234 235 esp_err = esp_https_ota_begin(&ota_config, &ota_handle); 235 236 if (esp_err != ESP_OK) { 236 - Serial.printf("[%lu] [OTA] HTTP OTA Begin Failed: %s\n", millis(), esp_err_to_name(esp_err)); 237 + LOG_DBG("OTA", "HTTP OTA Begin Failed: %s", esp_err_to_name(esp_err)); 237 238 return INTERNAL_UPDATE_ERROR; 238 239 } 239 240 ··· 249 250 esp_wifi_set_ps(WIFI_PS_MIN_MODEM); 250 251 251 252 if (esp_err != ESP_OK) { 252 - Serial.printf("[%lu] [OTA] esp_https_ota_perform Failed: %s\n", millis(), esp_err_to_name(esp_err)); 253 + LOG_ERR("OTA", "esp_https_ota_perform Failed: %s", esp_err_to_name(esp_err)); 253 254 esp_https_ota_finish(ota_handle); 254 255 return HTTP_ERROR; 255 256 } 256 257 257 258 if (!esp_https_ota_is_complete_data_received(ota_handle)) { 258 - Serial.printf("[%lu] [OTA] esp_https_ota_is_complete_data_received Failed: %s\n", millis(), 259 - esp_err_to_name(esp_err)); 259 + LOG_ERR("OTA", "esp_https_ota_is_complete_data_received Failed: %s", esp_err_to_name(esp_err)); 260 260 esp_https_ota_finish(ota_handle); 261 261 return INTERNAL_UPDATE_ERROR; 262 262 } 263 263 264 264 esp_err = esp_https_ota_finish(ota_handle); 265 265 if (esp_err != ESP_OK) { 266 - Serial.printf("[%lu] [OTA] esp_https_ota_finish Failed: %s\n", millis(), esp_err_to_name(esp_err)); 266 + LOG_ERR("OTA", "esp_https_ota_finish Failed: %s", esp_err_to_name(esp_err)); 267 267 return INTERNAL_UPDATE_ERROR; 268 268 } 269 269 270 - Serial.printf("[%lu] [OTA] Update completed\n", millis()); 270 + LOG_INF("OTA", "Update completed"); 271 271 return OK; 272 272 }