changes how we interact with calibre

This commit is contained in:
Justin Mitchell 2026-01-14 14:18:58 -05:00
parent 0313259998
commit dce9f7dd4d
3 changed files with 402 additions and 491 deletions

View File

@ -48,6 +48,7 @@ lib_deps =
ArduinoJson @ 7.4.2 ArduinoJson @ 7.4.2
QRCode @ 0.0.1 QRCode @ 0.0.1
links2004/WebSockets @ ^2.4.1 links2004/WebSockets @ ^2.4.1
mathieucarbou/AsyncTCP @ ^3.2.14
[env:default] [env:default]
extends = base extends = base

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include <AsyncTCP.h>
#include <SDCardManager.h> #include <SDCardManager.h>
#include <WiFiClient.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/semphr.h> #include <freertos/semphr.h>
@ -18,6 +18,8 @@
* Protocol specification sourced from Calibre's smart device driver: * Protocol specification sourced from Calibre's smart device driver:
* https://github.com/kovidgoyal/calibre/blob/master/src/calibre/devices/smart_device_app/driver.py * https://github.com/kovidgoyal/calibre/blob/master/src/calibre/devices/smart_device_app/driver.py
* *
* Uses AsyncTCP for callback-based networking (like KOReader's StreamMessageQueue).
*
* Protocol overview: * Protocol overview:
* 1. Device broadcasts "hello" on UDP ports 54982, 48123, 39001, 44044, 59678 * 1. Device broadcasts "hello" on UDP ports 54982, 48123, 39001, 44044, 59678
* 2. Calibre responds with its TCP server address * 2. Calibre responds with its TCP server address
@ -50,7 +52,7 @@ class CalibreWirelessActivity final : public Activity {
SEND_BOOK = 8, SEND_BOOK = 8,
GET_INITIALIZATION_INFO = 9, GET_INITIALIZATION_INFO = 9,
BOOK_DONE = 11, BOOK_DONE = 11,
NOOP = 12, // Was incorrectly 18 NOOP = 12,
DELETE_BOOK = 13, DELETE_BOOK = 13,
GET_BOOK_FILE_SEGMENT = 14, GET_BOOK_FILE_SEGMENT = 14,
GET_BOOK_METADATA = 15, GET_BOOK_METADATA = 15,
@ -62,23 +64,23 @@ class CalibreWirelessActivity final : public Activity {
}; };
TaskHandle_t displayTaskHandle = nullptr; TaskHandle_t displayTaskHandle = nullptr;
TaskHandle_t networkTaskHandle = nullptr; TaskHandle_t discoveryTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr; SemaphoreHandle_t renderingMutex = nullptr;
SemaphoreHandle_t stateMutex = nullptr; SemaphoreHandle_t dataMutex = nullptr; // Protects shared data accessed from callbacks
bool updateRequired = false; bool updateRequired = false;
volatile bool shouldExit = false; // Signal for tasks to exit gracefully volatile bool shouldExit = false;
WirelessState state = WirelessState::DISCOVERING; WirelessState state = WirelessState::DISCOVERING;
const std::function<void()> onComplete; const std::function<void()> onCompleteCallback;
// UDP discovery // UDP discovery
WiFiUDP udp; WiFiUDP udp;
// TCP connection (we connect to Calibre) // Async TCP connection
WiFiClient tcpClient; AsyncClient* tcpClient = nullptr;
std::string calibreHost; std::string calibreHost;
uint16_t calibrePort = 0; uint16_t calibrePort = 0;
uint16_t calibreAltPort = 0; // Alternative port (content server) uint16_t calibreAltPort = 0;
std::string calibreHostname; std::string calibreHostname;
// Transfer state // Transfer state
@ -94,26 +96,36 @@ class CalibreWirelessActivity final : public Activity {
FsFile currentFile; FsFile currentFile;
std::string recvBuffer; // Buffer for incoming data (like KOReader) std::string recvBuffer; // Buffer for incoming data (like KOReader)
// Large message skip state - for streaming past oversized JSON (e.g., large covers) // Large message skip state
bool inSkipMode = false; bool inSkipMode = false;
size_t skipBytesRemaining = 0; size_t skipBytesRemaining = 0;
int skipOpcode = -1; // Opcode of message being skipped int skipOpcode = -1;
std::string skipExtractedLpath; std::string skipExtractedLpath;
size_t skipExtractedLength = 0; size_t skipExtractedLength = 0;
// Display task
static void displayTaskTrampoline(void* param); static void displayTaskTrampoline(void* param);
static void networkTaskTrampoline(void* param); void displayTaskLoop();
[[noreturn]] void displayTaskLoop();
[[noreturn]] void networkTaskLoop();
void render() const; void render() const;
// Network operations // Discovery task (UDP is not async)
void listenForDiscovery(); static void discoveryTaskTrampoline(void* param);
void handleTcpClient(); void discoveryTaskLoop();
bool readJsonMessage(std::string& message);
// AsyncTCP callbacks
void onTcpConnect(AsyncClient* client);
void onTcpDisconnect(AsyncClient* client);
void onTcpData(AsyncClient* client, void* data, size_t len);
void onTcpError(AsyncClient* client, int8_t error);
// Data processing (called from onTcpData callback)
void processReceivedData();
void processBinaryData(const char* data, size_t len);
void processJsonData();
bool parseJsonMessage(std::string& message);
void sendJsonResponse(OpCode opcode, const std::string& data); void sendJsonResponse(OpCode opcode, const std::string& data);
void handleCommand(OpCode opcode, const std::string& data); void handleCommand(OpCode opcode, const std::string& data);
void receiveBinaryData();
// Protocol handlers // Protocol handlers
void handleGetInitializationInfo(const std::string& data); void handleGetInitializationInfo(const std::string& data);
@ -130,11 +142,12 @@ class CalibreWirelessActivity final : public Activity {
void setState(WirelessState newState); void setState(WirelessState newState);
void setStatus(const std::string& message); void setStatus(const std::string& message);
void setError(const std::string& message); void setError(const std::string& message);
void connectToCalibr();
public: public:
explicit CalibreWirelessActivity(GfxRenderer& renderer, MappedInputManager& mappedInput, explicit CalibreWirelessActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
const std::function<void()>& onComplete) const std::function<void()>& onComplete)
: Activity("CalibreWireless", renderer, mappedInput), onComplete(onComplete) {} : Activity("CalibreWireless", renderer, mappedInput), onCompleteCallback(onComplete) {}
void onEnter() override; void onEnter() override;
void onExit() override; void onExit() override;
void loop() override; void loop() override;