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,7 +1,7 @@
#include "CrossPointSettings.h"
#include <HalStorage.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <Serialization.h>
#include <cstring>
@@ -122,7 +122,7 @@ bool CrossPointSettings::saveToFile() const {
// New fields added at end for backward compatibility
outputFile.close();
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
LOG_DBG("CPS", "Settings saved to file");
return true;
}
@@ -135,7 +135,7 @@ bool CrossPointSettings::loadFromFile() {
uint8_t version;
serialization::readPod(inputFile, version);
if (version != SETTINGS_FILE_VERSION) {
Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version);
LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version);
inputFile.close();
return false;
}
@@ -238,7 +238,7 @@ bool CrossPointSettings::loadFromFile() {
}
inputFile.close();
Serial.printf("[%lu] [CPS] Settings loaded from file\n", millis());
LOG_DBG("CPS", "Settings loaded from file");
return true;
}

View File

@@ -1,7 +1,7 @@
#include "CrossPointState.h"
#include <HalStorage.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <Serialization.h>
namespace {
@@ -35,7 +35,7 @@ bool CrossPointState::loadFromFile() {
uint8_t version;
serialization::readPod(inputFile, version);
if (version > STATE_FILE_VERSION) {
Serial.printf("[%lu] [CPS] Deserialization failed: Unknown version %u\n", millis(), version);
LOG_ERR("CPS", "Deserialization failed: Unknown version %u", version);
inputFile.close();
return false;
}

View File

@@ -2,7 +2,7 @@
#include <Epub.h>
#include <HalStorage.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <Serialization.h>
#include <Xtc.h>
@@ -72,7 +72,7 @@ bool RecentBooksStore::saveToFile() const {
}
outputFile.close();
Serial.printf("[%lu] [RBS] Recent books saved to file (%d entries)\n", millis(), count);
LOG_DBG("RBS", "Recent books saved to file (%d entries)", count);
return true;
}
@@ -83,7 +83,7 @@ RecentBook RecentBooksStore::getDataFromBook(std::string path) const {
lastBookFileName = path.substr(lastSlash + 1);
}
Serial.printf("[%lu] [RBS] Loading recent book: %s\n", millis(), path.c_str());
LOG_DBG("RBS", "Loading recent book: %s", path.c_str());
// If epub, try to load the metadata for title/author and cover
if (StringUtils::checkFileExtension(lastBookFileName, ".epub")) {
@@ -136,7 +136,7 @@ bool RecentBooksStore::loadFromFile() {
}
}
} else {
Serial.printf("[%lu] [RBS] Deserialization failed: Unknown version %u\n", millis(), version);
LOG_ERR("RBS", "Deserialization failed: Unknown version %u", version);
inputFile.close();
return false;
}
@@ -158,6 +158,6 @@ bool RecentBooksStore::loadFromFile() {
}
inputFile.close();
Serial.printf("[%lu] [RBS] Recent books loaded from file (%d entries)\n", millis(), recentBooks.size());
LOG_DBG("RBS", "Recent books loaded from file (%d entries)", recentBooks.size());
return true;
}

View File

