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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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); }));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "SettingsActivity.h"
|
||||
|
||||
#include <GfxRenderer.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <Logging.h>
|
||||
|
||||
#include "ButtonRemapActivity.h"
|
||||
#include "CalibreSettingsActivity.h"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
42
src/main.cpp
42
src/main.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user