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
QRCode @ 0.0.1
links2004/WebSockets @ ^2.4.1
mathieucarbou/AsyncTCP @ ^3.2.14
[env:default]
extends = base

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
#pragma once
#include <AsyncTCP.h>
#include <SDCardManager.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
@ -18,6 +18,8 @@
* Protocol specification sourced from Calibre's smart device driver:
* 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:
* 1. Device broadcasts "hello" on UDP ports 54982, 48123, 39001, 44044, 59678
* 2. Calibre responds with its TCP server address
@ -50,7 +52,7 @@ class CalibreWirelessActivity final : public Activity {
SEND_BOOK = 8,
GET_INITIALIZATION_INFO = 9,
BOOK_DONE = 11,
NOOP = 12, // Was incorrectly 18
NOOP = 12,
DELETE_BOOK = 13,
GET_BOOK_FILE_SEGMENT = 14,
GET_BOOK_METADATA = 15,
@ -62,23 +64,23 @@ class CalibreWirelessActivity final : public Activity {
};
TaskHandle_t displayTaskHandle = nullptr;
TaskHandle_t networkTaskHandle = nullptr;
TaskHandle_t discoveryTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
SemaphoreHandle_t stateMutex = nullptr;
SemaphoreHandle_t dataMutex = nullptr; // Protects shared data accessed from callbacks
bool updateRequired = false;
volatile bool shouldExit = false; // Signal for tasks to exit gracefully
volatile bool shouldExit = false;
WirelessState state = WirelessState::DISCOVERING;
const std::function<void()> onComplete;
const std::function<void()> onCompleteCallback;
// UDP discovery
WiFiUDP udp;
// TCP connection (we connect to Calibre)
WiFiClient tcpClient;
// Async TCP connection
AsyncClient* tcpClient = nullptr;
std::string calibreHost;
uint16_t calibrePort = 0;
uint16_t calibreAltPort = 0; // Alternative port (content server)
uint16_t calibreAltPort = 0;
std::string calibreHostname;
// Transfer state
@ -94,26 +96,36 @@ class CalibreWirelessActivity final : public Activity {
FsFile currentFile;
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;
size_t skipBytesRemaining = 0;
int skipOpcode = -1; // Opcode of message being skipped
int skipOpcode = -1;
std::string skipExtractedLpath;
size_t skipExtractedLength = 0;
// Display task
static void displayTaskTrampoline(void* param);
static void networkTaskTrampoline(void* param);
[[noreturn]] void displayTaskLoop();
[[noreturn]] void networkTaskLoop();
void displayTaskLoop();
void render() const;
// Network operations
void listenForDiscovery();
void handleTcpClient();
bool readJsonMessage(std::string& message);
// Discovery task (UDP is not async)
static void discoveryTaskTrampoline(void* param);
void discoveryTaskLoop();
// 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 handleCommand(OpCode opcode, const std::string& data);
void receiveBinaryData();
// Protocol handlers
void handleGetInitializationInfo(const std::string& data);
@ -130,11 +142,12 @@ class CalibreWirelessActivity final : public Activity {
void setState(WirelessState newState);
void setStatus(const std::string& message);
void setError(const std::string& message);
void connectToCalibr();
public:
explicit CalibreWirelessActivity(GfxRenderer& renderer, MappedInputManager& mappedInput,
const std::function<void()>& onComplete)
: Activity("CalibreWireless", renderer, mappedInput), onComplete(onComplete) {}
: Activity("CalibreWireless", renderer, mappedInput), onCompleteCallback(onComplete) {}
void onEnter() override;
void onExit() override;
void loop() override;