Small cleanups from https://github.com/juicecultus/crosspoint-reader-x4
This commit is contained in:
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
#include <Utf8.h>
|
#include <Utf8.h>
|
||||||
|
|
||||||
inline int min(const int a, const int b) { return a < b ? a : b; }
|
#include <algorithm>
|
||||||
inline int max(const int a, const int b) { return a < b ? b : a; }
|
|
||||||
|
|
||||||
void EpdFont::getTextBounds(const char* string, const int startX, const int startY, int* minX, int* minY, int* maxX,
|
void EpdFont::getTextBounds(const char* string, const int startX, const int startY, int* minX, int* minY, int* maxX,
|
||||||
int* maxY) const {
|
int* maxY) const {
|
||||||
@@ -32,10 +31,10 @@ void EpdFont::getTextBounds(const char* string, const int startX, const int star
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
*minX = min(*minX, cursorX + glyph->left);
|
*minX = std::min(*minX, cursorX + glyph->left);
|
||||||
*maxX = max(*maxX, cursorX + glyph->left + glyph->width);
|
*maxX = std::max(*maxX, cursorX + glyph->left + glyph->width);
|
||||||
*minY = min(*minY, cursorY + glyph->top - glyph->height);
|
*minY = std::min(*minY, cursorY + glyph->top - glyph->height);
|
||||||
*maxY = max(*maxY, cursorY + glyph->top);
|
*maxY = std::max(*maxY, cursorY + glyph->top);
|
||||||
cursorX += glyph->advanceX;
|
cursorX += glyph->advanceX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,17 +109,20 @@ bool Epub::parseTocNcxFile() const {
|
|||||||
|
|
||||||
if (!ncxParser.setup()) {
|
if (!ncxParser.setup()) {
|
||||||
Serial.printf("[%lu] [EBP] Could not setup toc ncx parser\n", millis());
|
Serial.printf("[%lu] [EBP] Could not setup toc ncx parser\n", millis());
|
||||||
|
tempNcxFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto ncxBuffer = static_cast<uint8_t*>(malloc(1024));
|
const auto ncxBuffer = static_cast<uint8_t*>(malloc(1024));
|
||||||
if (!ncxBuffer) {
|
if (!ncxBuffer) {
|
||||||
Serial.printf("[%lu] [EBP] Could not allocate memory for toc ncx parser\n", millis());
|
Serial.printf("[%lu] [EBP] Could not allocate memory for toc ncx parser\n", millis());
|
||||||
|
tempNcxFile.close();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (tempNcxFile.available()) {
|
while (tempNcxFile.available()) {
|
||||||
const auto readSize = tempNcxFile.read(ncxBuffer, 1024);
|
const auto readSize = tempNcxFile.read(ncxBuffer, 1024);
|
||||||
|
if (readSize == 0) break;
|
||||||
const auto processedSize = ncxParser.write(ncxBuffer, readSize);
|
const auto processedSize = ncxParser.write(ncxBuffer, readSize);
|
||||||
|
|
||||||
if (processedSize != readSize) {
|
if (processedSize != readSize) {
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ void ChapterHtmlSlimParser::startNewTextBlock(const TextBlock::BLOCK_STYLE style
|
|||||||
|
|
||||||
void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* name, const XML_Char** atts) {
|
void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* name, const XML_Char** atts) {
|
||||||
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
||||||
(void)atts;
|
|
||||||
|
|
||||||
// Middle of skip
|
// Middle of skip
|
||||||
if (self->skipUntilDepth < self->depth) {
|
if (self->skipUntilDepth < self->depth) {
|
||||||
@@ -93,7 +92,7 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
|
|
||||||
if (matches(name, HEADER_TAGS, NUM_HEADER_TAGS)) {
|
if (matches(name, HEADER_TAGS, NUM_HEADER_TAGS)) {
|
||||||
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
|
self->startNewTextBlock(TextBlock::CENTER_ALIGN);
|
||||||
self->boldUntilDepth = min(self->boldUntilDepth, self->depth);
|
self->boldUntilDepth = std::min(self->boldUntilDepth, self->depth);
|
||||||
} else if (matches(name, BLOCK_TAGS, NUM_BLOCK_TAGS)) {
|
} else if (matches(name, BLOCK_TAGS, NUM_BLOCK_TAGS)) {
|
||||||
if (strcmp(name, "br") == 0) {
|
if (strcmp(name, "br") == 0) {
|
||||||
self->startNewTextBlock(self->currentTextBlock->getStyle());
|
self->startNewTextBlock(self->currentTextBlock->getStyle());
|
||||||
@@ -101,9 +100,9 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
|
|||||||
self->startNewTextBlock(TextBlock::JUSTIFIED);
|
self->startNewTextBlock(TextBlock::JUSTIFIED);
|
||||||
}
|
}
|
||||||
} else if (matches(name, BOLD_TAGS, NUM_BOLD_TAGS)) {
|
} else if (matches(name, BOLD_TAGS, NUM_BOLD_TAGS)) {
|
||||||
self->boldUntilDepth = min(self->boldUntilDepth, self->depth);
|
self->boldUntilDepth = std::min(self->boldUntilDepth, self->depth);
|
||||||
} else if (matches(name, ITALIC_TAGS, NUM_ITALIC_TAGS)) {
|
} else if (matches(name, ITALIC_TAGS, NUM_ITALIC_TAGS)) {
|
||||||
self->italicUntilDepth = min(self->italicUntilDepth, self->depth);
|
self->italicUntilDepth = std::min(self->italicUntilDepth, self->depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->depth += 1;
|
self->depth += 1;
|
||||||
@@ -162,7 +161,6 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char
|
|||||||
|
|
||||||
void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* name) {
|
void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* name) {
|
||||||
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
auto* self = static_cast<ChapterHtmlSlimParser*>(userData);
|
||||||
(void)name;
|
|
||||||
|
|
||||||
if (self->partWordBufferIndex > 0) {
|
if (self->partWordBufferIndex > 0) {
|
||||||
// Only flush out part word buffer if we're closing a block tag or are at the top of the HTML file.
|
// Only flush out part word buffer if we're closing a block tag or are at the top of the HTML file.
|
||||||
@@ -245,9 +243,9 @@ bool ChapterHtmlSlimParser::parseAndBuildPages() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t len = file.read(static_cast<uint8_t*>(buf), 1024);
|
const size_t len = file.read(buf, 1024);
|
||||||
|
|
||||||
if (len == 0) {
|
if (len == 0 && file.available() > 0) {
|
||||||
Serial.printf("[%lu] [EHP] File read error\n", millis());
|
Serial.printf("[%lu] [EHP] File read error\n", millis());
|
||||||
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
XML_StopParser(parser, XML_FALSE); // Stop any pending processing
|
||||||
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
XML_SetElementHandler(parser, nullptr, nullptr); // Clear callbacks
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class GfxRenderer {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), renderMode(BW), orientation(Portrait) {}
|
explicit GfxRenderer(EInkDisplay& einkDisplay) : einkDisplay(einkDisplay), renderMode(BW), orientation(Portrait) {}
|
||||||
~GfxRenderer() = default;
|
~GfxRenderer() { freeBwBufferChunks(); }
|
||||||
|
|
||||||
static constexpr int VIEWABLE_MARGIN_TOP = 9;
|
static constexpr int VIEWABLE_MARGIN_TOP = 9;
|
||||||
static constexpr int VIEWABLE_MARGIN_RIGHT = 3;
|
static constexpr int VIEWABLE_MARGIN_RIGHT = 3;
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ void CrossPointWebServer::begin() {
|
|||||||
|
|
||||||
Serial.printf("[%lu] [WEB] Creating web server on port %d...\n", millis(), port);
|
Serial.printf("[%lu] [WEB] Creating web server on port %d...\n", millis(), port);
|
||||||
server.reset(new WebServer(port));
|
server.reset(new WebServer(port));
|
||||||
|
|
||||||
|
// Disable WiFi sleep to improve responsiveness and prevent 'unreachable' errors.
|
||||||
|
// This is critical for reliable web server operation on ESP32.
|
||||||
|
WiFi.setSleep(false);
|
||||||
|
|
||||||
|
// 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());
|
Serial.printf("[%lu] [WEB] [MEM] Free heap after WebServer allocation: %d bytes\n", millis(), ESP.getFreeHeap());
|
||||||
|
|
||||||
if (!server) {
|
if (!server) {
|
||||||
@@ -157,15 +165,16 @@ void CrossPointWebServer::handleStatus() const {
|
|||||||
// Get correct IP based on AP vs STA mode
|
// Get correct IP based on AP vs STA mode
|
||||||
const String ipAddr = apMode ? WiFi.softAPIP().toString() : WiFi.localIP().toString();
|
const String ipAddr = apMode ? WiFi.softAPIP().toString() : WiFi.localIP().toString();
|
||||||
|
|
||||||
String json = "{";
|
JsonDocument doc;
|
||||||
json += "\"version\":\"" + String(CROSSPOINT_VERSION) + "\",";
|
doc["version"] = CROSSPOINT_VERSION;
|
||||||
json += "\"ip\":\"" + ipAddr + "\",";
|
doc["ip"] = ipAddr;
|
||||||
json += "\"mode\":\"" + String(apMode ? "AP" : "STA") + "\",";
|
doc["mode"] = apMode ? "AP" : "STA";
|
||||||
json += "\"rssi\":" + String(apMode ? 0 : WiFi.RSSI()) + ","; // RSSI not applicable in AP mode
|
doc["rssi"] = apMode ? 0 : WiFi.RSSI();
|
||||||
json += "\"freeHeap\":" + String(ESP.getFreeHeap()) + ",";
|
doc["freeHeap"] = ESP.getFreeHeap();
|
||||||
json += "\"uptime\":" + String(millis() / 1000);
|
doc["uptime"] = millis() / 1000;
|
||||||
json += "}";
|
|
||||||
|
|
||||||
|
String json;
|
||||||
|
serializeJson(doc, json);
|
||||||
server->send(200, "application/json", json);
|
server->send(200, "application/json", json);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +229,7 @@ void CrossPointWebServer::scanFiles(const char* path, const std::function<void(F
|
|||||||
}
|
}
|
||||||
|
|
||||||
file.close();
|
file.close();
|
||||||
|
yield(); // Yield to allow WiFi and other tasks to process during long scans
|
||||||
file = root.openNextFile();
|
file = root.openNextFile();
|
||||||
}
|
}
|
||||||
root.close();
|
root.close();
|
||||||
@@ -254,12 +264,15 @@ void CrossPointWebServer::handleFileListData() const {
|
|||||||
char output[512];
|
char output[512];
|
||||||
constexpr size_t outputSize = sizeof(output);
|
constexpr size_t outputSize = sizeof(output);
|
||||||
bool seenFirst = false;
|
bool seenFirst = false;
|
||||||
scanFiles(currentPath.c_str(), [this, &output, seenFirst](const FileInfo& info) mutable {
|
JsonDocument doc;
|
||||||
JsonDocument doc;
|
|
||||||
|
scanFiles(currentPath.c_str(), [this, &output, &doc, seenFirst](const FileInfo& info) mutable {
|
||||||
|
doc.clear();
|
||||||
doc["name"] = info.name;
|
doc["name"] = info.name;
|
||||||
doc["size"] = info.size;
|
doc["size"] = info.size;
|
||||||
doc["isDirectory"] = info.isDirectory;
|
doc["isDirectory"] = info.isDirectory;
|
||||||
doc["isEpub"] = info.isEpub;
|
doc["isEpub"] = info.isEpub;
|
||||||
|
|
||||||
const size_t written = serializeJson(doc, output, outputSize);
|
const size_t written = serializeJson(doc, output, outputSize);
|
||||||
if (written >= outputSize) {
|
if (written >= outputSize) {
|
||||||
// JSON output truncated; skip this entry to avoid sending malformed JSON
|
// JSON output truncated; skip this entry to avoid sending malformed JSON
|
||||||
|
|||||||
Reference in New Issue
Block a user