@@ -1,7 +1,7 @@
#include "WifiCredentialStore.h"
#include <HalStorage.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <Serialization.h>
// Initialize the static instance
@@ -21,7 +21,7 @@ constexpr size_t KEY_LENGTH = sizeof(OBFUSCATION_KEY);
} // namespace
void WifiCredentialStore::obfuscate(std::string& data) const {
Serial.printf("[%lu] [WCS] Obfuscating/deobfuscating %zu bytes\n", millis(), data.size());
LOG_DBG("WCS", "Obfuscating/deobfuscating %zu bytes", data.size());
for (size_t i = 0; i < data.size(); i++) {
data[i] ^= OBFUSCATION_KEY[i % KEY_LENGTH];
}
@@ -45,8 +45,7 @@ bool WifiCredentialStore::saveToFile() const {
for (const auto& cred : credentials) {
// Write SSID (plaintext - not sensitive)
serialization::writeString(file, cred.ssid);
Serial.printf("[%lu] [WCS] Saving SSID: %s, password length: %zu\n", millis(), cred.ssid.c_str(),
cred.password.size());
LOG_DBG("WCS", "Saving SSID: %s, password length: %zu", cred.ssid.c_str(), cred.password.size());
// Write password (obfuscated)
std::string obfuscatedPwd = cred.password;
@@ -55,7 +54,7 @@ bool WifiCredentialStore::saveToFile() const {
}
file.close();
Serial.printf("[%lu] [WCS] Saved %zu WiFi credentials to file\n", millis(), credentials.size());
LOG_DBG("WCS", "Saved %zu WiFi credentials to file", credentials.size());
return true;
}
@@ -69,7 +68,7 @@ bool WifiCredentialStore::loadFromFile() {
uint8_t version;
serialization::readPod(file, version);
if (version > WIFI_FILE_VERSION) {
Serial.printf("[%lu] [WCS] Unknown file version: %u\n", millis(), version);
LOG_DBG("WCS", "Unknown file version: %u", version);
file.close();
return false;
}
@@ -94,16 +93,15 @@ bool WifiCredentialStore::loadFromFile() {
// Read and deobfuscate password
serialization::readString(file, cred.password);
Serial.printf("[%lu] [WCS] Loaded SSID: %s, obfuscated password length: %zu\n", millis(), cred.ssid.c_str(),
cred.password.size());
LOG_DBG("WCS", "Loaded SSID: %s, obfuscated password length: %zu", cred.ssid.c_str(), cred.password.size());
obfuscate(cred.password); // XOR is symmetric, so same function deobfuscates
Serial.printf("[%lu] [WCS] After deobfuscation, password length: %zu\n", millis(), cred.password.size());
LOG_DBG("WCS", "After deobfuscation, password length: %zu", cred.password.size());
credentials.push_back(cred);
}
file.close();
Serial.printf("[%lu] [WCS] Loaded %zu WiFi credentials from file\n", millis(), credentials.size());
LOG_DBG("WCS", "Loaded %zu WiFi credentials from file", credentials.size());
return true;
}
@@ -113,19 +111,19 @@ bool WifiCredentialStore::addCredential(const std::string& ssid, const std::stri
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) {
cred->password = password;
Serial.printf("[%lu] [WCS] Updated credentials for: %s\n", millis(), ssid.c_str());
LOG_DBG("WCS", "Updated credentials for: %s", ssid.c_str());
return saveToFile();
}
// Check if we've reached the limit
if (credentials.size() >= MAX_NETWORKS) {
Serial.printf("[%lu] [WCS] Cannot add more networks, limit of %zu reached\n", millis(), MAX_NETWORKS);
LOG_DBG("WCS", "Cannot add more networks, limit of %zu reached", MAX_NETWORKS);
return false;
}
// Add new credential
credentials.push_back({ssid, password});
Serial.printf("[%lu] [WCS] Added credentials for: %s\n", millis(), ssid.c_str());
LOG_DBG("WCS", "Added credentials for: %s", ssid.c_str());
return saveToFile();
}
@@ -134,7 +132,7 @@ bool WifiCredentialStore::removeCredential(const std::string& ssid) {
[&ssid](const WifiCredential& cred) { return cred.ssid == ssid; });
if (cred != credentials.end()) {
credentials.erase(cred);
Serial.printf("[%lu] [WCS] Removed credentials for: %s\n", millis(), ssid.c_str());
LOG_DBG("WCS", "Removed credentials for: %s", ssid.c_str());
if (ssid == lastConnectedSsid) {
clearLastConnectedSsid();
}
@@ -176,5 +174,5 @@ void WifiCredentialStore::clearAll() {
credentials.clear();
lastConnectedSsid.clear();
saveToFile();
Serial.printf("[%lu] [WCS] Cleared all WiFi credentials\n", millis());
LOG_DBG("WCS", "Cleared all WiFi credentials");
}

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"

View File

@@ -1,6 +1,7 @@
#include "UITheme.h"
#include <GfxRenderer.h>
#include <Logging.h>
#include <memory>
@@ -23,12 +24,12 @@ void UITheme::reload() {
void UITheme::setTheme(CrossPointSettings::UI_THEME type) {
switch (type) {
case CrossPointSettings::UI_THEME::CLASSIC:
Serial.printf("[%lu] [UI] Using Classic theme\n", millis());
LOG_DBG("UI", "Using Classic theme");
currentTheme = new BaseTheme();
currentMetrics = &BaseMetrics::values;
break;
case CrossPointSettings::UI_THEME::LYRA:
Serial.printf("[%lu] [UI] Using Lyra theme\n", millis());
LOG_DBG("UI", "Using Lyra theme");
currentTheme = new LyraTheme();
currentMetrics = &LyraMetrics::values;
break;

View File

@@ -2,6 +2,7 @@
#include <GfxRenderer.h>
#include <HalStorage.h>
#include <Logging.h>
#include <Utf8.h>
#include <cstdint>
@@ -311,7 +312,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
if (Storage.openFileForRead("HOME", coverBmpPath, file)) {
Bitmap bitmap(file);
if (bitmap.parseHeaders() == BmpReaderError::Ok) {
Serial.printf("Rendering bmp\n");
LOG_DBG("THEME", "Rendering bmp");
// Calculate position to center image within the book card
int coverX, coverY;
@@ -345,7 +346,7 @@ void BaseTheme::drawRecentBookCover(GfxRenderer& renderer, Rect rect, const std:
// First render: if selected, draw selection indicators now
if (bookSelected) {
Serial.printf("Drawing selection\n");
LOG_DBG("THEME", "Drawing selection");
renderer.drawRect(bookX + 1, bookY + 1, bookWidth - 2, bookHeight - 2);
renderer.drawRect(bookX + 2, bookY + 2, bookWidth - 4, bookHeight - 4);
}

View File

@@ -5,6 +5,7 @@
#include <HalGPIO.h>
#include <HalPowerManager.h>
#include <HalStorage.h>
#include <Logging.h>
#include <SPI.h>
#include <builtinFonts/all.h>
@@ -203,8 +204,8 @@ void enterDeepSleep() {
enterNewActivity(new SleepActivity(renderer, mappedInputManager));
display.deepSleep();
Serial.printf("[%lu] [ ] Power button press calibration value: %lu ms\n", millis(), t2 - t1);
Serial.printf("[%lu] [ ] Entering deep sleep.\n", millis());
LOG_DBG("MAIN", "Power button press calibration value: %lu ms", t2 - t1);
LOG_DBG("MAIN", "Entering deep sleep");
powerManager.startDeepSleep(gpio);
}
@@ -257,7 +258,7 @@ void onGoHome() {
void setupDisplayAndFonts() {
display.begin();
renderer.begin();
Serial.printf("[%lu] [ ] Display initialized\n", millis());
LOG_DBG("MAIN", "Display initialized");
renderer.insertFont(BOOKERLY_14_FONT_ID, bookerly14FontFamily);
#ifndef OMIT_FONTS
renderer.insertFont(BOOKERLY_12_FONT_ID, bookerly12FontFamily);
@@ -276,7 +277,7 @@ void setupDisplayAndFonts() {
renderer.insertFont(UI_10_FONT_ID, ui10FontFamily);
renderer.insertFont(UI_12_FONT_ID, ui12FontFamily);
renderer.insertFont(SMALL_FONT_ID, smallFontFamily);
Serial.printf("[%lu] [ ] Fonts setup\n", millis());
LOG_DBG("MAIN", "Fonts setup");
}
void setup() {
@@ -298,7 +299,7 @@ void setup() {
// SD Card Initialization
// We need 6 open files concurrently when parsing a new chapter
if (!Storage.begin()) {
Serial.printf("[%lu] [ ] SD card initialization failed\n", millis());
LOG_ERR("MAIN", "SD card initialization failed");
setupDisplayAndFonts();
exitActivity();
enterNewActivity(new FullScreenMessageActivity(renderer, mappedInputManager, "SD card error", EpdFontFamily::BOLD));
@@ -313,12 +314,12 @@ void setup() {
switch (gpio.getWakeupReason()) {
case HalGPIO::WakeupReason::PowerButton:
// For normal wakeups, verify power button press duration
Serial.printf("[%lu] [ ] Verifying power button press duration\n", millis());
LOG_DBG("MAIN", "Verifying power button press duration");
verifyPowerButtonDuration();
break;
case HalGPIO::WakeupReason::AfterUSBPower:
// If USB power caused a cold boot, go back to sleep
Serial.printf("[%lu] [ ] Wakeup reason: After USB Power\n", millis());
LOG_DBG("MAIN", "Wakeup reason: After USB Power");
powerManager.startDeepSleep(gpio);
break;
case HalGPIO::WakeupReason::AfterFlash:
@@ -329,7 +330,7 @@ void setup() {
}
// First serial output only here to avoid timing inconsistencies for power button press duration verification
Serial.printf("[%lu] [ ] Starting CrossPoint version " CROSSPOINT_VERSION "\n", millis());
LOG_DBG("MAIN", "Starting CrossPoint version " CROSSPOINT_VERSION);
setupDisplayAndFonts();
@@ -367,11 +368,27 @@ void loop() {
renderer.setFadingFix(SETTINGS.fadingFix);
if (Serial && millis() - lastMemPrint >= 10000) {
Serial.printf("[%lu] [MEM] Free: %d bytes, Total: %d bytes, Min Free: %d bytes\n", millis(), ESP.getFreeHeap(),
ESP.getHeapSize(), ESP.getMinFreeHeap());
LOG_INF("MEM", "Free: %d bytes, Total: %d bytes, Min Free: %d bytes", ESP.getFreeHeap(), ESP.getHeapSize(),
ESP.getMinFreeHeap());
lastMemPrint = millis();
}
// Handle incoming serial commands,
// nb: we use logSerial from logging to avoid deprecation warnings
if (logSerial.available() > 0) {
String line = logSerial.readStringUntil('\n');
if (line.startsWith("CMD:")) {
String cmd = line.substring(4);
cmd.trim();
if (cmd == "SCREENSHOT") {
logSerial.printf("SCREENSHOT_START:%d\n", HalDisplay::BUFFER_SIZE);
uint8_t* buf = display.getFrameBuffer();
logSerial.write(buf, HalDisplay::BUFFER_SIZE);
logSerial.printf("SCREENSHOT_END\n");
}
}
}
// Check for any user activity (button press or release) or active background work
static unsigned long lastActivityTime = millis();
if (gpio.wasAnyPressed() || gpio.wasAnyReleased() || (currentActivity && currentActivity->preventAutoSleep())) {
@@ -381,7 +398,7 @@ void loop() {
const unsigned long sleepTimeoutMs = SETTINGS.getSleepTimeoutMs();
if (millis() - lastActivityTime >= sleepTimeoutMs) {
Serial.printf("[%lu] [SLP] Auto-sleep triggered after %lu ms of inactivity\n", millis(), sleepTimeoutMs);
LOG_DBG("SLP", "Auto-sleep triggered after %lu ms of inactivity", sleepTimeoutMs);
enterDeepSleep();
// This should never be hit as `enterDeepSleep` calls esp_deep_sleep_start
return;
@@ -403,8 +420,7 @@ void loop() {
if (loopDuration > maxLoopDuration) {
maxLoopDuration = loopDuration;
if (maxLoopDuration > 50) {
Serial.printf("[%lu] [LOOP] New max loop duration: %lu ms (activity: %lu ms)\n", millis(), maxLoopDuration,
activityDuration);
LOG_DBG("LOOP", "New max loop duration: %lu ms (activity: %lu ms)", maxLoopDuration, activityDuration);
}
}

View File

@@ -4,6 +4,7 @@
#include <Epub.h>
#include <FsHelpers.h>
#include <HalStorage.h>
#include <Logging.h>
#include <WiFi.h>
#include <esp_task_wdt.h>
@@ -44,7 +45,7 @@ void clearEpubCacheIfNeeded(const String& filePath) {
// Only clear cache for .epub files
if (StringUtils::checkFileExtension(filePath, ".epub")) {
Epub(filePath.c_str(), "/.crosspoint").clearCache();
Serial.printf("[%lu] [WEB] Cleared epub cache for: %s\n", millis(), filePath.c_str());
LOG_DBG("WEB", "Cleared epub cache for: %s", filePath.c_str());
}
}
@@ -89,7 +90,7 @@ CrossPointWebServer::~CrossPointWebServer() { stop(); }
void CrossPointWebServer::begin() {
if (running) {
Serial.printf("[%lu] [WEB] Web server already running\n", millis());
LOG_DBG("WEB", "Web server already running");
return;
}
@@ -99,18 +100,17 @@ void CrossPointWebServer::begin() {
const bool isInApMode = (wifiMode & WIFI_MODE_AP) && (WiFi.softAPgetStationNum() >= 0); // AP is running
if (!isStaConnected && !isInApMode) {
Serial.printf("[%lu] [WEB] Cannot start webserver - no valid network (mode=%d, status=%d)\n", millis(), wifiMode,
WiFi.status());
LOG_DBG("WEB", "Cannot start webserver - no valid network (mode=%d, status=%d)", wifiMode, WiFi.status());
return;
}
// Store AP mode flag for later use (e.g., in handleStatus)
apMode = isInApMode;
Serial.printf("[%lu] [WEB] [MEM] Free heap before begin: %d bytes\n", millis(), ESP.getFreeHeap());
Serial.printf("[%lu] [WEB] Network mode: %s\n", millis(), apMode ? "AP" : "STA");
LOG_DBG("WEB", "[MEM] Free heap before begin: %d bytes", ESP.getFreeHeap());
LOG_DBG("WEB", "Network mode: %s", apMode ? "AP" : "STA");
Serial.printf("[%lu] [WEB] Creating web server on port %d...\n", millis(), port);
LOG_DBG("WEB", "Creating web server on port %d...", port);
server.reset(new WebServer(port));
// Disable WiFi sleep to improve responsiveness and prevent 'unreachable' errors.
@@ -120,15 +120,15 @@ void CrossPointWebServer::begin() {
// Note: WebServer class doesn't have setNoDelay() in the standard ESP32 library.
// We rely on disabling WiFi sleep for responsiveness.
Serial.printf("[%lu] [WEB] [MEM] Free heap after WebServer allocation: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "[MEM] Free heap after WebServer allocation: %d bytes", ESP.getFreeHeap());
if (!server) {
Serial.printf("[%lu] [WEB] Failed to create WebServer!\n", millis());
LOG_ERR("WEB", "Failed to create WebServer!");
return;
}
// Setup routes
Serial.printf("[%lu] [WEB] Setting up routes...\n", millis());
LOG_DBG("WEB", "Setting up routes...");
server->on("/", HTTP_GET, [this] { handleRoot(); });
server->on("/files", HTTP_GET, [this] { handleFileList(); });
@@ -157,43 +157,41 @@ void CrossPointWebServer::begin() {
server->on("/api/settings", HTTP_POST, [this] { handlePostSettings(); });
server->onNotFound([this] { handleNotFound(); });
Serial.printf("[%lu] [WEB] [MEM] Free heap after route setup: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "[MEM] Free heap after route setup: %d bytes", ESP.getFreeHeap());
server->begin();
// Start WebSocket server for fast binary uploads
Serial.printf("[%lu] [WEB] Starting WebSocket server on port %d...\n", millis(), wsPort);
LOG_DBG("WEB", "Starting WebSocket server on port %d...", wsPort);
wsServer.reset(new WebSocketsServer(wsPort));
wsInstance = const_cast<CrossPointWebServer*>(this);
wsServer->begin();
wsServer->onEvent(wsEventCallback);
Serial.printf("[%lu] [WEB] WebSocket server started\n", millis());
LOG_DBG("WEB", "WebSocket server started");
udpActive = udp.begin(LOCAL_UDP_PORT);
Serial.printf("[%lu] [WEB] Discovery UDP %s on port %d\n", millis(), udpActive ? "enabled" : "failed",
LOCAL_UDP_PORT);
LOG_DBG("WEB", "Discovery UDP %s on port %d", udpActive ? "enabled" : "failed", LOCAL_UDP_PORT);
running = true;
Serial.printf("[%lu] [WEB] Web server started on port %d\n", millis(), port);
LOG_DBG("WEB", "Web server started on port %d", port);
// Show the correct IP based on network mode
const String ipAddr = apMode ? WiFi.softAPIP().toString() : WiFi.localIP().toString();
Serial.printf("[%lu] [WEB] Access at http://%s/\n", millis(), ipAddr.c_str());
Serial.printf("[%lu] [WEB] WebSocket at ws://%s:%d/\n", millis(), ipAddr.c_str(), wsPort);
Serial.printf("[%lu] [WEB] [MEM] Free heap after server.begin(): %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "Access at http://%s/", ipAddr.c_str());
LOG_DBG("WEB", "WebSocket at ws://%s:%d/", ipAddr.c_str(), wsPort);
LOG_DBG("WEB", "[MEM] Free heap after server.begin(): %d bytes", ESP.getFreeHeap());
}
void CrossPointWebServer::stop() {
if (!running || !server) {
Serial.printf("[%lu] [WEB] stop() called but already stopped (running=%d, server=%p)\n", millis(), running,
server.get());
LOG_DBG("WEB", "stop() called but already stopped (running=%d, server=%p)", running, server.get());
return;
}
Serial.printf("[%lu] [WEB] STOP INITIATED - setting running=false first\n", millis());
LOG_DBG("WEB", "STOP INITIATED - setting running=false first");
running = false; // Set this FIRST to prevent handleClient from using server
Serial.printf("[%lu] [WEB] [MEM] Free heap before stop: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "[MEM] Free heap before stop: %d bytes", ESP.getFreeHeap());
// Close any in-progress WebSocket upload
if (wsUploadInProgress && wsUploadFile) {
@@ -203,11 +201,11 @@ void CrossPointWebServer::stop() {
// Stop WebSocket server
if (wsServer) {
Serial.printf("[%lu] [WEB] Stopping WebSocket server...\n", millis());
LOG_DBG("WEB", "Stopping WebSocket server...");
wsServer->close();
wsServer.reset();
wsInstance = nullptr;
Serial.printf("[%lu] [WEB] WebSocket server stopped\n", millis());
LOG_DBG("WEB", "WebSocket server stopped");
}
if (udpActive) {
@@ -219,18 +217,18 @@ void CrossPointWebServer::stop() {
delay(20);
server->stop();
Serial.printf("[%lu] [WEB] [MEM] Free heap after server->stop(): %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "[MEM] Free heap after server->stop(): %d bytes", ESP.getFreeHeap());
// Brief delay before deletion
delay(10);
server.reset();
Serial.printf("[%lu] [WEB] Web server stopped and deleted\n", millis());
Serial.printf("[%lu] [WEB] [MEM] Free heap after delete server: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "Web server stopped and deleted");
LOG_DBG("WEB", "[MEM] Free heap after delete server: %d bytes", ESP.getFreeHeap());
// Note: Static upload variables (uploadFileName, uploadPath, uploadError) are declared
// later in the file and will be cleared when they go out of scope or on next upload
Serial.printf("[%lu] [WEB] [MEM] Free heap final: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "[MEM] Free heap final: %d bytes", ESP.getFreeHeap());
}
void CrossPointWebServer::handleClient() {
@@ -243,13 +241,13 @@ void CrossPointWebServer::handleClient() {
// Double-check server pointer is valid
if (!server) {
Serial.printf("[%lu] [WEB] WARNING: handleClient called with null server!\n", millis());
LOG_DBG("WEB", "WARNING: handleClient called with null server!");
return;
}
// Print debug every 10 seconds to confirm handleClient is being called
if (millis() - lastDebugPrint > 10000) {
Serial.printf("[%lu] [WEB] handleClient active, server running on port %d\n", millis(), port);
LOG_DBG("WEB", "handleClient active, server running on port %d", port);
lastDebugPrint = millis();
}
@@ -297,7 +295,7 @@ CrossPointWebServer::WsUploadStatus CrossPointWebServer::getWsUploadStatus() con
void CrossPointWebServer::handleRoot() const {
server->send(200, "text/html", HomePageHtml);
Serial.printf("[%lu] [WEB] Served root page\n", millis());
LOG_DBG("WEB", "Served root page");
}
void CrossPointWebServer::handleNotFound() const {
@@ -326,17 +324,17 @@ void CrossPointWebServer::handleStatus() const {
void CrossPointWebServer::scanFiles(const char* path, const std::function<void(FileInfo)>& callback) const {
FsFile root = Storage.open(path);
if (!root) {
Serial.printf("[%lu] [WEB] Failed to open directory: %s\n", millis(), path);
LOG_DBG("WEB", "Failed to open directory: %s", path);
return;
}
if (!root.isDirectory()) {
Serial.printf("[%lu] [WEB] Not a directory: %s\n", millis(), path);
LOG_DBG("WEB", "Not a directory: %s", path);
root.close();
return;
}
Serial.printf("[%lu] [WEB] Scanning files in: %s\n", millis(), path);
LOG_DBG("WEB", "Scanning files in: %s", path);
FsFile file = root.openNextFile();
char name[500];
@@ -422,7 +420,7 @@ void CrossPointWebServer::handleFileListData() const {
const size_t written = serializeJson(doc, output, outputSize);
if (written >= outputSize) {
// JSON output truncated; skip this entry to avoid sending malformed JSON
Serial.printf("[%lu] [WEB] Skipping file entry with oversized JSON for name: %s\n", millis(), info.name.c_str());
LOG_DBG("WEB", "Skipping file entry with oversized JSON for name: %s", info.name.c_str());
return;
}
@@ -436,7 +434,7 @@ void CrossPointWebServer::handleFileListData() const {
server->sendContent("]");
// End of streamed response, empty chunk to signal client
server->sendContent("");
Serial.printf("[%lu] [WEB] Served file listing page for path: %s\n", millis(), currentPath.c_str());
LOG_DBG("WEB", "Served file listing page for path: %s", currentPath.c_str());
}
void CrossPointWebServer::handleDownload() const {
@@ -517,8 +515,7 @@ static bool flushUploadBuffer(CrossPointWebServer::UploadState& state) {
esp_task_wdt_reset(); // Reset watchdog after SD write
if (written != state.bufferPos) {
Serial.printf("[%lu] [WEB] [UPLOAD] Buffer flush failed: expected %d, wrote %d\n", millis(), state.bufferPos,
written);
LOG_DBG("WEB", "[UPLOAD] Buffer flush failed: expected %d, wrote %d", state.bufferPos, written);
state.bufferPos = 0;
return false;
}
@@ -535,7 +532,7 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
// Safety check: ensure server is still valid
if (!running || !server) {
Serial.printf("[%lu] [WEB] [UPLOAD] ERROR: handleUpload called but server not running!\n", millis());
LOG_DBG("WEB", "[UPLOAD] ERROR: handleUpload called but server not running!");
return;
}
@@ -572,8 +569,8 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
state.path = "/";
}
Serial.printf("[%lu] [WEB] [UPLOAD] START: %s to path: %s\n", millis(), state.fileName.c_str(), state.path.c_str());
Serial.printf("[%lu] [WEB] [UPLOAD] Free heap: %d bytes\n", millis(), ESP.getFreeHeap());
LOG_DBG("WEB", "[UPLOAD] START: %s to path: %s", state.fileName.c_str(), state.path.c_str());
LOG_DBG("WEB", "[UPLOAD] Free heap: %d bytes", ESP.getFreeHeap());
// Create file path
String filePath = state.path;
@@ -583,7 +580,7 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
// Check if file already exists - SD operations can be slow
esp_task_wdt_reset();
if (Storage.exists(filePath.c_str())) {
Serial.printf("[%lu] [WEB] [UPLOAD] Overwriting existing file: %s\n", millis(), filePath.c_str());
LOG_DBG("WEB", "[UPLOAD] Overwriting existing file: %s", filePath.c_str());
esp_task_wdt_reset();
Storage.remove(filePath.c_str());
}
@@ -592,12 +589,12 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
esp_task_wdt_reset();
if (!Storage.openFileForWrite("WEB", filePath, state.file)) {
state.error = "Failed to create file on SD card";
Serial.printf("[%lu] [WEB] [UPLOAD] FAILED to create file: %s\n", millis(), filePath.c_str());
LOG_DBG("WEB", "[UPLOAD] FAILED to create file: %s", filePath.c_str());
return;
}
esp_task_wdt_reset();
Serial.printf("[%lu] [WEB] [UPLOAD] File created successfully: %s\n", millis(), filePath.c_str());
LOG_DBG("WEB", "[UPLOAD] File created successfully: %s", filePath.c_str());
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (state.file && state.error.isEmpty()) {
// Buffer incoming data and flush when buffer is full
@@ -630,8 +627,8 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
if (state.size - lastLoggedSize >= 102400) {
const unsigned long elapsed = millis() - uploadStartTime;
const float kbps = (elapsed > 0) ? (state.size / 1024.0) / (elapsed / 1000.0) : 0;
Serial.printf("[%lu] [WEB] [UPLOAD] %d bytes (%.1f KB), %.1f KB/s, %d writes\n", millis(), state.size,
state.size / 1024.0, kbps, writeCount);
LOG_DBG("WEB", "[UPLOAD] %d bytes (%.1f KB), %.1f KB/s, %d writes", state.size, state.size / 1024.0, kbps,
writeCount);
lastLoggedSize = state.size;
}
}
@@ -648,10 +645,10 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
const unsigned long elapsed = millis() - uploadStartTime;
const float avgKbps = (elapsed > 0) ? (state.size / 1024.0) / (elapsed / 1000.0) : 0;
const float writePercent = (elapsed > 0) ? (totalWriteTime * 100.0 / elapsed) : 0;
Serial.printf("[%lu] [WEB] [UPLOAD] Complete: %s (%d bytes in %lu ms, avg %.1f KB/s)\n", millis(),
state.fileName.c_str(), state.size, elapsed, avgKbps);
Serial.printf("[%lu] [WEB] [UPLOAD] Diagnostics: %d writes, total write time: %lu ms (%.1f%%)\n", millis(),
writeCount, totalWriteTime, writePercent);
LOG_DBG("WEB", "[UPLOAD] Complete: %s (%d bytes in %lu ms, avg %.1f KB/s)", state.fileName.c_str(), state.size,
elapsed, avgKbps);
LOG_DBG("WEB", "[UPLOAD] Diagnostics: %d writes, total write time: %lu ms (%.1f%%)", writeCount, totalWriteTime,
writePercent);
// Clear epub cache to prevent stale metadata issues when overwriting files
String filePath = state.path;
@@ -671,7 +668,7 @@ void CrossPointWebServer::handleUpload(UploadState& state) const {
Storage.remove(filePath.c_str());
}
state.error = "Upload aborted";
Serial.printf("[%lu] [WEB] Upload aborted\n", millis());
LOG_DBG("WEB", "Upload aborted");
}
}
@@ -716,7 +713,7 @@ void CrossPointWebServer::handleCreateFolder() const {
if (!folderPath.endsWith("/")) folderPath += "/";
folderPath += folderName;
Serial.printf("[%lu] [WEB] Creating folder: %s\n", millis(), folderPath.c_str());
LOG_DBG("WEB", "Creating folder: %s", folderPath.c_str());
// Check if already exists
if (Storage.exists(folderPath.c_str())) {
@@ -726,10 +723,10 @@ void CrossPointWebServer::handleCreateFolder() const {
// Create the folder
if (Storage.mkdir(folderPath.c_str())) {
Serial.printf("[%lu] [WEB] Folder created successfully: %s\n", millis(), folderPath.c_str());
LOG_DBG("WEB", "Folder created successfully: %s", folderPath.c_str());
server->send(200, "text/plain", "Folder created: " + folderName);
} else {
Serial.printf("[%lu] [WEB] Failed to create folder: %s\n", millis(), folderPath.c_str());
LOG_DBG("WEB", "Failed to create folder: %s", folderPath.c_str());
server->send(500, "text/plain", "Failed to create folder");
}
}
@@ -808,10 +805,10 @@ void CrossPointWebServer::handleRename() const {
file.close();
if (success) {
Serial.printf("[%lu] [WEB] Renamed file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str());
LOG_DBG("WEB", "Renamed file: %s -> %s", itemPath.c_str(), newPath.c_str());
server->send(200, "text/plain", "Renamed successfully");
} else {
Serial.printf("[%lu] [WEB] Failed to rename file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str());
LOG_ERR("WEB", "Failed to rename file: %s -> %s", itemPath.c_str(), newPath.c_str());
server->send(500, "text/plain", "Failed to rename file");
}
}
@@ -901,10 +898,10 @@ void CrossPointWebServer::handleMove() const {
file.close();
if (success) {
Serial.printf("[%lu] [WEB] Moved file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str());
LOG_DBG("WEB", "Moved file: %s -> %s", itemPath.c_str(), newPath.c_str());
server->send(200, "text/plain", "Moved successfully");
} else {
Serial.printf("[%lu] [WEB] Failed to move file: %s -> %s\n", millis(), itemPath.c_str(), newPath.c_str());
LOG_ERR("WEB", "Failed to move file: %s -> %s", itemPath.c_str(), newPath.c_str());
server->send(500, "text/plain", "Failed to move file");
}
}
@@ -935,7 +932,7 @@ void CrossPointWebServer::handleDelete() const {
// Check if item starts with a dot (hidden/system file)
if (itemName.startsWith(".")) {
Serial.printf("[%lu] [WEB] Delete rejected - hidden/system item: %s\n", millis(), itemPath.c_str());
LOG_DBG("WEB", "Delete rejected - hidden/system item: %s", itemPath.c_str());
server->send(403, "text/plain", "Cannot delete system files");
return;
}
@@ -943,7 +940,7 @@ void CrossPointWebServer::handleDelete() const {
// Check against explicitly protected items
for (size_t i = 0; i < HIDDEN_ITEMS_COUNT; i++) {
if (itemName.equals(HIDDEN_ITEMS[i])) {
Serial.printf("[%lu] [WEB] Delete rejected - protected item: %s\n", millis(), itemPath.c_str());
LOG_DBG("WEB", "Delete rejected - protected item: %s", itemPath.c_str());
server->send(403, "text/plain", "Cannot delete protected items");
return;
}
@@ -951,12 +948,12 @@ void CrossPointWebServer::handleDelete() const {
// Check if item exists
if (!Storage.exists(itemPath.c_str())) {
Serial.printf("[%lu] [WEB] Delete failed - item not found: %s\n", millis(), itemPath.c_str());
LOG_DBG("WEB", "Delete failed - item not found: %s", itemPath.c_str());
server->send(404, "text/plain", "Item not found");
return;
}
Serial.printf("[%lu] [WEB] Attempting to delete %s: %s\n", millis(), itemType.c_str(), itemPath.c_str());
LOG_DBG("WEB", "Attempting to delete %s: %s", itemType.c_str(), itemPath.c_str());
bool success = false;
@@ -970,7 +967,7 @@ void CrossPointWebServer::handleDelete() const {
// Folder is not empty
entry.close();
dir.close();
Serial.printf("[%lu] [WEB] Delete failed - folder not empty: %s\n", millis(), itemPath.c_str());
LOG_DBG("WEB", "Delete failed - folder not empty: %s", itemPath.c_str());
server->send(400, "text/plain", "Folder is not empty. Delete contents first.");
return;
}
@@ -983,17 +980,17 @@ void CrossPointWebServer::handleDelete() const {
}
if (success) {
Serial.printf("[%lu] [WEB] Successfully deleted: %s\n", millis(), itemPath.c_str());
LOG_DBG("WEB", "Successfully deleted: %s", itemPath.c_str());
server->send(200, "text/plain", "Deleted successfully");
} else {
Serial.printf("[%lu] [WEB] Failed to delete: %s\n", millis(), itemPath.c_str());
LOG_ERR("WEB", "Failed to delete: %s", itemPath.c_str());
server->send(500, "text/plain", "Failed to delete item");
}
}
void CrossPointWebServer::handleSettingsPage() const {
server->send(200, "text/html", SettingsPageHtml);
Serial.printf("[%lu] [WEB] Served settings page\n", millis());
LOG_DBG("WEB", "Served settings page");
}
void CrossPointWebServer::handleGetSettings() const {
@@ -1062,7 +1059,7 @@ void CrossPointWebServer::handleGetSettings() const {
const size_t written = serializeJson(doc, output, outputSize);
if (written >= outputSize) {
Serial.printf("[%lu] [WEB] Skipping oversized setting JSON for: %s\n", millis(), s.key);
LOG_DBG("WEB", "Skipping oversized setting JSON for: %s", s.key);
continue;
}
@@ -1076,7 +1073,7 @@ void CrossPointWebServer::handleGetSettings() const {
server->sendContent("]");
server->sendContent("");
Serial.printf("[%lu] [WEB] Served settings API\n", millis());
LOG_DBG("WEB", "Served settings API");
}
void CrossPointWebServer::handlePostSettings() {
@@ -1149,7 +1146,7 @@ void CrossPointWebServer::handlePostSettings() {
SETTINGS.saveToFile();
Serial.printf("[%lu] [WEB] Applied %d setting(s)\n", millis(), applied);
LOG_DBG("WEB", "Applied %d setting(s)", applied);
server->send(200, "text/plain", String("Applied ") + String(applied) + " setting(s)");
}
@@ -1169,7 +1166,7 @@ void CrossPointWebServer::wsEventCallback(uint8_t num, WStype_t type, uint8_t* p
void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t* payload, size_t length) {
switch (type) {
case WStype_DISCONNECTED:
Serial.printf("[%lu] [WS] Client %u disconnected\n", millis(), num);
LOG_DBG("WS", "Client %u disconnected", num);
// Clean up any in-progress upload
if (wsUploadInProgress && wsUploadFile) {
wsUploadFile.close();
@@ -1178,20 +1175,20 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
if (!filePath.endsWith("/")) filePath += "/";
filePath += wsUploadFileName;
Storage.remove(filePath.c_str());
Serial.printf("[%lu] [WS] Deleted incomplete upload: %s\n", millis(), filePath.c_str());
LOG_DBG("WS", "Deleted incomplete upload: %s", filePath.c_str());
}
wsUploadInProgress = false;
break;
case WStype_CONNECTED: {
Serial.printf("[%lu] [WS] Client %u connected\n", millis(), num);
LOG_DBG("WS", "Client %u connected", num);
break;
}
case WStype_TEXT: {
// Parse control messages
String msg = String((char*)payload);
Serial.printf("[%lu] [WS] Text from client %u: %s\n", millis(), num, msg.c_str());
LOG_DBG("WS", "Text from client %u: %s", num, msg.c_str());
if (msg.startsWith("START:")) {
// Parse: START:<filename>:<size>:<path>
@@ -1216,8 +1213,8 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
if (!filePath.endsWith("/")) filePath += "/";
filePath += wsUploadFileName;
Serial.printf("[%lu] [WS] Starting upload: %s (%d bytes) to %s\n", millis(), wsUploadFileName.c_str(),
wsUploadSize, filePath.c_str());
LOG_DBG("WS", "Starting upload: %s (%d bytes) to %s", wsUploadFileName.c_str(), wsUploadSize,
filePath.c_str());
// Check if file exists and remove it
esp_task_wdt_reset();
@@ -1283,8 +1280,8 @@ void CrossPointWebServer::onWebSocketEvent(uint8_t num, WStype_t type, uint8_t*
unsigned long elapsed = millis() - wsUploadStartTime;
float kbps = (elapsed > 0) ? (wsUploadSize / 1024.0) / (elapsed / 1000.0) : 0;
Serial.printf("[%lu] [WS] Upload complete: %s (%d bytes in %lu ms, %.1f KB/s)\n", millis(),
wsUploadFileName.c_str(), wsUploadSize, elapsed, kbps);
LOG_DBG("WS", "Upload complete: %s (%d bytes in %lu ms, %.1f KB/s)", wsUploadFileName.c_str(), wsUploadSize,
elapsed, kbps);
// Clear epub cache to prevent stale metadata issues when overwriting files
String filePath = wsUploadPath;

View File

@@ -1,7 +1,7 @@
#include "HttpDownloader.h"
#include <HTTPClient.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <StreamString.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
@@ -25,7 +25,7 @@ bool HttpDownloader::fetchUrl(const std::string& url, Stream& outContent) {
}
HTTPClient http;
Serial.printf("[%lu] [HTTP] Fetching: %s\n", millis(), url.c_str());
LOG_DBG("HTTP", "Fetching: %s", url.c_str());
http.begin(*client, url.c_str());
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
@@ -40,7 +40,7 @@ bool HttpDownloader::fetchUrl(const std::string& url, Stream& outContent) {
const int httpCode = http.GET();
if (httpCode != HTTP_CODE_OK) {
Serial.printf("[%lu] [HTTP] Fetch failed: %d\n", millis(), httpCode);
LOG_ERR("HTTP", "Fetch failed: %d", httpCode);
http.end();
return false;
}
@@ -49,7 +49,7 @@ bool HttpDownloader::fetchUrl(const std::string& url, Stream& outContent) {
http.end();
Serial.printf("[%lu] [HTTP] Fetch success\n", millis());
LOG_DBG("HTTP", "Fetch success");
return true;
}
@@ -75,8 +75,8 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
}
HTTPClient http;
Serial.printf("[%lu] [HTTP] Downloading: %s\n", millis(), url.c_str());
Serial.printf("[%lu] [HTTP] Destination: %s\n", millis(), destPath.c_str());
LOG_DBG("HTTP", "Downloading: %s", url.c_str());
LOG_DBG("HTTP", "Destination: %s", destPath.c_str());
http.begin(*client, url.c_str());
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
@@ -91,13 +91,13 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
const int httpCode = http.GET();
if (httpCode != HTTP_CODE_OK) {
Serial.printf("[%lu] [HTTP] Download failed: %d\n", millis(), httpCode);
LOG_ERR("HTTP", "Download failed: %d", httpCode);
http.end();
return HTTP_ERROR;
}
const size_t contentLength = http.getSize();
Serial.printf("[%lu] [HTTP] Content-Length: %zu\n", millis(), contentLength);
LOG_DBG("HTTP", "Content-Length: %zu", contentLength);
// Remove existing file if present
if (Storage.exists(destPath.c_str())) {
@@ -107,7 +107,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
// Open file for writing
FsFile file;
if (!Storage.openFileForWrite("HTTP", destPath.c_str(), file)) {
Serial.printf("[%lu] [HTTP] Failed to open file for writing\n", millis());
LOG_ERR("HTTP", "Failed to open file for writing");
http.end();
return FILE_ERROR;
}
@@ -115,7 +115,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
// Get the stream for chunked reading
WiFiClient* stream = http.getStreamPtr();
if (!stream) {
Serial.printf("[%lu] [HTTP] Failed to get stream\n", millis());
LOG_ERR("HTTP", "Failed to get stream");
file.close();
Storage.remove(destPath.c_str());
http.end();
@@ -143,7 +143,7 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
const size_t written = file.write(buffer, bytesRead);
if (written != bytesRead) {
Serial.printf("[%lu] [HTTP] Write failed: wrote %zu of %zu bytes\n", millis(), written, bytesRead);
LOG_ERR("HTTP", "Write failed: wrote %zu of %zu bytes", written, bytesRead);
file.close();
Storage.remove(destPath.c_str());
http.end();
@@ -160,11 +160,11 @@ HttpDownloader::DownloadError HttpDownloader::downloadToFile(const std::string&
file.close();
http.end();
Serial.printf("[%lu] [HTTP] Downloaded %zu bytes\n", millis(), downloaded);
LOG_DBG("HTTP", "Downloaded %zu bytes", downloaded);
// Verify download size if known
if (contentLength > 0 && downloaded != contentLength) {
Serial.printf("[%lu] [HTTP] Size mismatch: got %zu, expected %zu\n", millis(), downloaded, contentLength);
LOG_ERR("HTTP", "Size mismatch: got %zu, expected %zu", downloaded, contentLength);
Storage.remove(destPath.c_str());
return HTTP_ERROR;
}

View File

@@ -1,6 +1,7 @@
#include "OtaUpdater.h"
#include <ArduinoJson.h>
#include <Logging.h>
#include "esp_http_client.h"
#include "esp_https_ota.h"
@@ -39,7 +40,7 @@ esp_err_t event_handler(esp_http_client_event_t* event) {
local_buf = static_cast<char*>(calloc(content_len + 1, sizeof(char)));
output_len = 0;
if (local_buf == NULL) {
Serial.printf("[%lu] [OTA] HTTP Client Out of Memory Failed, Allocation %d\n", millis(), content_len);
LOG_ERR("OTA", "HTTP Client Out of Memory Failed, Allocation %d", content_len);
return ESP_ERR_NO_MEM;
}
}
@@ -52,7 +53,7 @@ esp_err_t event_handler(esp_http_client_event_t* event) {
/* Code might be hits here, It happened once (for version checking) but I need more logs to handle that */
int chunked_len;
esp_http_client_get_chunk_length(event->client, &chunked_len);
Serial.printf("[%lu] [OTA] esp_http_client_is_chunked_response failed, chunked_len: %d\n", millis(), chunked_len);
LOG_DBG("OTA", "esp_http_client_is_chunked_response failed, chunked_len: %d", chunked_len);
}
return ESP_OK;
@@ -88,20 +89,20 @@ OtaUpdater::OtaUpdaterError OtaUpdater::checkForUpdate() {
esp_http_client_handle_t client_handle = esp_http_client_init(&client_config);
if (!client_handle) {
Serial.printf("[%lu] [OTA] HTTP Client Handle Failed\n", millis());
LOG_ERR("OTA", "HTTP Client Handle Failed");
return INTERNAL_UPDATE_ERROR;
}
esp_err = esp_http_client_set_header(client_handle, "User-Agent", "CrossPoint-ESP32-" CROSSPOINT_VERSION);
if (esp_err != ESP_OK) {
Serial.printf("[%lu] [OTA] esp_http_client_set_header Failed : %s\n", millis(), esp_err_to_name(esp_err));
LOG_ERR("OTA", "esp_http_client_set_header Failed : %s", esp_err_to_name(esp_err));
esp_http_client_cleanup(client_handle);
return INTERNAL_UPDATE_ERROR;
}
esp_err = esp_http_client_perform(client_handle);
if (esp_err != ESP_OK) {
Serial.printf("[%lu] [OTA] esp_http_client_perform Failed : %s\n", millis(), esp_err_to_name(esp_err));
LOG_ERR("OTA", "esp_http_client_perform Failed : %s", esp_err_to_name(esp_err));
esp_http_client_cleanup(client_handle);
return HTTP_ERROR;
}
@@ -109,7 +110,7 @@ OtaUpdater::OtaUpdaterError OtaUpdater::checkForUpdate() {
/* esp_http_client_close will be called inside cleanup as well*/
esp_err = esp_http_client_cleanup(client_handle);
if (esp_err != ESP_OK) {
Serial.printf("[%lu] [OTA] esp_http_client_cleanupp Failed : %s\n", millis(), esp_err_to_name(esp_err));
LOG_ERR("OTA", "esp_http_client_cleanup Failed : %s", esp_err_to_name(esp_err));
return INTERNAL_UPDATE_ERROR;
}
@@ -119,17 +120,17 @@ OtaUpdater::OtaUpdaterError OtaUpdater::checkForUpdate() {
filter["assets"][0]["size"] = true;
const DeserializationError error = deserializeJson(doc, local_buf, DeserializationOption::Filter(filter));
if (error) {
Serial.printf("[%lu] [OTA] JSON parse failed: %s\n", millis(), error.c_str());
LOG_ERR("OTA", "JSON parse failed: %s", error.c_str());
return JSON_PARSE_ERROR;
}
if (!doc["tag_name"].is<std::string>()) {
Serial.printf("[%lu] [OTA] No tag_name found\n", millis());
LOG_ERR("OTA", "No tag_name found");
return JSON_PARSE_ERROR;
}
if (!doc["assets"].is<JsonArray>()) {
Serial.printf("[%lu] [OTA] No assets found\n", millis());
LOG_ERR("OTA", "No assets found");
return JSON_PARSE_ERROR;
}
@@ -146,11 +147,11 @@ OtaUpdater::OtaUpdaterError OtaUpdater::checkForUpdate() {
}
if (!updateAvailable) {
Serial.printf("[%lu] [OTA] No firmware.bin asset found\n", millis());
LOG_ERR("OTA", "No firmware.bin asset found");
return NO_UPDATE;
}
Serial.printf("[%lu] [OTA] Found update: %s\n", millis(), latestVersion.c_str());
LOG_DBG("OTA", "Found update: %s", latestVersion.c_str());
return OK;
}
@@ -233,7 +234,7 @@ OtaUpdater::OtaUpdaterError OtaUpdater::installUpdate() {
esp_err = esp_https_ota_begin(&ota_config, &ota_handle);
if (esp_err != ESP_OK) {
Serial.printf("[%lu] [OTA] HTTP OTA Begin Failed: %s\n", millis(), esp_err_to_name(esp_err));
LOG_DBG("OTA", "HTTP OTA Begin Failed: %s", esp_err_to_name(esp_err));
return INTERNAL_UPDATE_ERROR;
}
@@ -249,24 +250,23 @@ OtaUpdater::OtaUpdaterError OtaUpdater::installUpdate() {
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
if (esp_err != ESP_OK) {
Serial.printf("[%lu] [OTA] esp_https_ota_perform Failed: %s\n", millis(), esp_err_to_name(esp_err));
LOG_ERR("OTA", "esp_https_ota_perform Failed: %s", esp_err_to_name(esp_err));
esp_https_ota_finish(ota_handle);
return HTTP_ERROR;
}
if (!esp_https_ota_is_complete_data_received(ota_handle)) {
Serial.printf("[%lu] [OTA] esp_https_ota_is_complete_data_received Failed: %s\n", millis(),
esp_err_to_name(esp_err));
LOG_ERR("OTA", "esp_https_ota_is_complete_data_received Failed: %s", esp_err_to_name(esp_err));
esp_https_ota_finish(ota_handle);
return INTERNAL_UPDATE_ERROR;
}
esp_err = esp_https_ota_finish(ota_handle);
if (esp_err != ESP_OK) {
Serial.printf("[%lu] [OTA] esp_https_ota_finish Failed: %s\n", millis(), esp_err_to_name(esp_err));
LOG_ERR("OTA", "esp_https_ota_finish Failed: %s", esp_err_to_name(esp_err));
return INTERNAL_UPDATE_ERROR;
}
Serial.printf("[%lu] [OTA] Update completed\n", millis());
LOG_INF("OTA", "Update completed");
return OK;
}

View File

@@ -1,7 +1,7 @@
#include "BookSettings.h"
#include <HalStorage.h>
#include <HardwareSerial.h>
#include <Logging.h>
#include <Serialization.h>
namespace {
@@ -37,15 +37,15 @@ BookSettings BookSettings::load(const std::string& cachePath) {
} while (false);
f.close();
Serial.printf("[%lu] [BST] Loaded book settings from %s (letterboxFill=%d)\n", millis(), filePath(cachePath).c_str(),
settings.letterboxFillOverride);
LOG_DBG("BST", "Loaded book settings from %s (letterboxFill=%d)", filePath(cachePath).c_str(),
settings.letterboxFillOverride);
return settings;
}
bool BookSettings::save(const std::string& cachePath, const BookSettings& settings) {
FsFile f;
if (!Storage.openFileForWrite("BST", filePath(cachePath), f)) {
Serial.printf("[%lu] [BST] Could not save book settings!\n", millis());
LOG_ERR("BST", "Could not save book settings!");
return false;
}
@@ -55,6 +55,6 @@ bool BookSettings::save(const std::string& cachePath, const BookSettings& settin
// New fields added here
f.close();
Serial.printf("[%lu] [BST] Saved book settings to %s\n", millis(), filePath(cachePath).c_str());
LOG_DBG("BST", "Saved book settings to %s", filePath(cachePath).c_str());
return true;
}

View File

@@ -1,6 +1,7 @@
#include "BookmarkStore.h"
#include <HalStorage.h>
#include <Logging.h>
#include <algorithm>
@@ -78,7 +79,7 @@ std::vector<Bookmark> BookmarkStore::load(const std::string& cachePath) {
bool BookmarkStore::save(const std::string& cachePath, const std::vector<Bookmark>& bookmarks) {
FsFile f;
if (!Storage.openFileForWrite("BKM", filePath(cachePath), f)) {
Serial.printf("[%lu] [BKM] Could not save bookmarks!\n", millis());
LOG_ERR("BKM", "Could not save bookmarks!");
return false;
}
@@ -107,7 +108,7 @@ bool BookmarkStore::save(const std::string& cachePath, const std::vector<Bookmar
}
f.close();
Serial.printf("[%lu] [BKM] Saved %d bookmarks\n", millis(), count);
LOG_DBG("BKM", "Saved %d bookmarks", count);
return true;
}