fixes crash on back

This commit is contained in:
Justin Mitchell 2026-01-14 13:25:33 -05:00
parent 0fa57a6bb4
commit 0313259998
2 changed files with 49 additions and 24 deletions

View File

@ -50,6 +50,7 @@ void CalibreWirelessActivity::onEnter() {
skipOpcode = -1; skipOpcode = -1;
skipExtractedLpath.clear(); skipExtractedLpath.clear();
skipExtractedLength = 0; skipExtractedLength = 0;
shouldExit = false;
updateRequired = true; updateRequired = true;
@ -66,30 +67,27 @@ void CalibreWirelessActivity::onEnter() {
void CalibreWirelessActivity::onExit() { void CalibreWirelessActivity::onExit() {
Activity::onExit(); Activity::onExit();
// Stop network task FIRST before touching any shared state // Signal tasks to exit gracefully FIRST
// This prevents the task from accessing members while we clean up shouldExit = true;
if (networkTaskHandle) {
vTaskDelete(networkTaskHandle);
networkTaskHandle = nullptr;
}
// Stop display task // Small delay to let tasks see the flag
if (displayTaskHandle) { vTaskDelay(50 / portTICK_PERIOD_MS);
vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr;
}
// Now safe to clean up - tasks are stopped // Close TCP to unblock any pending reads in the network task
// Turn off WiFi when exiting
WiFi.mode(WIFI_OFF);
// Stop UDP listening
udp.stop();
// Close TCP client if connected
if (tcpClient.connected()) { if (tcpClient.connected()) {
tcpClient.stop(); tcpClient.stop();
} }
udp.stop();
// Give tasks more time to notice the closed connection and exit
vTaskDelay(250 / portTICK_PERIOD_MS);
// Clear task handles (tasks self-deleted)
networkTaskHandle = nullptr;
displayTaskHandle = nullptr;
// Turn off WiFi when exiting
WiFi.mode(WIFI_OFF);
// Close any open file // Close any open file
if (currentFile) { if (currentFile) {
@ -122,23 +120,28 @@ void CalibreWirelessActivity::loop() {
} }
void CalibreWirelessActivity::displayTaskLoop() { void CalibreWirelessActivity::displayTaskLoop() {
while (true) { while (!shouldExit) {
if (updateRequired) { if (updateRequired) {
updateRequired = false; updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY); xSemaphoreTake(renderingMutex, portMAX_DELAY);
render(); if (!shouldExit) { // Double-check after acquiring mutex
render();
}
xSemaphoreGive(renderingMutex); xSemaphoreGive(renderingMutex);
} }
vTaskDelay(50 / portTICK_PERIOD_MS); vTaskDelay(50 / portTICK_PERIOD_MS);
} }
vTaskDelete(nullptr); // Self-delete when done
} }
void CalibreWirelessActivity::networkTaskLoop() { void CalibreWirelessActivity::networkTaskLoop() {
while (true) { while (!shouldExit) {
xSemaphoreTake(stateMutex, portMAX_DELAY); xSemaphoreTake(stateMutex, portMAX_DELAY);
const auto currentState = state; const auto currentState = state;
xSemaphoreGive(stateMutex); xSemaphoreGive(stateMutex);
if (shouldExit) break;
switch (currentState) { switch (currentState) {
case WirelessState::DISCOVERING: case WirelessState::DISCOVERING:
listenForDiscovery(); listenForDiscovery();
@ -160,6 +163,7 @@ void CalibreWirelessActivity::networkTaskLoop() {
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
} }
vTaskDelete(nullptr); // Self-delete when done
} }
void CalibreWirelessActivity::listenForDiscovery() { void CalibreWirelessActivity::listenForDiscovery() {
@ -802,7 +806,8 @@ void CalibreWirelessActivity::handleSendBook(const std::string& data) {
currentFileSize = length; currentFileSize = length;
bytesReceived = 0; bytesReceived = 0;
Serial.printf("[%lu] [CAL] SEND_BOOK: lpath='%s', length=%zu\n", millis(), lpath.c_str(), length); Serial.printf("[%lu] [CAL] SEND_BOOK: lpath='%s', length=%zu, recvBuffer leftover=%zu\n",
millis(), lpath.c_str(), length, recvBuffer.size());
setState(WirelessState::RECEIVING); setState(WirelessState::RECEIVING);
setStatus("Receiving: " + filename); setStatus("Receiving: " + filename);
@ -824,11 +829,18 @@ void CalibreWirelessActivity::handleSendBook(const std::string& data) {
// Check if recvBuffer has leftover data (binary file data that arrived with the JSON) // Check if recvBuffer has leftover data (binary file data that arrived with the JSON)
if (!recvBuffer.empty()) { if (!recvBuffer.empty()) {
size_t toWrite = std::min(recvBuffer.size(), binaryBytesRemaining); size_t toWrite = std::min(recvBuffer.size(), binaryBytesRemaining);
Serial.printf("[%lu] [CAL] Writing %zu bytes from recvBuffer (had %zu bytes)\n",
millis(), toWrite, recvBuffer.size());
size_t written = currentFile.write(reinterpret_cast<const uint8_t*>(recvBuffer.data()), toWrite); size_t written = currentFile.write(reinterpret_cast<const uint8_t*>(recvBuffer.data()), toWrite);
if (written != toWrite) {
Serial.printf("[%lu] [CAL] WARNING: file.write returned %zu, expected %zu\n", millis(), written, toWrite);
}
bytesReceived += written; bytesReceived += written;
binaryBytesRemaining -= written; binaryBytesRemaining -= written;
recvBuffer = recvBuffer.substr(toWrite); recvBuffer = recvBuffer.substr(written); // Use written, not toWrite!
updateRequired = true; updateRequired = true;
Serial.printf("[%lu] [CAL] After recvBuffer write: received=%zu, remaining=%zu, recvBuffer=%zu\n",
millis(), bytesReceived, binaryBytesRemaining, recvBuffer.size());
} }
} }
@ -856,11 +868,23 @@ void CalibreWirelessActivity::handleNoop(const std::string& data) {
} }
void CalibreWirelessActivity::receiveBinaryData() { void CalibreWirelessActivity::receiveBinaryData() {
static unsigned long lastProgressLog = 0;
// Read all available data in a loop to prevent TCP backpressure // Read all available data in a loop to prevent TCP backpressure
// This is important because Calibre sends data continuously // This is important because Calibre sends data continuously
while (binaryBytesRemaining > 0) { while (binaryBytesRemaining > 0) {
if (shouldExit) return;
const int available = tcpClient.available(); const int available = tcpClient.available();
if (available == 0) { if (available == 0) {
// Log progress periodically when waiting for data
if (millis() - lastProgressLog > 2000) {
Serial.printf("[%lu] [CAL] Binary transfer waiting: %zu/%zu bytes (%.1f%%), remaining=%zu\n",
millis(), bytesReceived, currentFileSize,
currentFileSize > 0 ? (100.0 * bytesReceived / currentFileSize) : 0.0,
binaryBytesRemaining);
lastProgressLog = millis();
}
// Check if connection is still alive // Check if connection is still alive
if (!tcpClient.connected()) { if (!tcpClient.connected()) {
Serial.printf("[%lu] [CAL] Connection lost during binary transfer. Received %zu/%zu bytes\n", Serial.printf("[%lu] [CAL] Connection lost during binary transfer. Received %zu/%zu bytes\n",

View File

@ -66,6 +66,7 @@ class CalibreWirelessActivity final : public Activity {
SemaphoreHandle_t renderingMutex = nullptr; SemaphoreHandle_t renderingMutex = nullptr;
SemaphoreHandle_t stateMutex = nullptr; SemaphoreHandle_t stateMutex = nullptr;
bool updateRequired = false; bool updateRequired = false;
volatile bool shouldExit = false; // Signal for tasks to exit gracefully
WirelessState state = WirelessState::DISCOVERING; WirelessState state = WirelessState::DISCOVERING;
const std::function<void()> onComplete; const std::function<void()> onComplete;