diff --git a/src/graphics/niche/Drivers/EInk/LCMEN2R13EFC1.cpp b/src/graphics/niche/Drivers/EInk/LCMEN2R13EFC1.cpp index 13a3f452d..fb37544b2 100644 --- a/src/graphics/niche/Drivers/EInk/LCMEN2R13EFC1.cpp +++ b/src/graphics/niche/Drivers/EInk/LCMEN2R13EFC1.cpp @@ -1,9 +1,11 @@ -#include "./LCMEN2R13EFC1.h" - #ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS +#include "./LCMEN2R13EFC1.h" + #include +#include "SPILock.h" + using namespace NicheGraphics::Drivers; // Look up table: fast refresh, common electrode @@ -150,6 +152,9 @@ void LCMEN213EFC1::reset() void LCMEN213EFC1::sendCommand(const uint8_t command) { + // Take firmware's SPI lock + spiLock->lock(); + spi->beginTransaction(spiSettings); digitalWrite(pin_dc, LOW); // DC pin low indicates command digitalWrite(pin_cs, LOW); @@ -157,6 +162,8 @@ void LCMEN213EFC1::sendCommand(const uint8_t command) digitalWrite(pin_cs, HIGH); digitalWrite(pin_dc, HIGH); spi->endTransaction(); + + spiLock->unlock(); } void LCMEN213EFC1::sendData(uint8_t data) @@ -166,6 +173,9 @@ void LCMEN213EFC1::sendData(uint8_t data) void LCMEN213EFC1::sendData(const uint8_t *data, uint32_t size) { + // Take firmware's SPI lock + spiLock->lock(); + spi->beginTransaction(spiSettings); digitalWrite(pin_dc, HIGH); // DC pin HIGH indicates data, instead of command digitalWrite(pin_cs, LOW); @@ -183,6 +193,8 @@ void LCMEN213EFC1::sendData(const uint8_t *data, uint32_t size) digitalWrite(pin_cs, HIGH); digitalWrite(pin_dc, HIGH); spi->endTransaction(); + + spiLock->unlock(); } void LCMEN213EFC1::configFull() diff --git a/src/graphics/niche/Drivers/EInk/SSD16XX.cpp b/src/graphics/niche/Drivers/EInk/SSD16XX.cpp index a2357a80b..d0d030be8 100644 --- a/src/graphics/niche/Drivers/EInk/SSD16XX.cpp +++ b/src/graphics/niche/Drivers/EInk/SSD16XX.cpp @@ -1,6 +1,9 @@ +#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS + #include "./SSD16XX.h" -#ifdef MESHTASTIC_INCLUDE_NICHE_GRAPHICS +#include "SPILock.h" + using namespace NicheGraphics::Drivers; SSD16XX::SSD16XX(uint16_t width, uint16_t height, UpdateTypes supported, uint8_t bufferOffsetX) @@ -82,6 +85,9 @@ void SSD16XX::sendCommand(const uint8_t command) if (failed) return; + // Take firmware's SPI lock + spiLock->lock(); + spi->beginTransaction(spiSettings); digitalWrite(pin_dc, LOW); // DC pin low indicates command digitalWrite(pin_cs, LOW); @@ -89,6 +95,8 @@ void SSD16XX::sendCommand(const uint8_t command) digitalWrite(pin_cs, HIGH); digitalWrite(pin_dc, HIGH); spi->endTransaction(); + + spiLock->unlock(); } void SSD16XX::sendData(uint8_t data) @@ -103,6 +111,9 @@ void SSD16XX::sendData(const uint8_t *data, uint32_t size) if (failed) return; + // Take firmware's SPI lock + spiLock->lock(); + spi->beginTransaction(spiSettings); digitalWrite(pin_dc, HIGH); // DC pin HIGH indicates data, instead of command digitalWrite(pin_cs, LOW); @@ -119,6 +130,8 @@ void SSD16XX::sendData(const uint8_t *data, uint32_t size) digitalWrite(pin_cs, HIGH); digitalWrite(pin_dc, HIGH); spi->endTransaction(); + + spiLock->unlock(); } void SSD16XX::configFullscreen() diff --git a/src/graphics/niche/FlashData.h b/src/graphics/niche/FlashData.h index a27c4aea0..233d0922e 100644 --- a/src/graphics/niche/FlashData.h +++ b/src/graphics/niche/FlashData.h @@ -13,6 +13,7 @@ Avoid bloating everyone's protobuf code for our one-off UI implementations #include "configuration.h" +#include "SPILock.h" #include "SafeFile.h" namespace NicheGraphics @@ -46,6 +47,9 @@ template class FlashData public: static bool load(T *data, const char *label) { + // Take firmware's SPI lock + concurrency::LockGuard guard(spiLock); + // Set false if we run into issues bool okay = true; @@ -103,14 +107,18 @@ template class FlashData return okay; } - // Save module's custom data (settings?) to flash. Does use protobufs + // Save module's custom data (settings?) to flash. Doesn't use protobufs + // Takes the firmware's SPI lock, in case the files are stored on SD card + // Need to lock and unlock around specific FS methods, as the SafeFile class takes the lock for itself internally. static void save(T *data, const char *label) { // Get a filename based on the label std::string filename = getFilename(label); #ifdef FSCom + spiLock->lock(); FSCom.mkdir("/NicheGraphics"); + spiLock->unlock(); auto f = SafeFile(filename.c_str(), true); // "true": full atomic. Write new data to temp file, then rename. @@ -119,10 +127,10 @@ template class FlashData // Calculate a hash of the data uint32_t hash = getHash(data); + spiLock->lock(); f.write((uint8_t *)data, sizeof(T)); // Write the actual data f.write((uint8_t *)&hash, sizeof(hash)); // Append the hash - - // f.flush(); + spiLock->unlock(); bool writeSucceeded = f.close(); @@ -139,6 +147,9 @@ template class FlashData inline void clearFlashData() { + // Take firmware's SPI lock, in case the files are stored on SD card + concurrency::LockGuard guard(spiLock); + #ifdef FSCom File dir = FSCom.open("/NicheGraphics"); // Open the directory File file = dir.openNextFile(); // Attempt to open the first file in the directory diff --git a/src/graphics/niche/InkHUD/MessageStore.cpp b/src/graphics/niche/InkHUD/MessageStore.cpp index ac6fe1b35..94e0aa661 100644 --- a/src/graphics/niche/InkHUD/MessageStore.cpp +++ b/src/graphics/niche/InkHUD/MessageStore.cpp @@ -22,6 +22,8 @@ InkHUD::MessageStore::MessageStore(std::string label) } // Write the contents of the MessageStore::messages object to flash +// Takes the firmware's SPI lock during FS operations. Implemented for consistency, but only relevant when using SD card. +// Need to lock and unlock around specific FS methods, as the SafeFile class takes the lock for itself internally void InkHUD::MessageStore::saveToFlash() { assert(!filename.empty()); @@ -29,7 +31,9 @@ void InkHUD::MessageStore::saveToFlash() #ifdef FSCom // Make the directory, if doesn't already exist // This is the same directory accessed by NicheGraphics::FlashData + spiLock->lock(); FSCom.mkdir("/NicheGraphics"); + spiLock->unlock(); // Open or create the file // No "full atomic": don't save then rename @@ -37,6 +41,9 @@ void InkHUD::MessageStore::saveToFlash() LOG_INFO("Saving messages in %s", filename.c_str()); + // Take firmware's SPI Lock while writing + spiLock->lock(); + // 1st byte: how many messages will be written to store f.write(messages.size()); @@ -51,6 +58,9 @@ void InkHUD::MessageStore::saveToFlash() LOG_DEBUG("Wrote message %u, length %u, text \"%s\"", (uint32_t)i, min(MAX_MESSAGE_SIZE, m.text.size()), m.text.c_str()); } + // Release firmware's SPI lock, because SafeFile::close needs it + spiLock->unlock(); + bool writeSucceeded = f.close(); if (!writeSucceeded) { @@ -63,6 +73,7 @@ void InkHUD::MessageStore::saveToFlash() // Attempt to load the previous contents of the MessageStore:message deque from flash. // Filename is controlled by the "label" parameter +// Takes the firmware's SPI lock during FS operations. Implemented for consistency, but only relevant when using SD card. void InkHUD::MessageStore::loadFromFlash() { // Hopefully redundant. Initial intention is to only load / save once per boot. @@ -70,6 +81,9 @@ void InkHUD::MessageStore::loadFromFlash() #ifdef FSCom + // Take the firmware's SPI Lock, in case filesystem is on SD card + concurrency::LockGuard guard(spiLock); + // Check that the file *does* actually exist if (!FSCom.exists(filename.c_str())) { LOG_WARN("'%s' not found. Using default values", filename.c_str());