merge upstream/master: logging pragma, screenshot retrieval, nbsp fix

Merge 3 upstream commits into mod/master:
- feat: Allow screenshot retrieval from device (#820)
- feat: Add central logging pragma (#843)
- fix: Account for nbsp character as non-breaking space (#757)

Conflict resolution:
- src/main.cpp: kept mod's HalPowerManager + upstream's Logging/screenshot
- SleepActivity.cpp: kept mod's letterbox fill rework, applied LOG_* pattern

Additional changes for logging compatibility:
- Converted remaining Serial.printf calls in mod files to LOG_* macros
  (HalPowerManager, BookSettings, BookmarkStore, GfxRenderer)
- Added ENABLE_SERIAL_LOG and LOG_LEVEL=2 to [env:mod] build flags

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
cottongin
2026-02-13 16:27:58 -05:00
58 changed files with 1188 additions and 768 deletions

View File

@@ -1,6 +1,6 @@
#pragma once
#include <HardwareSerial.h>
#include <Logging.h>
#include <string>
#include <utility>
@@ -18,8 +18,8 @@ class Activity {
explicit Activity(std::string name, GfxRenderer& renderer, MappedInputManager& mappedInput)
: name(std::move(name)), renderer(renderer), mappedInput(mappedInput) {}
virtual ~Activity() = default;
virtual void onEnter() { Serial.printf("[%lu] [ACT] Entering activity: %s\n", millis(), name.c_str()); }
virtual void onExit() { Serial.printf("[%lu] [ACT] Exiting activity: %s\n", millis(), name.c_str()); }
virtual void onEnter() { LOG_DBG("ACT", "Entering activity: %s", name.c_str()); }
virtual void onExit() { LOG_DBG("ACT", "Exiting activity: %s", name.c_str()); }
virtual void loop() {}
virtual bool skipLoopDelay() { return false; }
virtual bool preventAutoSleep() { return false; }

View File

@@ -3,6 +3,7 @@
#include <Epub.h>
#include <GfxRenderer.h>
#include <HalStorage.h>
#include <Logging.h>
#include <Serialization.h>
#include <Txt.h>
#include <Xtc.h>
@@ -142,8 +143,7 @@ bool loadEdgeCache(const std::string& path, int screenWidth, int screenHeight, L
file.close();
data.valid = true;
Serial.printf("[%lu] [SLP] Loaded edge cache from %s (avgA=%d, avgB=%d)\n", millis(), path.c_str(), data.avgA,
data.avgB);
LOG_DBG("SLP", "Loaded edge cache from %s (avgA=%d, avgB=%d)", path.c_str(), data.avgA, data.avgB);
return true;
}
@@ -163,7 +163,7 @@ bool saveEdgeCache(const std::string& path, int screenWidth, int screenHeight, c
serialization::writePod(file, static_cast<int16_t>(data.letterboxB));
file.close();
Serial.printf("[%lu] [SLP] Saved edge cache to %s\n", millis(), path.c_str());
LOG_DBG("SLP", "Saved edge cache to %s", path.c_str());
return true;
}
@@ -380,13 +380,13 @@ void SleepActivity::renderCustomSleepScreen() const {
}
if (filename.substr(filename.length() - 4) != ".bmp") {
Serial.printf("[%lu] [SLP] Skipping non-.bmp file name: %s\n", millis(), name);
LOG_DBG("SLP", "Skipping non-.bmp file name: %s", name);
file.close();
continue;
}
Bitmap bitmap(file);
if (bitmap.parseHeaders() != BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Skipping invalid BMP file: %s\n", millis(), name);
LOG_DBG("SLP", "Skipping invalid BMP file: %s", name);
file.close();
continue;
}
@@ -406,7 +406,7 @@ void SleepActivity::renderCustomSleepScreen() const {
const auto filename = "/sleep/" + files[randomFileIndex];
FsFile file;
if (Storage.openFileForRead("SLP", filename, file)) {
Serial.printf("[%lu] [SLP] Randomly loading: /sleep/%s\n", millis(), files[randomFileIndex].c_str());
LOG_DBG("SLP", "Randomly loading: /sleep/%s", files[randomFileIndex].c_str());
delay(100);
Bitmap bitmap(file, true);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
@@ -425,7 +425,7 @@ void SleepActivity::renderCustomSleepScreen() const {
if (Storage.openFileForRead("SLP", "/sleep.bmp", file)) {
Bitmap bitmap(file, true);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Loading: /sleep.bmp\n", millis());
LOG_DBG("SLP", "Loading: /sleep.bmp");
renderBitmapSleepScreen(bitmap);
return;
}
@@ -458,37 +458,36 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap, const std::str
const auto pageHeight = renderer.getScreenHeight();
float cropX = 0, cropY = 0;
Serial.printf("[%lu] [SLP] bitmap %d x %d, screen %d x %d\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
pageWidth, pageHeight);
LOG_DBG("SLP", "bitmap %d x %d, screen %d x %d", bitmap.getWidth(), bitmap.getHeight(), pageWidth, pageHeight);
// Always compute aspect-ratio-preserving scale and position (supports both larger and smaller images)
float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight);
Serial.printf("[%lu] [SLP] bitmap ratio: %f, screen ratio: %f\n", millis(), ratio, screenRatio);
LOG_DBG("SLP", "bitmap ratio: %f, screen ratio: %f", ratio, screenRatio);
if (ratio > screenRatio) {
// image wider than viewport ratio, needs to be centered vertically
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
cropX = 1.0f - (screenRatio / ratio);
Serial.printf("[%lu] [SLP] Cropping bitmap x: %f\n", millis(), cropX);
LOG_DBG("SLP", "Cropping bitmap x: %f", cropX);
ratio = (1.0f - cropX) * static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
}
x = 0;
y = std::round((static_cast<float>(pageHeight) - static_cast<float>(pageWidth) / ratio) / 2);
Serial.printf("[%lu] [SLP] Centering with ratio %f to y=%d\n", millis(), ratio, y);
LOG_DBG("SLP", "Centering with ratio %f to y=%d", ratio, y);
} else {
// image taller than or equal to viewport ratio, needs to be centered horizontally
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
cropY = 1.0f - (ratio / screenRatio);
Serial.printf("[%lu] [SLP] Cropping bitmap y: %f\n", millis(), cropY);
LOG_DBG("SLP", "Cropping bitmap y: %f", cropY);
ratio = static_cast<float>(bitmap.getWidth()) / ((1.0f - cropY) * static_cast<float>(bitmap.getHeight()));
}
x = std::round((static_cast<float>(pageWidth) - static_cast<float>(pageHeight) * ratio) / 2);
y = 0;
Serial.printf("[%lu] [SLP] Centering with ratio %f to x=%d\n", millis(), ratio, x);
LOG_DBG("SLP", "Centering with ratio %f to x=%d", ratio, x);
}
Serial.printf("[%lu] [SLP] drawing to %d x %d\n", millis(), x, y);
LOG_DBG("SLP", "drawing to %d x %d", x, y);
// Compute the scale factor (same formula as drawBitmap) so we can map screen coords to source coords
const float effectiveWidth = (1.0f - cropX) * bitmap.getWidth();
@@ -515,17 +514,16 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap, const std::str
cacheLoaded = loadEdgeCache(edgeCachePath, pageWidth, pageHeight, fillData);
}
if (!cacheLoaded) {
Serial.printf("[%lu] [SLP] Letterbox detected (x=%d, y=%d), computing edge averages for %s fill\n", millis(), x,
y, fillModeName);
LOG_DBG("SLP", "Letterbox detected (x=%d, y=%d), computing edge averages for %s fill", x, y, fillModeName);
fillData = computeEdgeAverages(bitmap, x, y, pageWidth, pageHeight, scale, cropX, cropY);
if (fillData.valid && !edgeCachePath.empty()) {
saveEdgeCache(edgeCachePath, pageWidth, pageHeight, fillData);
}
}
if (fillData.valid) {
Serial.printf("[%lu] [SLP] Letterbox fill: %s, horizontal=%d, avgA=%d, avgB=%d, letterboxA=%d, letterboxB=%d\n",
millis(), fillModeName, fillData.horizontal, fillData.avgA, fillData.avgB, fillData.letterboxA,
fillData.letterboxB);
LOG_DBG("SLP", "Letterbox fill: %s, horizontal=%d, avgA=%d, avgB=%d, letterboxA=%d, letterboxB=%d",
fillModeName, fillData.horizontal, fillData.avgA, fillData.avgB, fillData.letterboxA,
fillData.letterboxB);
}
}
@@ -596,12 +594,12 @@ void SleepActivity::renderCoverSleepScreen() const {
// Handle XTC file
Xtc lastXtc(APP_STATE.openEpubPath, "/.crosspoint");
if (!lastXtc.load()) {
Serial.printf("[%lu] [SLP] Failed to load last XTC\n", millis());
LOG_ERR("SLP", "Failed to load last XTC");
return (this->*renderNoCoverSleepScreen)();
}
if (!lastXtc.generateCoverBmp()) {
Serial.printf("[%lu] [SLP] Failed to generate XTC cover bmp\n", millis());
LOG_ERR("SLP", "Failed to generate XTC cover bmp");
return (this->*renderNoCoverSleepScreen)();
}
@@ -611,12 +609,12 @@ void SleepActivity::renderCoverSleepScreen() const {
// Handle TXT file - looks for cover image in the same folder
Txt lastTxt(APP_STATE.openEpubPath, "/.crosspoint");
if (!lastTxt.load()) {
Serial.printf("[%lu] [SLP] Failed to load last TXT\n", millis());
LOG_ERR("SLP", "Failed to load last TXT");
return (this->*renderNoCoverSleepScreen)();
}
if (!lastTxt.generateCoverBmp()) {
Serial.printf("[%lu] [SLP] No cover image found for TXT file\n", millis());
LOG_ERR("SLP", "No cover image found for TXT file");
return (this->*renderNoCoverSleepScreen)();
}
@@ -627,12 +625,12 @@ void SleepActivity::renderCoverSleepScreen() const {
Epub lastEpub(APP_STATE.openEpubPath, "/.crosspoint");
// Skip loading css since we only need metadata here
if (!lastEpub.load(true, true)) {
Serial.printf("[%lu] [SLP] Failed to load last epub\n", millis());
LOG_ERR("SLP", "Failed to load last epub");
return (this->*renderNoCoverSleepScreen)();
}
if (!lastEpub.generateCoverBmp(cropped)) {
Serial.printf("[%lu] [SLP] Failed to generate cover bmp\n", millis());
LOG_ERR("SLP", "Failed to generate cover bmp");
return (this->*renderNoCoverSleepScreen)();
}
@@ -653,7 +651,7 @@ void SleepActivity::renderCoverSleepScreen() const {
if (Storage.openFileForRead("SLP", coverBmpPath, file)) {
Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("[%lu] [SLP] Rendering sleep cover: %s\n", millis(), coverBmpPath.c_str());
LOG_DBG("SLP", "Rendering sleep cover: %s", coverBmpPath.c_str());
// Derive edge cache path from cover BMP path (e.g. cover.bmp -> cover_edges.bin)
std::string edgeCachePath;
const auto dotPos = coverBmpPath.rfind(".bmp");

View File

@@ -2,7 +2,7 @@
#include <Epub.h>
#include <GfxRenderer.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <OpdsStream.h>
#include <WiFi.h>
@@ -78,14 +78,14 @@ void OpdsBookBrowserActivity::loop() {
// Check if WiFi is still connected
if (WiFi.status() == WL_CONNECTED && WiFi.localIP() != IPAddress(0, 0, 0, 0)) {
// WiFi connected - just retry fetching the feed
Serial.printf("[%lu] [OPDS] Retry: WiFi connected, retrying fetch\n", millis());
LOG_DBG("OPDS", "Retry: WiFi connected, retrying fetch");
state = BrowserState::LOADING;
statusMessage = "Loading...";
updateRequired = true;
fetchFeed(currentPath);
} else {
// WiFi not connected - launch WiFi selection
Serial.printf("[%lu] [OPDS] Retry: WiFi not connected, launching selection\n", millis());
LOG_DBG("OPDS", "Retry: WiFi not connected, launching selection");
launchWifiSelection();
}
} else if (mappedInput.wasReleased(MappedInputManager::Button::Back)) {
@@ -265,7 +265,7 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
}
std::string url = UrlUtils::buildUrl(serverUrl, path);
Serial.printf("[%lu] [OPDS] Fetching: %s\n", millis(), url.c_str());
LOG_DBG("OPDS", "Fetching: %s", url.c_str());
OpdsParser parser;
@@ -287,7 +287,7 @@ void OpdsBookBrowserActivity::fetchFeed(const std::string& path) {
}
entries = std::move(parser).getEntries();
Serial.printf("[%lu] [OPDS] Found %d entries\n", millis(), entries.size());
LOG_DBG("OPDS", "Found %d entries", entries.size());
selectorIndex = 0;
if (entries.empty()) {
@@ -351,7 +351,7 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
}
std::string filename = "/" + StringUtils::sanitizeFilename(baseName) + ".epub";
Serial.printf("[%lu] [OPDS] Downloading: %s -> %s\n", millis(), downloadUrl.c_str(), filename.c_str());
LOG_DBG("OPDS", "Downloading: %s -> %s", downloadUrl.c_str(), filename.c_str());
const auto result =
HttpDownloader::downloadToFile(downloadUrl, filename, [this](const size_t downloaded, const size_t total) {
@@ -361,12 +361,12 @@ void OpdsBookBrowserActivity::downloadBook(const OpdsEntry& book) {
});
if (result == HttpDownloader::OK) {
Serial.printf("[%lu] [OPDS] Download complete: %s\n", millis(), filename.c_str());
LOG_DBG("OPDS", "Download complete: %s", filename.c_str());
// Invalidate any existing cache for this file to prevent stale metadata issues
Epub epub(filename, "/.crosspoint");
epub.clearCache();
Serial.printf("[%lu] [OPDS] Cleared cache for: %s\n", millis(), filename.c_str());
LOG_DBG("OPDS", "Cleared cache for: %s", filename.c_str());
state = BrowserState::BROWSING;
updateRequired = true;
@@ -403,13 +403,13 @@ void OpdsBookBrowserActivity::onWifiSelectionComplete(const bool connected) {
exitActivity();
if (connected) {
Serial.printf("[%lu] [OPDS] WiFi connected via selection, fetching feed\n", millis());
LOG_DBG("OPDS", "WiFi connected via selection, fetching feed");
state = BrowserState::LOADING;
statusMessage = "Loading...";
updateRequired = true;
fetchFeed(currentPath);
} else {
Serial.printf("[%lu] [OPDS] WiFi selection cancelled/failed\n", millis());
LOG_DBG("OPDS", "WiFi selection cancelled/failed");
// Force disconnect to ensure clean state for next retry
// This prevents stale connection status from interfering
WiFi.disconnect();

View File

@@ -73,7 +73,7 @@ void RecentBooksActivity::loop() {
if (mappedInput.wasReleased(MappedInputManager::Button::Confirm)) {
if (!recentBooks.empty() && selectorIndex < static_cast<int>(recentBooks.size())) {
Serial.printf("[%lu] [RBA] Selected recent book: %s\n", millis(), recentBooks[selectorIndex].path.c_str());
LOG_DBG("RBA", "Selected recent book: %s", recentBooks[selectorIndex].path.c_str());
onSelectBook(recentBooks[selectorIndex].path);
return;
}

View File

@@ -96,7 +96,7 @@ void CalibreConnectActivity::startWebServer() {
if (MDNS.begin(HOSTNAME)) {
// mDNS is optional for the Calibre plugin but still helpful for users.
Serial.printf("[%lu] [CAL] mDNS started: http://%s.local/\n", millis(), HOSTNAME);
LOG_DBG("CAL", "mDNS started: http://%s.local/", HOSTNAME);
}
webServer.reset(new CrossPointWebServer());
@@ -131,7 +131,7 @@ void CalibreConnectActivity::loop() {
if (webServer && webServer->isRunning()) {
const unsigned long timeSinceLastHandleClient = millis() - lastHandleClientTime;
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
Serial.printf("[%lu] [CAL] WARNING: %lu ms gap since last handleClient\n", millis(), timeSinceLastHandleClient);
LOG_DBG("CAL", "WARNING: %lu ms gap since last handleClient", timeSinceLastHandleClient);
}
esp_task_wdt_reset();

View File

@@ -37,7 +37,7 @@ void CrossPointWebServerActivity::taskTrampoline(void* param) {
void CrossPointWebServerActivity::onEnter() {
ActivityWithSubactivity::onEnter();
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onEnter: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEBACT] [MEM", "Free heap at onEnter: %d bytes", ESP.getFreeHeap());
renderingMutex = xSemaphoreCreateMutex();
@@ -58,7 +58,7 @@ void CrossPointWebServerActivity::onEnter() {
);
// Launch network mode selection subactivity
Serial.printf("[%lu] [WEBACT] Launching NetworkModeSelectionActivity...\n", millis());
LOG_DBG("WEBACT", "Launching NetworkModeSelectionActivity...");
enterNewActivity(new NetworkModeSelectionActivity(
renderer, mappedInput, [this](const NetworkMode mode) { onNetworkModeSelected(mode); },
[this]() { onGoBack(); } // Cancel goes back to home
@@ -68,7 +68,7 @@ void CrossPointWebServerActivity::onEnter() {
void CrossPointWebServerActivity::onExit() {
ActivityWithSubactivity::onExit();
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEBACT] [MEM", "Free heap at onExit start: %d bytes", ESP.getFreeHeap());
state = WebServerActivityState::SHUTTING_DOWN;
@@ -80,7 +80,7 @@ void CrossPointWebServerActivity::onExit() {
// Stop DNS server if running (AP mode)
if (dnsServer) {
Serial.printf("[%lu] [WEBACT] Stopping DNS server...\n", millis());
LOG_DBG("WEBACT", "Stopping DNS server...");
dnsServer->stop();
delete dnsServer;
dnsServer = nullptr;
@@ -91,39 +91,39 @@ void CrossPointWebServerActivity::onExit() {
// Disconnect WiFi gracefully
if (isApMode) {
Serial.printf("[%lu] [WEBACT] Stopping WiFi AP...\n", millis());
LOG_DBG("WEBACT", "Stopping WiFi AP...");
WiFi.softAPdisconnect(true);
} else {
Serial.printf("[%lu] [WEBACT] Disconnecting WiFi (graceful)...\n", millis());
LOG_DBG("WEBACT", "Disconnecting WiFi (graceful)...");
WiFi.disconnect(false); // false = don't erase credentials, send disconnect frame
}
delay(30); // Allow disconnect frame to be sent
Serial.printf("[%lu] [WEBACT] Setting WiFi mode OFF...\n", millis());
LOG_DBG("WEBACT", "Setting WiFi mode OFF...");
WiFi.mode(WIFI_OFF);
delay(30); // Allow WiFi hardware to power down
Serial.printf("[%lu] [WEBACT] [MEM] Free heap after WiFi disconnect: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEBACT] [MEM", "Free heap after WiFi disconnect: %d bytes", ESP.getFreeHeap());
// Acquire mutex before deleting task
Serial.printf("[%lu] [WEBACT] Acquiring rendering mutex before task deletion...\n", millis());
LOG_DBG("WEBACT", "Acquiring rendering mutex before task deletion...");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
// Delete the display task
Serial.printf("[%lu] [WEBACT] Deleting display task...\n", millis());
LOG_DBG("WEBACT", "Deleting display task...");
if (displayTaskHandle) {
vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr;
Serial.printf("[%lu] [WEBACT] Display task deleted\n", millis());
LOG_DBG("WEBACT", "Display task deleted");
}
// Delete the mutex
Serial.printf("[%lu] [WEBACT] Deleting mutex...\n", millis());
LOG_DBG("WEBACT", "Deleting mutex...");
vSemaphoreDelete(renderingMutex);
renderingMutex = nullptr;
Serial.printf("[%lu] [WEBACT] Mutex deleted\n", millis());
LOG_DBG("WEBACT", "Mutex deleted");
Serial.printf("[%lu] [WEBACT] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEBACT] [MEM", "Free heap at onExit end: %d bytes", ESP.getFreeHeap());
}
void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode) {
@@ -133,7 +133,7 @@ void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode)
} else if (mode == NetworkMode::CREATE_HOTSPOT) {
modeName = "Create Hotspot";
}
Serial.printf("[%lu] [WEBACT] Network mode selected: %s\n", millis(), modeName);
LOG_DBG("WEBACT", "Network mode selected: %s", modeName);
networkMode = mode;
isApMode = (mode == NetworkMode::CREATE_HOTSPOT);
@@ -155,11 +155,11 @@ void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode)
if (mode == NetworkMode::JOIN_NETWORK) {
// STA mode - launch WiFi selection
Serial.printf("[%lu] [WEBACT] Turning on WiFi (STA mode)...\n", millis());
LOG_DBG("WEBACT", "Turning on WiFi (STA mode)...");
WiFi.mode(WIFI_STA);
state = WebServerActivityState::WIFI_SELECTION;
Serial.printf("[%lu] [WEBACT] Launching WifiSelectionActivity...\n", millis());
LOG_DBG("WEBACT", "Launching WifiSelectionActivity...");
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
[this](const bool connected) { onWifiSelectionComplete(connected); }));
} else {
@@ -171,7 +171,7 @@ void CrossPointWebServerActivity::onNetworkModeSelected(const NetworkMode mode)
}
void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected) {
Serial.printf("[%lu] [WEBACT] WifiSelectionActivity completed, connected=%d\n", millis(), connected);
LOG_DBG("WEBACT", "WifiSelectionActivity completed, connected=%d", connected);
if (connected) {
// Get connection info before exiting subactivity
@@ -183,7 +183,7 @@ void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected)
// Start mDNS for hostname resolution
if (MDNS.begin(AP_HOSTNAME)) {
Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME);
LOG_DBG("WEBACT", "mDNS started: http://%s.local/", AP_HOSTNAME);
}
// Start the web server
@@ -199,8 +199,8 @@ void CrossPointWebServerActivity::onWifiSelectionComplete(const bool connected)
}
void CrossPointWebServerActivity::startAccessPoint() {
Serial.printf("[%lu] [WEBACT] Starting Access Point mode...\n", millis());
Serial.printf("[%lu] [WEBACT] [MEM] Free heap before AP start: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEBACT", "Starting Access Point mode...");
LOG_DBG("WEBACT] [MEM", "Free heap before AP start: %d bytes", ESP.getFreeHeap());
// Configure and start the AP
WiFi.mode(WIFI_AP);
@@ -216,7 +216,7 @@ void CrossPointWebServerActivity::startAccessPoint() {
}
if (!apStarted) {
Serial.printf("[%lu] [WEBACT] ERROR: Failed to start Access Point!\n", millis());
LOG_ERR("WEBACT", "ERROR: Failed to start Access Point!");
onGoBack();
return;
}
@@ -230,15 +230,15 @@ void CrossPointWebServerActivity::startAccessPoint() {
connectedIP = ipStr;
connectedSSID = AP_SSID;
Serial.printf("[%lu] [WEBACT] Access Point started!\n", millis());
Serial.printf("[%lu] [WEBACT] SSID: %s\n", millis(), AP_SSID);
Serial.printf("[%lu] [WEBACT] IP: %s\n", millis(), connectedIP.c_str());
LOG_DBG("WEBACT", "Access Point started!");
LOG_DBG("WEBACT", "SSID: %s", AP_SSID);
LOG_DBG("WEBACT", "IP: %s", connectedIP.c_str());
// Start mDNS for hostname resolution
if (MDNS.begin(AP_HOSTNAME)) {
Serial.printf("[%lu] [WEBACT] mDNS started: http://%s.local/\n", millis(), AP_HOSTNAME);
LOG_DBG("WEBACT", "mDNS started: http://%s.local/", AP_HOSTNAME);
} else {
Serial.printf("[%lu] [WEBACT] WARNING: mDNS failed to start\n", millis());
LOG_DBG("WEBACT", "WARNING: mDNS failed to start");
}
// Start DNS server for captive portal behavior
@@ -246,16 +246,16 @@ void CrossPointWebServerActivity::startAccessPoint() {
dnsServer = new DNSServer();
dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
dnsServer->start(DNS_PORT, "*", apIP);
Serial.printf("[%lu] [WEBACT] DNS server started for captive portal\n", millis());
LOG_DBG("WEBACT", "DNS server started for captive portal");
Serial.printf("[%lu] [WEBACT] [MEM] Free heap after AP start: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEBACT] [MEM", "Free heap after AP start: %d bytes", ESP.getFreeHeap());
// Start the web server
startWebServer();
}
void CrossPointWebServerActivity::startWebServer() {
Serial.printf("[%lu] [WEBACT] Starting web server...\n", millis());
LOG_DBG("WEBACT", "Starting web server...");
// Create the web server instance
webServer.reset(new CrossPointWebServer());
@@ -263,16 +263,16 @@ void CrossPointWebServerActivity::startWebServer() {
if (webServer->isRunning()) {
state = WebServerActivityState::SERVER_RUNNING;
Serial.printf("[%lu] [WEBACT] Web server started successfully\n", millis());
LOG_DBG("WEBACT", "Web server started successfully");
// Force an immediate render since we're transitioning from a subactivity
// that had its own rendering task. We need to make sure our display is shown.
xSemaphoreTake(renderingMutex, portMAX_DELAY);
render();
xSemaphoreGive(renderingMutex);
Serial.printf("[%lu] [WEBACT] Rendered File Transfer screen\n", millis());
LOG_DBG("WEBACT", "Rendered File Transfer screen");
} else {
Serial.printf("[%lu] [WEBACT] ERROR: Failed to start web server!\n", millis());
LOG_ERR("WEBACT", "ERROR: Failed to start web server!");
webServer.reset();
// Go back on error
onGoBack();
@@ -281,9 +281,9 @@ void CrossPointWebServerActivity::startWebServer() {
void CrossPointWebServerActivity::stopWebServer() {
if (webServer && webServer->isRunning()) {
Serial.printf("[%lu] [WEBACT] Stopping web server...\n", millis());
LOG_DBG("WEBACT", "Stopping web server...");
webServer->stop();
Serial.printf("[%lu] [WEBACT] Web server stopped\n", millis());
LOG_DBG("WEBACT", "Web server stopped");
}
webServer.reset();
}
@@ -309,7 +309,7 @@ void CrossPointWebServerActivity::loop() {
lastWifiCheck = millis();
const wl_status_t wifiStatus = WiFi.status();
if (wifiStatus != WL_CONNECTED) {
Serial.printf("[%lu] [WEBACT] WiFi disconnected! Status: %d\n", millis(), wifiStatus);
LOG_DBG("WEBACT", "WiFi disconnected! Status: %d", wifiStatus);
// Show error and exit gracefully
state = WebServerActivityState::SHUTTING_DOWN;
updateRequired = true;
@@ -318,7 +318,7 @@ void CrossPointWebServerActivity::loop() {
// Log weak signal warnings
const int rssi = WiFi.RSSI();
if (rssi < -75) {
Serial.printf("[%lu] [WEBACT] Warning: Weak WiFi signal: %d dBm\n", millis(), rssi);
LOG_DBG("WEBACT", "Warning: Weak WiFi signal: %d dBm", rssi);
}
}
}
@@ -329,8 +329,7 @@ void CrossPointWebServerActivity::loop() {
// Log if there's a significant gap between handleClient calls (>100ms)
if (lastHandleClientTime > 0 && timeSinceLastHandleClient > 100) {
Serial.printf("[%lu] [WEBACT] WARNING: %lu ms gap since last handleClient\n", millis(),
timeSinceLastHandleClient);
LOG_DBG("WEBACT", "WARNING: %lu ms gap since last handleClient", timeSinceLastHandleClient);
}
// Reset watchdog BEFORE processing - HTTP header parsing can be slow
@@ -401,7 +400,7 @@ void drawQRCode(const GfxRenderer& renderer, const int x, const int y, const std
// The structure to manage the QR code
QRCode qrcode;
uint8_t qrcodeBytes[qrcode_getBufferSize(4)];
Serial.printf("[%lu] [WEBACT] QR Code (%lu): %s\n", millis(), data.length(), data.c_str());
LOG_DBG("WEBACT", "QR Code (%lu): %s", data.length(), data.c_str());
qrcode_initText(&qrcode, qrcodeBytes, 4, ECC_LOW, data.c_str());
const uint8_t px = 6; // pixels per module

View File

@@ -1,6 +1,7 @@
#include "WifiSelectionActivity.h"
#include <GfxRenderer.h>
#include <Logging.h>
#include <WiFi.h>
#include <map>
@@ -62,7 +63,7 @@ void WifiSelectionActivity::onEnter() {
if (!lastSsid.empty()) {
const auto* cred = WIFI_STORE.findCredential(lastSsid);
if (cred) {
Serial.printf("[%lu] [WIFI] Attempting to auto-connect to %s\n", millis(), lastSsid.c_str());
LOG_DBG("WIFI", "Attempting to auto-connect to %s", lastSsid.c_str());
selectedSSID = cred->ssid;
enteredPassword = cred->password;
selectedRequiresPassword = !cred->password.empty();
@@ -82,12 +83,12 @@ void WifiSelectionActivity::onEnter() {
void WifiSelectionActivity::onExit() {
Activity::onExit();
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit start: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WIFI] [MEM", "Free heap at onExit start: %d bytes", ESP.getFreeHeap());
// Stop any ongoing WiFi scan
Serial.printf("[%lu] [WIFI] Deleting WiFi scan...\n", millis());
LOG_DBG("WIFI", "Deleting WiFi scan...");
WiFi.scanDelete();
Serial.printf("[%lu] [WIFI] [MEM] Free heap after scanDelete: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WIFI] [MEM", "Free heap after scanDelete: %d bytes", ESP.getFreeHeap());
// Note: We do NOT disconnect WiFi here - the parent activity
// (CrossPointWebServerActivity) manages WiFi connection state. We just clean
@@ -95,25 +96,25 @@ void WifiSelectionActivity::onExit() {
// Acquire mutex before deleting task to ensure task isn't using it
// This prevents hangs/crashes if the task holds the mutex when deleted
Serial.printf("[%lu] [WIFI] Acquiring rendering mutex before task deletion...\n", millis());
LOG_DBG("WIFI", "Acquiring rendering mutex before task deletion...");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
// Delete the display task (we now hold the mutex, so task is blocked if it
// needs it)
Serial.printf("[%lu] [WIFI] Deleting display task...\n", millis());
LOG_DBG("WIFI", "Deleting display task...");
if (displayTaskHandle) {
vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr;
Serial.printf("[%lu] [WIFI] Display task deleted\n", millis());
LOG_DBG("WIFI", "Display task deleted");
}
// Now safe to delete the mutex since we own it
Serial.printf("[%lu] [WIFI] Deleting mutex...\n", millis());
LOG_DBG("WIFI", "Deleting mutex...");
vSemaphoreDelete(renderingMutex);
renderingMutex = nullptr;
Serial.printf("[%lu] [WIFI] Mutex deleted\n", millis());
LOG_DBG("WIFI", "Mutex deleted");
Serial.printf("[%lu] [WIFI] [MEM] Free heap at onExit end: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WIFI] [MEM", "Free heap at onExit end: %d bytes", ESP.getFreeHeap());
}
void WifiSelectionActivity::startWifiScan() {
@@ -211,8 +212,7 @@ void WifiSelectionActivity::selectNetwork(const int index) {
// Use saved password - connect directly
enteredPassword = savedCred->password;
usedSavedPassword = true;
Serial.printf("[%lu] [WiFi] Using saved password for %s, length: %zu\n", millis(), selectedSSID.c_str(),
enteredPassword.size());
LOG_DBG("WiFi", "Using saved password for %s, length: %zu", selectedSSID.c_str(), enteredPassword.size());
attemptConnection();
return;
}
@@ -290,10 +290,9 @@ void WifiSelectionActivity::checkConnectionStatus() {
updateRequired = true;
} else {
// Using saved password or open network - complete immediately
Serial.printf(
"[%lu] [WIFI] Connected with saved/open credentials, "
"completing immediately\n",
millis());
LOG_DBG("WIFI",
"Connected with saved/open credentials, "
"completing immediately");
onComplete(true);
}
return;

View File

@@ -4,6 +4,7 @@
#include <FsHelpers.h>
#include <GfxRenderer.h>
#include <HalStorage.h>
#include <Logging.h>
#include "CrossPointSettings.h"
#include "CrossPointState.h"
@@ -88,7 +89,7 @@ void EpubReaderActivity::onEnter() {
currentSpineIndex = data[0] + (data[1] << 8);
nextPageNumber = data[2] + (data[3] << 8);
cachedSpineIndex = currentSpineIndex;
Serial.printf("[%lu] [ERS] Loaded cache: %d, %d\n", millis(), currentSpineIndex, nextPageNumber);
LOG_DBG("ERS", "Loaded cache: %d, %d", currentSpineIndex, nextPageNumber);
}
if (dataSize == 6) {
cachedChapterTotalPageCount = data[4] + (data[5] << 8);
@@ -101,8 +102,7 @@ void EpubReaderActivity::onEnter() {
int textSpineIndex = epub->getSpineIndexForTextReference();
if (textSpineIndex != 0) {
currentSpineIndex = textSpineIndex;
Serial.printf("[%lu] [ERS] Opened for first time, navigating to text reference at index %d\n", millis(),
textSpineIndex);
LOG_DBG("ERS", "Opened for first time, navigating to text reference at index %d", textSpineIndex);
}
}
@@ -867,7 +867,7 @@ void EpubReaderActivity::renderScreen() {
if (!section) {
const auto filepath = epub->getSpineItem(currentSpineIndex).href;
Serial.printf("[%lu] [ERS] Loading file: %s, index: %d\n", millis(), filepath.c_str(), currentSpineIndex);
LOG_DBG("ERS", "Loading file: %s, index: %d", filepath.c_str(), currentSpineIndex);
section = std::unique_ptr<Section>(new Section(epub, currentSpineIndex, renderer));
const uint16_t viewportWidth = renderer.getScreenWidth() - orientedMarginLeft - orientedMarginRight;
@@ -876,19 +876,19 @@ void EpubReaderActivity::renderScreen() {
if (!section->loadSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle)) {
Serial.printf("[%lu] [ERS] Cache not found, building...\n", millis());
LOG_DBG("ERS", "Cache not found, building...");
const auto popupFn = [this]() { GUI.drawPopup(renderer, "Indexing..."); };
if (!section->createSectionFile(SETTINGS.getReaderFontId(), SETTINGS.getReaderLineCompression(),
SETTINGS.extraParagraphSpacing, SETTINGS.paragraphAlignment, viewportWidth,
viewportHeight, SETTINGS.hyphenationEnabled, SETTINGS.embeddedStyle, popupFn)) {
Serial.printf("[%lu] [ERS] Failed to persist page data to SD\n", millis());
LOG_ERR("ERS", "Failed to persist page data to SD");
section.reset();
return;
}
} else {
Serial.printf("[%lu] [ERS] Cache found, skipping build...\n", millis());
LOG_DBG("ERS", "Cache found, skipping build...");
}
if (nextPageNumber == UINT16_MAX) {
@@ -922,7 +922,7 @@ void EpubReaderActivity::renderScreen() {
renderer.clearScreen();
if (section->pageCount == 0) {
Serial.printf("[%lu] [ERS] No pages to render\n", millis());
LOG_DBG("ERS", "No pages to render");
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Empty chapter", true, EpdFontFamily::BOLD);
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
renderer.displayBuffer();
@@ -930,7 +930,7 @@ void EpubReaderActivity::renderScreen() {
}
if (section->currentPage < 0 || section->currentPage >= section->pageCount) {
Serial.printf("[%lu] [ERS] Page out of bounds: %d (max %d)\n", millis(), section->currentPage, section->pageCount);
LOG_DBG("ERS", "Page out of bounds: %d (max %d)", section->currentPage, section->pageCount);
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Out of bounds", true, EpdFontFamily::BOLD);
renderStatusBar(orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
renderer.displayBuffer();
@@ -940,14 +940,14 @@ void EpubReaderActivity::renderScreen() {
{
auto p = section->loadPageFromSectionFile();
if (!p) {
Serial.printf("[%lu] [ERS] Failed to load page from SD - clearing section cache\n", millis());
LOG_ERR("ERS", "Failed to load page from SD - clearing section cache");
section->clearCache();
section.reset();
return renderScreen();
}
const auto start = millis();
renderContents(std::move(p), orientedMarginTop, orientedMarginRight, orientedMarginBottom, orientedMarginLeft);
Serial.printf("[%lu] [ERS] Rendered page in %dms\n", millis(), millis() - start);
LOG_DBG("ERS", "Rendered page in %dms", millis() - start);
}
saveProgress(currentSpineIndex, section->currentPage, section->pageCount);
}
@@ -964,9 +964,9 @@ void EpubReaderActivity::saveProgress(int spineIndex, int currentPage, int pageC
data[5] = (pageCount >> 8) & 0xFF;
f.write(data, 6);
f.close();
Serial.printf("[%lu] [ERS] Progress saved: Chapter %d, Page %d\n", millis(), spineIndex, currentPage);
LOG_DBG("ERS", "Progress saved: Chapter %d, Page %d", spineIndex, currentPage);
} else {
Serial.printf("[%lu] [ERS] Could not save progress!\n", millis());
LOG_ERR("ERS", "Could not save progress!");
}
}
void EpubReaderActivity::renderContents(std::unique_ptr<Page> page, const int orientedMarginTop,

View File

@@ -1,6 +1,7 @@
#include "KOReaderSyncActivity.h"
#include <GfxRenderer.h>
#include <Logging.h>
#include <WiFi.h>
#include <esp_sntp.h>
@@ -32,9 +33,9 @@ void syncTimeWithNTP() {
}
if (retry < maxRetries) {
Serial.printf("[%lu] [KOSync] NTP time synced\n", millis());
LOG_DBG("KOSync", "NTP time synced");
} else {
Serial.printf("[%lu] [KOSync] NTP sync timeout, using fallback\n", millis());
LOG_DBG("KOSync", "NTP sync timeout, using fallback");
}
}
} // namespace
@@ -48,12 +49,12 @@ void KOReaderSyncActivity::onWifiSelectionComplete(const bool success) {
exitActivity();
if (!success) {
Serial.printf("[%lu] [KOSync] WiFi connection failed, exiting\n", millis());
LOG_DBG("KOSync", "WiFi connection failed, exiting");
onCancel();
return;
}
Serial.printf("[%lu] [KOSync] WiFi connected, starting sync\n", millis());
LOG_DBG("KOSync", "WiFi connected, starting sync");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = SYNCING;
@@ -88,7 +89,7 @@ void KOReaderSyncActivity::performSync() {
return;
}
Serial.printf("[%lu] [KOSync] Document hash: %s\n", millis(), documentHash.c_str());
LOG_DBG("KOSync", "Document hash: %s", documentHash.c_str());
xSemaphoreTake(renderingMutex, portMAX_DELAY);
statusMessage = "Fetching remote progress...";
@@ -188,12 +189,12 @@ void KOReaderSyncActivity::onEnter() {
}
// Turn on WiFi
Serial.printf("[%lu] [KOSync] Turning on WiFi...\n", millis());
LOG_DBG("KOSync", "Turning on WiFi...");
WiFi.mode(WIFI_STA);
// Check if already connected
if (WiFi.status() == WL_CONNECTED) {
Serial.printf("[%lu] [KOSync] Already connected to WiFi\n", millis());
LOG_DBG("KOSync", "Already connected to WiFi");
state = SYNCING;
statusMessage = "Syncing time...";
updateRequired = true;
@@ -216,7 +217,7 @@ void KOReaderSyncActivity::onEnter() {
}
// Launch WiFi selection subactivity
Serial.printf("[%lu] [KOSync] Launching WifiSelectionActivity...\n", millis());
LOG_DBG("KOSync", "Launching WifiSelectionActivity...");
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
[this](const bool connected) { onWifiSelectionComplete(connected); }));
}

View File

@@ -30,7 +30,7 @@ bool ReaderActivity::isTxtFile(const std::string& path) {
std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
if (!Storage.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
LOG_ERR("READER", "File does not exist: %s", path.c_str());
return nullptr;
}
@@ -39,13 +39,13 @@ std::unique_ptr<Epub> ReaderActivity::loadEpub(const std::string& path) {
return epub;
}
Serial.printf("[%lu] [ ] Failed to load epub\n", millis());
LOG_ERR("READER", "Failed to load epub");
return nullptr;
}
std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
if (!Storage.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
LOG_ERR("READER", "File does not exist: %s", path.c_str());
return nullptr;
}
@@ -54,13 +54,13 @@ std::unique_ptr<Xtc> ReaderActivity::loadXtc(const std::string& path) {
return xtc;
}
Serial.printf("[%lu] [ ] Failed to load XTC\n", millis());
LOG_ERR("READER", "Failed to load XTC");
return nullptr;
}
std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
if (!Storage.exists(path.c_str())) {
Serial.printf("[%lu] [ ] File does not exist: %s\n", millis(), path.c_str());
LOG_ERR("READER", "File does not exist: %s", path.c_str());
return nullptr;
}
@@ -69,7 +69,7 @@ std::unique_ptr<Txt> ReaderActivity::loadTxt(const std::string& path) {
return txt;
}
Serial.printf("[%lu] [ ] Failed to load TXT\n", millis());
LOG_ERR("READER", "Failed to load TXT");
return nullptr;
}

View File

@@ -200,8 +200,7 @@ void TxtReaderActivity::initializeReader() {
linesPerPage = viewportHeight / lineHeight;
if (linesPerPage < 1) linesPerPage = 1;
Serial.printf("[%lu] [TRS] Viewport: %dx%d, lines per page: %d\n", millis(), viewportWidth, viewportHeight,
linesPerPage);
LOG_DBG("TRS", "Viewport: %dx%d, lines per page: %d", viewportWidth, viewportHeight, linesPerPage);
// Try to load cached page index first
if (!loadPageIndexCache()) {
@@ -224,7 +223,7 @@ void TxtReaderActivity::buildPageIndex() {
size_t offset = 0;
const size_t fileSize = txt->getFileSize();
Serial.printf("[%lu] [TRS] Building page index for %zu bytes...\n", millis(), fileSize);
LOG_DBG("TRS", "Building page index for %zu bytes...", fileSize);
GUI.drawPopup(renderer, "Indexing...");
@@ -253,7 +252,7 @@ void TxtReaderActivity::buildPageIndex() {
}
totalPages = pageOffsets.size();
Serial.printf("[%lu] [TRS] Built page index: %d pages\n", millis(), totalPages);
LOG_DBG("TRS", "Built page index: %d pages", totalPages);
}
bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>& outLines, size_t& nextOffset) {
@@ -268,7 +267,7 @@ bool TxtReaderActivity::loadPageAtOffset(size_t offset, std::vector<std::string>
size_t chunkSize = std::min(CHUNK_SIZE, fileSize - offset);
auto* buffer = static_cast<uint8_t*>(malloc(chunkSize + 1));
if (!buffer) {
Serial.printf("[%lu] [TRS] Failed to allocate %zu bytes\n", millis(), chunkSize);
LOG_ERR("TRS", "Failed to allocate %zu bytes", chunkSize);
return false;
}
@@ -597,7 +596,7 @@ void TxtReaderActivity::loadProgress() {
if (currentPage < 0) {
currentPage = 0;
}
Serial.printf("[%lu] [TRS] Loaded progress: page %d/%d\n", millis(), currentPage, totalPages);
LOG_DBG("TRS", "Loaded progress: page %d/%d", currentPage, totalPages);
}
f.close();
}
@@ -619,7 +618,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
std::string cachePath = txt->getCachePath() + "/index.bin";
FsFile f;
if (!Storage.openFileForRead("TRS", cachePath, f)) {
Serial.printf("[%lu] [TRS] No page index cache found\n", millis());
LOG_DBG("TRS", "No page index cache found");
return false;
}
@@ -627,7 +626,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
uint32_t magic;
serialization::readPod(f, magic);
if (magic != CACHE_MAGIC) {
Serial.printf("[%lu] [TRS] Cache magic mismatch, rebuilding\n", millis());
LOG_DBG("TRS", "Cache magic mismatch, rebuilding");
f.close();
return false;
}
@@ -635,7 +634,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
uint8_t version;
serialization::readPod(f, version);
if (version != CACHE_VERSION) {
Serial.printf("[%lu] [TRS] Cache version mismatch (%d != %d), rebuilding\n", millis(), version, CACHE_VERSION);
LOG_DBG("TRS", "Cache version mismatch (%d != %d), rebuilding", version, CACHE_VERSION);
f.close();
return false;
}
@@ -643,7 +642,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
uint32_t fileSize;
serialization::readPod(f, fileSize);
if (fileSize != txt->getFileSize()) {
Serial.printf("[%lu] [TRS] Cache file size mismatch, rebuilding\n", millis());
LOG_DBG("TRS", "Cache file size mismatch, rebuilding");
f.close();
return false;
}
@@ -651,7 +650,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
int32_t cachedWidth;
serialization::readPod(f, cachedWidth);
if (cachedWidth != viewportWidth) {
Serial.printf("[%lu] [TRS] Cache viewport width mismatch, rebuilding\n", millis());
LOG_DBG("TRS", "Cache viewport width mismatch, rebuilding");
f.close();
return false;
}
@@ -659,7 +658,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
int32_t cachedLines;
serialization::readPod(f, cachedLines);
if (cachedLines != linesPerPage) {
Serial.printf("[%lu] [TRS] Cache lines per page mismatch, rebuilding\n", millis());
LOG_DBG("TRS", "Cache lines per page mismatch, rebuilding");
f.close();
return false;
}
@@ -667,7 +666,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
int32_t fontId;
serialization::readPod(f, fontId);
if (fontId != cachedFontId) {
Serial.printf("[%lu] [TRS] Cache font ID mismatch (%d != %d), rebuilding\n", millis(), fontId, cachedFontId);
LOG_DBG("TRS", "Cache font ID mismatch (%d != %d), rebuilding", fontId, cachedFontId);
f.close();
return false;
}
@@ -675,7 +674,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
int32_t margin;
serialization::readPod(f, margin);
if (margin != cachedScreenMargin) {
Serial.printf("[%lu] [TRS] Cache screen margin mismatch, rebuilding\n", millis());
LOG_DBG("TRS", "Cache screen margin mismatch, rebuilding");
f.close();
return false;
}
@@ -683,7 +682,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
uint8_t alignment;
serialization::readPod(f, alignment);
if (alignment != cachedParagraphAlignment) {
Serial.printf("[%lu] [TRS] Cache paragraph alignment mismatch, rebuilding\n", millis());
LOG_DBG("TRS", "Cache paragraph alignment mismatch, rebuilding");
f.close();
return false;
}
@@ -703,7 +702,7 @@ bool TxtReaderActivity::loadPageIndexCache() {
f.close();
totalPages = pageOffsets.size();
Serial.printf("[%lu] [TRS] Loaded page index cache: %d pages\n", millis(), totalPages);
LOG_DBG("TRS", "Loaded page index cache: %d pages", totalPages);
return true;
}
@@ -711,7 +710,7 @@ void TxtReaderActivity::savePageIndexCache() const {
std::string cachePath = txt->getCachePath() + "/index.bin";
FsFile f;
if (!Storage.openFileForWrite("TRS", cachePath, f)) {
Serial.printf("[%lu] [TRS] Failed to save page index cache\n", millis());
LOG_ERR("TRS", "Failed to save page index cache");
return;
}
@@ -732,5 +731,5 @@ void TxtReaderActivity::savePageIndexCache() const {
}
f.close();
Serial.printf("[%lu] [TRS] Saved page index cache: %d pages\n", millis(), totalPages);
LOG_DBG("TRS", "Saved page index cache: %d pages", totalPages);
}

View File

@@ -237,7 +237,7 @@ void XtcReaderActivity::renderPage() {
// Allocate page buffer
uint8_t* pageBuffer = static_cast<uint8_t*>(malloc(pageBufferSize));
if (!pageBuffer) {
Serial.printf("[%lu] [XTR] Failed to allocate page buffer (%lu bytes)\n", millis(), pageBufferSize);
LOG_ERR("XTR", "Failed to allocate page buffer (%lu bytes)", pageBufferSize);
renderer.clearScreen();
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Memory error", true, EpdFontFamily::BOLD);
renderer.displayBuffer();
@@ -247,7 +247,7 @@ void XtcReaderActivity::renderPage() {
// Load page data
size_t bytesRead = xtc->loadPage(currentPage, pageBuffer, pageBufferSize);
if (bytesRead == 0) {
Serial.printf("[%lu] [XTR] Failed to load page %lu\n", millis(), currentPage);
LOG_ERR("XTR", "Failed to load page %lu", currentPage);
free(pageBuffer);
renderer.clearScreen();
renderer.drawCenteredText(UI_12_FONT_ID, 300, "Page load error", true, EpdFontFamily::BOLD);
@@ -296,8 +296,8 @@ void XtcReaderActivity::renderPage() {
pixelCounts[getPixelValue(x, y)]++;
}
}
Serial.printf("[%lu] [XTR] Pixel distribution: White=%lu, DarkGrey=%lu, LightGrey=%lu, Black=%lu\n", millis(),
pixelCounts[0], pixelCounts[1], pixelCounts[2], pixelCounts[3]);
LOG_DBG("XTR", "Pixel distribution: White=%lu, DarkGrey=%lu, LightGrey=%lu, Black=%lu", pixelCounts[0],
pixelCounts[1], pixelCounts[2], pixelCounts[3]);
// Pass 1: BW buffer - draw all non-white pixels as black
for (uint16_t y = 0; y < pageHeight; y++) {
@@ -360,8 +360,7 @@ void XtcReaderActivity::renderPage() {
free(pageBuffer);
Serial.printf("[%lu] [XTR] Rendered page %lu/%lu (2-bit grayscale)\n", millis(), currentPage + 1,
xtc->getPageCount());
LOG_DBG("XTR", "Rendered page %lu/%lu (2-bit grayscale)", currentPage + 1, xtc->getPageCount());
return;
} else {
// 1-bit mode: 8 pixels per byte, MSB first
@@ -397,8 +396,7 @@ void XtcReaderActivity::renderPage() {
pagesUntilFullRefresh--;
}
Serial.printf("[%lu] [XTR] Rendered page %lu/%lu (%u-bit)\n", millis(), currentPage + 1, xtc->getPageCount(),
bitDepth);
LOG_DBG("XTR", "Rendered page %lu/%lu (%u-bit)", currentPage + 1, xtc->getPageCount(), bitDepth);
}
void XtcReaderActivity::saveProgress() const {
@@ -420,7 +418,7 @@ void XtcReaderActivity::loadProgress() {
uint8_t data[4];
if (f.read(data, 4) == 4) {
currentPage = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
Serial.printf("[%lu] [XTR] Loaded progress: page %lu\n", millis(), currentPage);
LOG_DBG("XTR", "Loaded progress: page %lu", currentPage);
// Validate page number
if (currentPage >= xtc->getPageCount()) {

View File

@@ -2,7 +2,7 @@
#include <GfxRenderer.h>
#include <HalStorage.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include "MappedInputManager.h"
#include "components/UITheme.h"
@@ -104,12 +104,12 @@ void ClearCacheActivity::render() {
}
void ClearCacheActivity::clearCache() {
Serial.printf("[%lu] [CLEAR_CACHE] Clearing cache...\n", millis());
LOG_DBG("CLEAR_CACHE", "Clearing cache...");
// Open .crosspoint directory
auto root = Storage.open("/.crosspoint");
if (!root || !root.isDirectory()) {
Serial.printf("[%lu] [CLEAR_CACHE] Failed to open cache directory\n", millis());
LOG_DBG("CLEAR_CACHE", "Failed to open cache directory");
if (root) root.close();
state = FAILED;
updateRequired = true;
@@ -128,14 +128,14 @@ void ClearCacheActivity::clearCache() {
// Only delete directories starting with epub_ or xtc_
if (file.isDirectory() && (itemName.startsWith("epub_") || itemName.startsWith("xtc_"))) {
String fullPath = "/.crosspoint/" + itemName;
Serial.printf("[%lu] [CLEAR_CACHE] Removing cache: %s\n", millis(), fullPath.c_str());
LOG_DBG("CLEAR_CACHE", "Removing cache: %s", fullPath.c_str());
file.close(); // Close before attempting to delete
if (Storage.removeDir(fullPath.c_str())) {
clearedCount++;
} else {
Serial.printf("[%lu] [CLEAR_CACHE] Failed to remove: %s\n", millis(), fullPath.c_str());
LOG_ERR("CLEAR_CACHE", "Failed to remove: %s", fullPath.c_str());
failedCount++;
}
} else {
@@ -144,7 +144,7 @@ void ClearCacheActivity::clearCache() {
}
root.close();
Serial.printf("[%lu] [CLEAR_CACHE] Cache cleared: %d removed, %d failed\n", millis(), clearedCount, failedCount);
LOG_DBG("CLEAR_CACHE", "Cache cleared: %d removed, %d failed", clearedCount, failedCount);
state = SUCCESS;
updateRequired = true;
@@ -153,7 +153,7 @@ void ClearCacheActivity::clearCache() {
void ClearCacheActivity::loop() {
if (state == WARNING) {
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
Serial.printf("[%lu] [CLEAR_CACHE] User confirmed, starting cache clear\n", millis());
LOG_DBG("CLEAR_CACHE", "User confirmed, starting cache clear");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = CLEARING;
xSemaphoreGive(renderingMutex);
@@ -164,7 +164,7 @@ void ClearCacheActivity::loop() {
}
if (mappedInput.wasPressed(MappedInputManager::Button::Back)) {
Serial.printf("[%lu] [CLEAR_CACHE] User cancelled\n", millis());
LOG_DBG("CLEAR_CACHE", "User cancelled");
goBack();
}
return;

View File

@@ -18,12 +18,12 @@ void OtaUpdateActivity::onWifiSelectionComplete(const bool success) {
exitActivity();
if (!success) {
Serial.printf("[%lu] [OTA] WiFi connection failed, exiting\n", millis());
LOG_ERR("OTA", "WiFi connection failed, exiting");
goBack();
return;
}
Serial.printf("[%lu] [OTA] WiFi connected, checking for update\n", millis());
LOG_DBG("OTA", "WiFi connected, checking for update");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = CHECKING_FOR_UPDATE;
@@ -32,7 +32,7 @@ void OtaUpdateActivity::onWifiSelectionComplete(const bool success) {
vTaskDelay(10 / portTICK_PERIOD_MS);
const auto res = updater.checkForUpdate();
if (res != OtaUpdater::OK) {
Serial.printf("[%lu] [OTA] Update check failed: %d\n", millis(), res);
LOG_DBG("OTA", "Update check failed: %d", res);
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = FAILED;
xSemaphoreGive(renderingMutex);
@@ -41,7 +41,7 @@ void OtaUpdateActivity::onWifiSelectionComplete(const bool success) {
}
if (!updater.isUpdateNewer()) {
Serial.printf("[%lu] [OTA] No new update available\n", millis());
LOG_DBG("OTA", "No new update available");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = NO_UPDATE;
xSemaphoreGive(renderingMutex);
@@ -68,11 +68,11 @@ void OtaUpdateActivity::onEnter() {
);
// Turn on WiFi immediately
Serial.printf("[%lu] [OTA] Turning on WiFi...\n", millis());
LOG_DBG("OTA", "Turning on WiFi...");
WiFi.mode(WIFI_STA);
// Launch WiFi selection subactivity
Serial.printf("[%lu] [OTA] Launching WifiSelectionActivity...\n", millis());
LOG_DBG("OTA", "Launching WifiSelectionActivity...");
enterNewActivity(new WifiSelectionActivity(renderer, mappedInput,
[this](const bool connected) { onWifiSelectionComplete(connected); }));
}
@@ -116,8 +116,7 @@ void OtaUpdateActivity::render() {
float updaterProgress = 0;
if (state == UPDATE_IN_PROGRESS) {
Serial.printf("[%lu] [OTA] Update progress: %d / %d\n", millis(), updater.getProcessedSize(),
updater.getTotalSize());
LOG_DBG("OTA", "Update progress: %d / %d", updater.getProcessedSize(), updater.getTotalSize());
updaterProgress = static_cast<float>(updater.getProcessedSize()) / static_cast<float>(updater.getTotalSize());
// Only update every 2% at the most
if (static_cast<int>(updaterProgress * 50) == lastUpdaterPercentage / 2) {
@@ -190,7 +189,7 @@ void OtaUpdateActivity::loop() {
if (state == WAITING_CONFIRMATION) {
if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) {
Serial.printf("[%lu] [OTA] New update available, starting download...\n", millis());
LOG_DBG("OTA", "New update available, starting download...");
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = UPDATE_IN_PROGRESS;
xSemaphoreGive(renderingMutex);
@@ -199,7 +198,7 @@ void OtaUpdateActivity::loop() {
const auto res = updater.installUpdate();
if (res != OtaUpdater::OK) {
Serial.printf("[%lu] [OTA] Update failed: %d\n", millis(), res);
LOG_DBG("OTA", "Update failed: %d", res);
xSemaphoreTake(renderingMutex, portMAX_DELAY);
state = FAILED;
xSemaphoreGive(renderingMutex);

View File

@@ -1,7 +1,7 @@
#include "SettingsActivity.h"
#include <GfxRenderer.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include "ButtonRemapActivity.h"
#include "CalibreSettingsActivity.h"