Add watchdog resets and write buffer to Calibre Wireless mode

Apply the same stability fixes from WebSocket upload to Calibre:
- Add esp_task_wdt.h include and watchdog resets throughout
- Increase receive buffer from 1KB to 4KB for better throughput
- Add 4KB write buffer for batched SD writes (reduces write calls)
- Reset watchdog during file creation, network reads, and SD writes
- Reset watchdog every 16 iterations in JSON message reading loop
- Clean up write buffer on exit and error conditions
This commit is contained in:
Claude 2026-01-13 23:20:11 +00:00
parent 6e78a7037d
commit de730ca130
No known key found for this signature in database

View File

@ -16,6 +16,45 @@
namespace {
constexpr uint16_t UDP_PORTS[] = {54982, 48123, 39001, 44044, 59678};
constexpr uint16_t LOCAL_UDP_PORT = 8134; // Port to receive responses
// Write buffer for batched SD writes (improves throughput by reducing write calls)
constexpr size_t WRITE_BUFFER_SIZE = 4096; // 4KB buffer
static uint8_t writeBuffer[WRITE_BUFFER_SIZE];
static size_t writeBufferPos = 0;
static File* currentWriteFile = nullptr;
static bool flushWriteBuffer() {
if (writeBufferPos > 0 && currentWriteFile && *currentWriteFile) {
esp_task_wdt_reset();
const size_t written = currentWriteFile->write(writeBuffer, writeBufferPos);
esp_task_wdt_reset();
if (written != writeBufferPos) {
writeBufferPos = 0;
return false;
}
writeBufferPos = 0;
}
return true;
}
static bool bufferedWrite(const uint8_t* data, size_t len) {
while (len > 0) {
const size_t space = WRITE_BUFFER_SIZE - writeBufferPos;
const size_t toCopy = std::min(space, len);
memcpy(writeBuffer + writeBufferPos, data, toCopy);
writeBufferPos += toCopy;
data += toCopy;
len -= toCopy;
if (writeBufferPos >= WRITE_BUFFER_SIZE) {
if (!flushWriteBuffer()) {
return false;
}
}
}
return true;
}
} // namespace
void CalibreWirelessActivity::displayTaskTrampoline(void* param) {
@ -80,7 +119,9 @@ void CalibreWirelessActivity::onExit() {
tcpClient.stop();
}
// Close any open file to prevent corruption
// Flush write buffer and close any open file to prevent corruption
flushWriteBuffer();
currentWriteFile = nullptr;
if (currentFile) {
Serial.printf("[%lu] [CAL] Closing open file...\n", millis());
currentFile.flush();
@ -374,6 +415,7 @@ bool CalibreWirelessActivity::readJsonMessage(std::string& message) {
}
// Read in chunks
char buf[1024];
int iterations = 0;
while (available > 0) {
int toRead = std::min(available, static_cast<int>(sizeof(buf)));
int bytesRead = tcpClient.read(reinterpret_cast<uint8_t*>(buf), toRead);
@ -383,6 +425,10 @@ bool CalibreWirelessActivity::readJsonMessage(std::string& message) {
} else {
break;
}
// Reset watchdog every 16 iterations to prevent timeout during large reads
if ((++iterations & 0xF) == 0) {
esp_task_wdt_reset();
}
}
}
@ -655,12 +701,18 @@ void CalibreWirelessActivity::handleSendBook(const std::string& data) {
setState(WirelessState::RECEIVING);
setStatus("Receiving: " + filename);
// Open file for writing
// Open file for writing - reset watchdog as FAT allocation can be slow
esp_task_wdt_reset();
if (!SdMan.openFileForWrite("CAL", currentFilename.c_str(), currentFile)) {
setError("Failed to create file");
sendJsonResponse(OpCode::ERROR, "{\"message\":\"Failed to create file\"}");
return;
}
esp_task_wdt_reset();
// Initialize write buffer
currentWriteFile = &currentFile;
writeBufferPos = 0;
// Send OK to start receiving binary data
sendJsonResponse(OpCode::OK, "{}");
@ -672,11 +724,12 @@ void CalibreWirelessActivity::handleSendBook(const std::string& data) {
// Check if recvBuffer has leftover data (binary file data that arrived with the JSON)
if (!recvBuffer.empty()) {
size_t toWrite = std::min(recvBuffer.size(), binaryBytesRemaining);
size_t written = currentFile.write(reinterpret_cast<const uint8_t*>(recvBuffer.data()), toWrite);
bytesReceived += written;
binaryBytesRemaining -= written;
recvBuffer = recvBuffer.substr(toWrite);
updateRequired = true;
if (bufferedWrite(reinterpret_cast<const uint8_t*>(recvBuffer.data()), toWrite)) {
bytesReceived += toWrite;
binaryBytesRemaining -= toWrite;
recvBuffer = recvBuffer.substr(toWrite);
updateRequired = true;
}
}
}
@ -708,6 +761,8 @@ void CalibreWirelessActivity::receiveBinaryData() {
if (available == 0) {
// Check if connection is still alive
if (!tcpClient.connected()) {
flushWriteBuffer();
currentWriteFile = nullptr;
currentFile.close();
inBinaryMode = false;
setError("Transfer interrupted");
@ -715,18 +770,34 @@ void CalibreWirelessActivity::receiveBinaryData() {
return;
}
uint8_t buffer[1024];
// Use 4KB buffer for network reads
uint8_t buffer[4096];
const size_t toRead = std::min(sizeof(buffer), binaryBytesRemaining);
// Reset watchdog before network read
esp_task_wdt_reset();
const size_t bytesRead = tcpClient.read(buffer, toRead);
if (bytesRead > 0) {
currentFile.write(buffer, bytesRead);
// Use buffered write for better throughput
if (!bufferedWrite(buffer, bytesRead)) {
flushWriteBuffer();
currentWriteFile = nullptr;
currentFile.close();
inBinaryMode = false;
setError("Write error");
return;
}
bytesReceived += bytesRead;
binaryBytesRemaining -= bytesRead;
updateRequired = true;
if (binaryBytesRemaining == 0) {
// Transfer complete
// Transfer complete - flush remaining buffer
esp_task_wdt_reset();
flushWriteBuffer();
currentWriteFile = nullptr;
currentFile.flush();
currentFile.close();
inBinaryMode = false;