Avoid leaving screens mid-display update

Was leave the EPD in a bad state, blocking further actions
This commit is contained in:
Dave Allie 2025-12-06 03:02:52 +11:00
parent 98c8e7e77c
commit 899caab70c
No known key found for this signature in database
GPG Key ID: F2FDDB3AD8D0276F
4 changed files with 24 additions and 13 deletions

View File

@ -18,7 +18,7 @@ void EpubReaderScreen::onEnter() {
return; return;
} }
sectionMutex = xSemaphoreCreateMutex(); renderingMutex = xSemaphoreCreateMutex();
epub->setupCacheDir(); epub->setupCacheDir();
@ -45,13 +45,14 @@ void EpubReaderScreen::onEnter() {
} }
void EpubReaderScreen::onExit() { void EpubReaderScreen::onExit() {
xSemaphoreTake(sectionMutex, portMAX_DELAY); // Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) { if (displayTaskHandle) {
vTaskDelete(displayTaskHandle); vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr; displayTaskHandle = nullptr;
} }
vSemaphoreDelete(sectionMutex); vSemaphoreDelete(renderingMutex);
sectionMutex = nullptr; renderingMutex = nullptr;
delete section; delete section;
section = nullptr; section = nullptr;
delete epub; delete epub;
@ -82,23 +83,25 @@ void EpubReaderScreen::handleInput(const Input input) {
if (section->currentPage > 0) { if (section->currentPage > 0) {
section->currentPage--; section->currentPage--;
} else { } else {
xSemaphoreTake(sectionMutex, portMAX_DELAY); // We don't want to delete the section mid-render, so grab the semaphore
xSemaphoreTake(renderingMutex, portMAX_DELAY);
nextPageNumber = UINT16_MAX; nextPageNumber = UINT16_MAX;
currentSpineIndex--; currentSpineIndex--;
delete section; delete section;
section = nullptr; section = nullptr;
xSemaphoreGive(sectionMutex); xSemaphoreGive(renderingMutex);
} }
} else if (input.button == VOLUME_DOWN || input.button == RIGHT) { } else if (input.button == VOLUME_DOWN || input.button == RIGHT) {
if (section->currentPage < section->pageCount - 1) { if (section->currentPage < section->pageCount - 1) {
section->currentPage++; section->currentPage++;
} else { } else {
xSemaphoreTake(sectionMutex, portMAX_DELAY); // We don't want to delete the section mid-render, so grab the semaphore
xSemaphoreTake(renderingMutex, portMAX_DELAY);
nextPageNumber = 0; nextPageNumber = 0;
currentSpineIndex++; currentSpineIndex++;
delete section; delete section;
section = nullptr; section = nullptr;
xSemaphoreGive(sectionMutex); xSemaphoreGive(renderingMutex);
} }
} }
@ -112,7 +115,9 @@ void EpubReaderScreen::displayTaskLoop() {
while (true) { while (true) {
if (updateRequired) { if (updateRequired) {
updateRequired = false; updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY);
renderPage(); renderPage();
xSemaphoreGive(renderingMutex);
} }
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
} }
@ -127,7 +132,6 @@ void EpubReaderScreen::renderPage() {
currentSpineIndex = 0; currentSpineIndex = 0;
} }
xSemaphoreTake(sectionMutex, portMAX_DELAY);
if (!section) { if (!section) {
const auto filepath = epub->getSpineItem(currentSpineIndex); const auto filepath = epub->getSpineItem(currentSpineIndex);
Serial.printf("Loading file: %s, index: %d\n", filepath.c_str(), currentSpineIndex); Serial.printf("Loading file: %s, index: %d\n", filepath.c_str(), currentSpineIndex);
@ -153,7 +157,6 @@ void EpubReaderScreen::renderPage() {
Serial.println("Failed to persist page data to SD"); Serial.println("Failed to persist page data to SD");
delete section; delete section;
section = nullptr; section = nullptr;
xSemaphoreGive(sectionMutex);
return; return;
} }
} else { } else {
@ -186,8 +189,6 @@ void EpubReaderScreen::renderPage() {
data[3] = (section->currentPage >> 8) & 0xFF; data[3] = (section->currentPage >> 8) & 0xFF;
f.write(data, 4); f.write(data, 4);
f.close(); f.close();
xSemaphoreGive(sectionMutex);
} }
void EpubReaderScreen::renderStatusBar() const { void EpubReaderScreen::renderStatusBar() const {

View File

@ -11,7 +11,7 @@ class EpubReaderScreen final : public Screen {
Epub* epub; Epub* epub;
Section* section = nullptr; Section* section = nullptr;
TaskHandle_t displayTaskHandle = nullptr; TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t sectionMutex = nullptr; SemaphoreHandle_t renderingMutex = nullptr;
int currentSpineIndex = 0; int currentSpineIndex = 0;
int nextPageNumber = 0; int nextPageNumber = 0;
int pagesUntilFullRefresh = 0; int pagesUntilFullRefresh = 0;

View File

@ -30,6 +30,8 @@ void FileSelectionScreen::loadFiles() {
} }
void FileSelectionScreen::onEnter() { void FileSelectionScreen::onEnter() {
renderingMutex = xSemaphoreCreateMutex();
basepath = "/"; basepath = "/";
loadFiles(); loadFiles();
selectorIndex = 0; selectorIndex = 0;
@ -46,10 +48,14 @@ void FileSelectionScreen::onEnter() {
} }
void FileSelectionScreen::onExit() { void FileSelectionScreen::onExit() {
// Wait until not rendering to delete task to avoid killing mid-instruction to EPD
xSemaphoreTake(renderingMutex, portMAX_DELAY);
if (displayTaskHandle) { if (displayTaskHandle) {
vTaskDelete(displayTaskHandle); vTaskDelete(displayTaskHandle);
displayTaskHandle = nullptr; displayTaskHandle = nullptr;
} }
vSemaphoreDelete(renderingMutex);
renderingMutex = nullptr;
files.clear(); files.clear();
} }
@ -85,7 +91,9 @@ void FileSelectionScreen::displayTaskLoop() {
while (true) { while (true) {
if (updateRequired) { if (updateRequired) {
updateRequired = false; updateRequired = false;
xSemaphoreTake(renderingMutex, portMAX_DELAY);
render(); render();
xSemaphoreGive(renderingMutex);
} }
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
#include <freertos/semphr.h>
#include <functional> #include <functional>
#include <string> #include <string>
@ -10,6 +11,7 @@
class FileSelectionScreen final : public Screen { class FileSelectionScreen final : public Screen {
TaskHandle_t displayTaskHandle = nullptr; TaskHandle_t displayTaskHandle = nullptr;
SemaphoreHandle_t renderingMutex = nullptr;
std::string basepath = "/"; std::string basepath = "/";
std::vector<std::string> files; std::vector<std::string> files;
int selectorIndex = 0; int selectorIndex = 0;