Cherrypick "add more locking for shared SPI devices (#5595) " (#5728)

* add more locking for shared SPI devices (#5595)

* add more locking for shared SPI devices
* call initSPI before the lock is used
* remove old one
* don't double lock
* Add missing unlock
* More missing unlocks
* Add locks to SafeFile, remove from `readcb`, introduce some LockGuards
* fix lock in setupSDCard()
* pull radiolib trunk with SPI-CS fixes
* change ContentHandler to Constructor type locks, where applicable

---------

Co-authored-by: mverch67 <manuel.verch@gmx.de>
Co-authored-by: GUVWAF <thijs@havinga.eu>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>

* mesh-tab: lower I2C touch frequency

---------

Co-authored-by: Thomas Göttgens <tgoettgens@gmail.com>
Co-authored-by: mverch67 <manuel.verch@gmx.de>
Co-authored-by: GUVWAF <thijs@havinga.eu>
Co-authored-by: Manuel <71137295+mverch67@users.noreply.github.com>
This commit is contained in:
Tom Fifield 2025-01-03 10:05:26 +08:00 committed by GitHub
parent 9d710041c4
commit e1aaafb77a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 125 additions and 22 deletions

View File

@ -124,7 +124,8 @@ lib_deps =
[radiolib_base] [radiolib_base]
lib_deps = lib_deps =
jgromes/RadioLib@7.1.0 ; jgromes/RadioLib@7.1.0
https://github.com/jgromes/RadioLib.git#92b687821ff4e6c358d866f84566f66672ab02b8
; Common libs for environmental measurements in telemetry module ; Common libs for environmental measurements in telemetry module
; (not included in native / portduino) ; (not included in native / portduino)

View File

@ -9,6 +9,7 @@
* *
*/ */
#include "FSCommon.h" #include "FSCommon.h"
#include "SPILock.h"
#include "configuration.h" #include "configuration.h"
#ifdef HAS_SDCARD #ifdef HAS_SDCARD
@ -102,6 +103,8 @@ bool copyFile(const char *from, const char *to)
return true; return true;
#elif defined(FSCom) #elif defined(FSCom)
// take SPI Lock
concurrency::LockGuard g(spiLock);
unsigned char cbuffer[16]; unsigned char cbuffer[16];
File f1 = FSCom.open(from, FILE_O_READ); File f1 = FSCom.open(from, FILE_O_READ);
@ -145,16 +148,23 @@ bool renameFile(const char *pathFrom, const char *pathTo)
return false; return false;
} }
#elif defined(FSCom) #elif defined(FSCom)
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
// take SPI Lock
spiLock->lock();
// rename was fixed for ESP32 IDF LittleFS in April // rename was fixed for ESP32 IDF LittleFS in April
return FSCom.rename(pathFrom, pathTo); bool result = FSCom.rename(pathFrom, pathTo);
spiLock->unlock();
return result;
#else #else
// copyFile does its own locking.
if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) { if (copyFile(pathFrom, pathTo) && FSCom.remove(pathFrom)) {
return true; return true;
} else { } else {
return false; return false;
} }
#endif #endif
#endif #endif
} }
@ -164,6 +174,7 @@ bool renameFile(const char *pathFrom, const char *pathTo)
* @brief Get the list of files in a directory. * @brief Get the list of files in a directory.
* *
* This function returns a list of files in a directory. The list includes the full path of each file. * This function returns a list of files in a directory. The list includes the full path of each file.
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
* *
* @param dirname The name of the directory. * @param dirname The name of the directory.
* @param levels The number of levels of subdirectories to list. * @param levels The number of levels of subdirectories to list.
@ -212,6 +223,7 @@ std::vector<meshtastic_FileInfo> getFiles(const char *dirname, uint8_t levels)
/** /**
* Lists the contents of a directory. * Lists the contents of a directory.
* We can't use SPILOCK here because of recursion. Callers of this function should use SPILOCK.
* *
* @param dirname The name of the directory to list. * @param dirname The name of the directory to list.
* @param levels The number of levels of subdirectories to list. * @param levels The number of levels of subdirectories to list.
@ -325,18 +337,21 @@ void listDir(const char *dirname, uint8_t levels, bool del)
void rmDir(const char *dirname) void rmDir(const char *dirname)
{ {
#ifdef FSCom #ifdef FSCom
#if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)) #if (defined(ARCH_ESP32) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO))
listDir(dirname, 10, true); listDir(dirname, 10, true);
#elif defined(ARCH_NRF52) #elif defined(ARCH_NRF52)
// nRF52 implementation of LittleFS has a recursive delete function // nRF52 implementation of LittleFS has a recursive delete function
FSCom.rmdir_r(dirname); FSCom.rmdir_r(dirname);
#endif #endif
#endif #endif
} }
void fsInit() void fsInit()
{ {
#ifdef FSCom #ifdef FSCom
spiLock->lock();
if (!FSBegin()) { if (!FSBegin()) {
LOG_ERROR("Filesystem mount failed"); LOG_ERROR("Filesystem mount failed");
// assert(0); This auto-formats the partition, so no need to fail here. // assert(0); This auto-formats the partition, so no need to fail here.
@ -347,6 +362,7 @@ void fsInit()
LOG_DEBUG("Filesystem files:"); LOG_DEBUG("Filesystem files:");
#endif #endif
listDir("/", 10); listDir("/", 10);
spiLock->unlock();
#endif #endif
} }
@ -356,6 +372,7 @@ void fsInit()
void setupSDCard() void setupSDCard()
{ {
#ifdef HAS_SDCARD #ifdef HAS_SDCARD
concurrency::LockGuard g(spiLock);
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI); SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
if (!SD.begin(SDCARD_CS, SDHandler)) { if (!SD.begin(SDCARD_CS, SDHandler)) {

View File

@ -5,6 +5,7 @@
// Only way to work on both esp32 and nrf52 // Only way to work on both esp32 and nrf52
static File openFile(const char *filename, bool fullAtomic) static File openFile(const char *filename, bool fullAtomic)
{ {
concurrency::LockGuard g(spiLock);
if (!fullAtomic) if (!fullAtomic)
FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists) FSCom.remove(filename); // Nuke the old file to make space (ignore if it !exists)
@ -53,14 +54,19 @@ bool SafeFile::close()
if (!f) if (!f)
return false; return false;
spiLock->lock();
f.close(); f.close();
spiLock->unlock();
if (!testReadback()) if (!testReadback())
return false; return false;
// brief window of risk here ;-) { // Scope for lock
if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) { concurrency::LockGuard g(spiLock);
LOG_ERROR("Can't remove old pref file"); // brief window of risk here ;-)
return false; if (fullAtomic && FSCom.exists(filename.c_str()) && !FSCom.remove(filename.c_str())) {
LOG_ERROR("Can't remove old pref file");
return false;
}
} }
String filenameTmp = filename; String filenameTmp = filename;
@ -76,6 +82,7 @@ bool SafeFile::close()
/// Read our (closed) tempfile back in and compare the hash /// Read our (closed) tempfile back in and compare the hash
bool SafeFile::testReadback() bool SafeFile::testReadback()
{ {
concurrency::LockGuard g(spiLock);
bool lfs_failed = lfs_assert_failed; bool lfs_failed = lfs_assert_failed;
lfs_assert_failed = false; lfs_assert_failed = false;

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "FSCommon.h" #include "FSCommon.h"
#include "SPILock.h"
#include "configuration.h" #include "configuration.h"
#ifdef FSCom #ifdef FSCom

View File

@ -364,6 +364,8 @@ void setup()
#endif #endif
#endif #endif
initSPI();
OSThread::setup(); OSThread::setup();
ledPeriodic = new Periodic("Blink", ledBlinker); ledPeriodic = new Periodic("Blink", ledBlinker);
@ -640,8 +642,6 @@ void setup()
rp2040Setup(); rp2040Setup();
#endif #endif
initSPI(); // needed here before reading from littleFS
// We do this as early as possible because this loads preferences from flash // We do this as early as possible because this loads preferences from flash
// but we need to do this after main cpu init (esp32setup), because we need the random seed set // but we need to do this after main cpu init (esp32setup), because we need the random seed set
nodeDB = new NodeDB; nodeDB = new NodeDB;

View File

@ -13,6 +13,7 @@
#include "PowerFSM.h" #include "PowerFSM.h"
#include "RTC.h" #include "RTC.h"
#include "Router.h" #include "Router.h"
#include "SPILock.h"
#include "SafeFile.h" #include "SafeFile.h"
#include "TypeConversions.h" #include "TypeConversions.h"
#include "error.h" #include "error.h"
@ -423,12 +424,15 @@ bool NodeDB::factoryReset(bool eraseBleBonds)
{ {
LOG_INFO("Perform factory reset!"); LOG_INFO("Perform factory reset!");
// first, remove the "/prefs" (this removes most prefs) // first, remove the "/prefs" (this removes most prefs)
rmDir("/prefs"); spiLock->lock();
rmDir("/prefs"); // this uses spilock internally...
#ifdef FSCom #ifdef FSCom
if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) { if (FSCom.exists("/static/rangetest.csv") && !FSCom.remove("/static/rangetest.csv")) {
LOG_ERROR("Could not remove rangetest.csv file"); LOG_ERROR("Could not remove rangetest.csv file");
} }
#endif #endif
spiLock->unlock();
// second, install default state (this will deal with the duplicate mac address issue) // second, install default state (this will deal with the duplicate mac address issue)
installDefaultDeviceState(); installDefaultDeviceState();
installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds installDefaultConfig(!eraseBleBonds); // Also preserve the private key if we're not erasing BLE bonds
@ -913,6 +917,7 @@ LoadFileResult NodeDB::loadProto(const char *filename, size_t protoSize, size_t
{ {
LoadFileResult state = LoadFileResult::OTHER_FAILURE; LoadFileResult state = LoadFileResult::OTHER_FAILURE;
#ifdef FSCom #ifdef FSCom
concurrency::LockGuard g(spiLock);
auto f = FSCom.open(filename, FILE_O_READ); auto f = FSCom.open(filename, FILE_O_READ);
@ -946,8 +951,10 @@ void NodeDB::loadFromDisk()
// disk we will still factoryReset to restore things. // disk we will still factoryReset to restore things.
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
spiLock->lock();
if (FSCom.exists("/static/static")) if (FSCom.exists("/static/static"))
rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release
spiLock->unlock();
#endif #endif
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
@ -1097,9 +1104,6 @@ void NodeDB::loadFromDisk()
bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct, bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct,
bool fullAtomic) bool fullAtomic)
{ {
#ifdef ARCH_ESP32
concurrency::LockGuard g(spiLock);
#endif
bool okay = false; bool okay = false;
#ifdef FSCom #ifdef FSCom
auto f = SafeFile(filename, fullAtomic); auto f = SafeFile(filename, fullAtomic);
@ -1127,7 +1131,9 @@ bool NodeDB::saveProto(const char *filename, size_t protoSize, const pb_msgdesc_
bool NodeDB::saveChannelsToDisk() bool NodeDB::saveChannelsToDisk()
{ {
#ifdef FSCom #ifdef FSCom
spiLock->lock();
FSCom.mkdir("/prefs"); FSCom.mkdir("/prefs");
spiLock->unlock();
#endif #endif
return saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile); return saveProto(channelFileName, meshtastic_ChannelFile_size, &meshtastic_ChannelFile_msg, &channelFile);
} }
@ -1135,7 +1141,9 @@ bool NodeDB::saveChannelsToDisk()
bool NodeDB::saveDeviceStateToDisk() bool NodeDB::saveDeviceStateToDisk()
{ {
#ifdef FSCom #ifdef FSCom
spiLock->lock();
FSCom.mkdir("/prefs"); FSCom.mkdir("/prefs");
spiLock->unlock();
#endif #endif
// Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB // Note: if MAX_NUM_NODES=100 and meshtastic_NodeInfoLite_size=166, so will be approximately 17KB
// Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this // Because so huge we _must_ not use fullAtomic, because the filesystem is probably too small to hold two copies of this
@ -1148,7 +1156,9 @@ bool NodeDB::saveToDiskNoRetry(int saveWhat)
bool success = true; bool success = true;
#ifdef FSCom #ifdef FSCom
spiLock->lock();
FSCom.mkdir("/prefs"); FSCom.mkdir("/prefs");
spiLock->unlock();
#endif #endif
if (saveWhat & SEGMENT_CONFIG) { if (saveWhat & SEGMENT_CONFIG) {
config.has_device = true; config.has_device = true;
@ -1199,7 +1209,9 @@ bool NodeDB::saveToDisk(int saveWhat)
if (!success) { if (!success) {
LOG_ERROR("Failed to save to disk, retrying"); LOG_ERROR("Failed to save to disk, retrying");
#ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion #ifdef ARCH_NRF52 // @geeksville is not ready yet to say we should do this on other platforms. See bug #4184 discussion
spiLock->lock();
FSCom.format(); FSCom.format();
spiLock->unlock();
#endif #endif
success = saveToDiskNoRetry(saveWhat); success = saveToDiskNoRetry(saveWhat);

View File

@ -12,6 +12,7 @@
#include "PhoneAPI.h" #include "PhoneAPI.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "RadioInterface.h" #include "RadioInterface.h"
#include "SPILock.h"
#include "TypeConversions.h" #include "TypeConversions.h"
#include "main.h" #include "main.h"
#include "xmodem.h" #include "xmodem.h"
@ -54,7 +55,9 @@ void PhoneAPI::handleStartConfig()
// even if we were already connected - restart our state machine // even if we were already connected - restart our state machine
state = STATE_SEND_MY_INFO; state = STATE_SEND_MY_INFO;
pauseBluetoothLogging = true; pauseBluetoothLogging = true;
spiLock->lock();
filesManifest = getFiles("/", 10); filesManifest = getFiles("/", 10);
spiLock->unlock();
LOG_DEBUG("Got %d files in manifest", filesManifest.size()); LOG_DEBUG("Got %d files in manifest", filesManifest.size());
LOG_INFO("Start API client config"); LOG_INFO("Start API client config");

View File

@ -10,6 +10,7 @@
#include "mesh/wifi/WiFiAPClient.h" #include "mesh/wifi/WiFiAPClient.h"
#endif #endif
#include "Led.h" #include "Led.h"
#include "SPILock.h"
#include "power.h" #include "power.h"
#include "serialization/JSON.h" #include "serialization/JSON.h"
#include <FSCommon.h> #include <FSCommon.h>
@ -236,6 +237,7 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res)
void htmlDeleteDir(const char *dirname) void htmlDeleteDir(const char *dirname)
{ {
File root = FSCom.open(dirname); File root = FSCom.open(dirname);
if (!root) { if (!root) {
return; return;
@ -318,6 +320,7 @@ void handleFsBrowseStatic(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "GET"); res->setHeader("Access-Control-Allow-Methods", "GET");
concurrency::LockGuard g(spiLock);
auto fileList = htmlListDir("/static", 10); auto fileList = htmlListDir("/static", 10);
// create json output structure // create json output structure
@ -349,9 +352,12 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
res->setHeader("Content-Type", "application/json"); res->setHeader("Content-Type", "application/json");
res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Origin", "*");
res->setHeader("Access-Control-Allow-Methods", "DELETE"); res->setHeader("Access-Control-Allow-Methods", "DELETE");
if (params->getQueryParameter("delete", paramValDelete)) { if (params->getQueryParameter("delete", paramValDelete)) {
std::string pathDelete = "/" + paramValDelete; std::string pathDelete = "/" + paramValDelete;
concurrency::LockGuard g(spiLock);
if (FSCom.remove(pathDelete.c_str())) { if (FSCom.remove(pathDelete.c_str())) {
LOG_INFO("%s", pathDelete.c_str()); LOG_INFO("%s", pathDelete.c_str());
JSONObject jsonObjOuter; JSONObject jsonObjOuter;
jsonObjOuter["status"] = new JSONValue("ok"); jsonObjOuter["status"] = new JSONValue("ok");
@ -360,6 +366,7 @@ void handleFsDeleteStatic(HTTPRequest *req, HTTPResponse *res)
delete value; delete value;
return; return;
} else { } else {
LOG_INFO("%s", pathDelete.c_str()); LOG_INFO("%s", pathDelete.c_str());
JSONObject jsonObjOuter; JSONObject jsonObjOuter;
jsonObjOuter["status"] = new JSONValue("Error"); jsonObjOuter["status"] = new JSONValue("Error");
@ -393,6 +400,8 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
filenameGzip = "/static/index.html.gz"; filenameGzip = "/static/index.html.gz";
} }
concurrency::LockGuard g(spiLock);
if (FSCom.exists(filename.c_str())) { if (FSCom.exists(filename.c_str())) {
file = FSCom.open(filename.c_str()); file = FSCom.open(filename.c_str());
if (!file.available()) { if (!file.available()) {
@ -410,6 +419,7 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res)
file = FSCom.open(filenameGzip.c_str()); file = FSCom.open(filenameGzip.c_str());
res->setHeader("Content-Type", "text/html"); res->setHeader("Content-Type", "text/html");
if (!file.available()) { if (!file.available()) {
LOG_WARN("File not available - %s", filenameGzip.c_str()); LOG_WARN("File not available - %s", filenameGzip.c_str());
res->println("Web server is running.<br><br>The content you are looking for can't be found. Please see: <a " res->println("Web server is running.<br><br>The content you are looking for can't be found. Please see: <a "
"href=https://meshtastic.org/docs/software/web-client/>FAQ</a>.<br><br><a " "href=https://meshtastic.org/docs/software/web-client/>FAQ</a>.<br><br><a "
@ -535,6 +545,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
// concepts of the body parser functionality easier to understand. // concepts of the body parser functionality easier to understand.
std::string pathname = "/static/" + filename; std::string pathname = "/static/" + filename;
concurrency::LockGuard g(spiLock);
// Create a new file to stream the data into // Create a new file to stream the data into
File file = FSCom.open(pathname.c_str(), FILE_O_WRITE); File file = FSCom.open(pathname.c_str(), FILE_O_WRITE);
size_t fileLength = 0; size_t fileLength = 0;
@ -571,6 +582,7 @@ void handleFormUpload(HTTPRequest *req, HTTPResponse *res)
file.flush(); file.flush();
file.close(); file.close();
res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, pathname.c_str()); res->printf("<p>Saved %d bytes to %s</p>", (int)fileLength, pathname.c_str());
} }
if (!didwrite) { if (!didwrite) {
@ -642,9 +654,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
jsonObjMemory["heap_free"] = new JSONValue((int)memGet.getFreeHeap()); jsonObjMemory["heap_free"] = new JSONValue((int)memGet.getFreeHeap());
jsonObjMemory["psram_total"] = new JSONValue((int)memGet.getPsramSize()); jsonObjMemory["psram_total"] = new JSONValue((int)memGet.getPsramSize());
jsonObjMemory["psram_free"] = new JSONValue((int)memGet.getFreePsram()); jsonObjMemory["psram_free"] = new JSONValue((int)memGet.getFreePsram());
spiLock->lock();
jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes()); jsonObjMemory["fs_total"] = new JSONValue((int)FSCom.totalBytes());
jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes()); jsonObjMemory["fs_used"] = new JSONValue((int)FSCom.usedBytes());
jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes())); jsonObjMemory["fs_free"] = new JSONValue(int(FSCom.totalBytes() - FSCom.usedBytes()));
spiLock->unlock();
// data->power // data->power
JSONObject jsonObjPower; JSONObject jsonObjPower;
@ -786,6 +800,7 @@ void handleDeleteFsContent(HTTPRequest *req, HTTPResponse *res)
LOG_INFO("Delete files from /static/* : "); LOG_INFO("Delete files from /static/* : ");
concurrency::LockGuard g(spiLock);
htmlDeleteDir("/static"); htmlDeleteDir("/static");
res->println("<p><hr><p><a href=/admin>Back to admin</a>"); res->println("<p><hr><p><a href=/admin>Back to admin</a>");

View File

@ -1,6 +1,7 @@
#include "configuration.h" #include "configuration.h"
#include "FSCommon.h" #include "FSCommon.h"
#include "SPILock.h"
#include "mesh-pb-constants.h" #include "mesh-pb-constants.h"
#include <Arduino.h> #include <Arduino.h>
#include <pb_decode.h> #include <pb_decode.h>
@ -55,9 +56,12 @@ bool readcb(pb_istream_t *stream, uint8_t *buf, size_t count)
/// Write to an arduino file /// Write to an arduino file
bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count) bool writecb(pb_ostream_t *stream, const uint8_t *buf, size_t count)
{ {
spiLock->lock();
auto file = (Print *)stream->state; auto file = (Print *)stream->state;
// LOG_DEBUG("writing %d bytes to protobuf file", count); // LOG_DEBUG("writing %d bytes to protobuf file", count);
return file->write(buf, count) == count; bool status = file->write(buf, count) == count;
spiLock->unlock();
return status;
} }
#endif #endif

View File

@ -4,6 +4,7 @@
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" #include "PowerFSM.h"
#include "RTC.h" #include "RTC.h"
#include "SPILock.h"
#include "meshUtils.h" #include "meshUtils.h"
#include <FSCommon.h> #include <FSCommon.h>
#if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH #if defined(ARCH_ESP32) && !MESHTASTIC_EXCLUDE_BLUETOOTH
@ -358,12 +359,15 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
} }
case meshtastic_AdminMessage_delete_file_request_tag: { case meshtastic_AdminMessage_delete_file_request_tag: {
LOG_DEBUG("Client requesting to delete file: %s", r->delete_file_request); LOG_DEBUG("Client requesting to delete file: %s", r->delete_file_request);
#ifdef FSCom #ifdef FSCom
spiLock->lock();
if (FSCom.remove(r->delete_file_request)) { if (FSCom.remove(r->delete_file_request)) {
LOG_DEBUG("Successfully deleted file"); LOG_DEBUG("Successfully deleted file");
} else { } else {
LOG_DEBUG("Failed to delete file"); LOG_DEBUG("Failed to delete file");
} }
spiLock->unlock();
#endif #endif
break; break;
} }

View File

@ -9,6 +9,7 @@
#include "MeshService.h" #include "MeshService.h"
#include "NodeDB.h" #include "NodeDB.h"
#include "PowerFSM.h" // needed for button bypass #include "PowerFSM.h" // needed for button bypass
#include "SPILock.h"
#include "detect/ScanI2C.h" #include "detect/ScanI2C.h"
#include "input/ScanAndSelect.h" #include "input/ScanAndSelect.h"
#include "mesh/generated/meshtastic/cannedmessages.pb.h" #include "mesh/generated/meshtastic/cannedmessages.pb.h"
@ -1184,8 +1185,10 @@ bool CannedMessageModule::saveProtoForModule()
{ {
bool okay = true; bool okay = true;
#ifdef FS #ifdef FSCom
FS.mkdir("/prefs"); spiLock->lock();
FSCom.mkdir("/prefs");
spiLock->unlock();
#endif #endif
okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size, okay &= nodeDB->saveProto(cannedMessagesConfigFile, meshtastic_CannedMessageModuleConfig_size,

View File

@ -15,6 +15,7 @@
#include "PowerFSM.h" #include "PowerFSM.h"
#include "RTC.h" #include "RTC.h"
#include "Router.h" #include "Router.h"
#include "SPILock.h"
#include "airtime.h" #include "airtime.h"
#include "configuration.h" #include "configuration.h"
#include "gps/GeoCoord.h" #include "gps/GeoCoord.h"
@ -205,6 +206,7 @@ bool RangeTestModuleRadio::appendFile(const meshtastic_MeshPacket &mp)
LOG_DEBUG("gpsStatus->getDOP() %d", gpsStatus->getDOP()); LOG_DEBUG("gpsStatus->getDOP() %d", gpsStatus->getDOP());
LOG_DEBUG("-----------------------------------------"); LOG_DEBUG("-----------------------------------------");
*/ */
concurrency::LockGuard g(spiLock);
if (!FSBegin()) { if (!FSBegin()) {
LOG_DEBUG("An Error has occurred while mounting the filesystem"); LOG_DEBUG("An Error has occurred while mounting the filesystem");
return 0; return 0;

View File

@ -5,6 +5,7 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "BME680Sensor.h" #include "BME680Sensor.h"
#include "FSCommon.h" #include "FSCommon.h"
#include "SPILock.h"
#include "TelemetrySensor.h" #include "TelemetrySensor.h"
BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {} BME680Sensor::BME680Sensor() : TelemetrySensor(meshtastic_TelemetrySensorType_BME680, "BME680") {}
@ -75,6 +76,7 @@ bool BME680Sensor::getMetrics(meshtastic_Telemetry *measurement)
void BME680Sensor::loadState() void BME680Sensor::loadState()
{ {
#ifdef FSCom #ifdef FSCom
spiLock->lock();
auto file = FSCom.open(bsecConfigFileName, FILE_O_READ); auto file = FSCom.open(bsecConfigFileName, FILE_O_READ);
if (file) { if (file) {
file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE); file.read((uint8_t *)&bsecState, BSEC_MAX_STATE_BLOB_SIZE);
@ -84,6 +86,7 @@ void BME680Sensor::loadState()
} else { } else {
LOG_INFO("No %s state found (File: %s)", sensorName, bsecConfigFileName); LOG_INFO("No %s state found (File: %s)", sensorName, bsecConfigFileName);
} }
spiLock->unlock();
#else #else
LOG_ERROR("ERROR: Filesystem not implemented"); LOG_ERROR("ERROR: Filesystem not implemented");
#endif #endif
@ -92,6 +95,7 @@ void BME680Sensor::loadState()
void BME680Sensor::updateState() void BME680Sensor::updateState()
{ {
#ifdef FSCom #ifdef FSCom
spiLock->lock();
bool update = false; bool update = false;
if (stateUpdateCounter == 0) { if (stateUpdateCounter == 0) {
/* First state update when IAQ accuracy is >= 3 */ /* First state update when IAQ accuracy is >= 3 */
@ -127,6 +131,7 @@ void BME680Sensor::updateState()
LOG_INFO("Can't write %s state (File: %s)", sensorName, bsecConfigFileName); LOG_INFO("Can't write %s state (File: %s)", sensorName, bsecConfigFileName);
} }
} }
spiLock->unlock();
#else #else
LOG_ERROR("ERROR: Filesystem not implemented"); LOG_ERROR("ERROR: Filesystem not implemented");
#endif #endif

View File

@ -5,6 +5,7 @@
#include "../mesh/generated/meshtastic/telemetry.pb.h" #include "../mesh/generated/meshtastic/telemetry.pb.h"
#include "FSCommon.h" #include "FSCommon.h"
#include "NAU7802Sensor.h" #include "NAU7802Sensor.h"
#include "SPILock.h"
#include "SafeFile.h" #include "SafeFile.h"
#include "TelemetrySensor.h" #include "TelemetrySensor.h"
#include <Throttle.h> #include <Throttle.h>
@ -111,13 +112,16 @@ bool NAU7802Sensor::saveCalibrationData()
} else { } else {
okay = true; okay = true;
} }
spiLock->lock();
okay &= file.close(); okay &= file.close();
spiLock->unlock();
return okay; return okay;
} }
bool NAU7802Sensor::loadCalibrationData() bool NAU7802Sensor::loadCalibrationData()
{ {
spiLock->lock();
auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ); auto file = FSCom.open(nau7802ConfigFileName, FILE_O_READ);
bool okay = false; bool okay = false;
if (file) { if (file) {
@ -134,6 +138,7 @@ bool NAU7802Sensor::loadCalibrationData()
} else { } else {
LOG_INFO("No %s state found (File: %s)", sensorName, nau7802ConfigFileName); LOG_INFO("No %s state found (File: %s)", sensorName, nau7802ConfigFileName);
} }
spiLock->unlock();
return okay; return okay;
} }

View File

@ -49,6 +49,7 @@
**********************************************************************************************************************/ **********************************************************************************************************************/
#include "xmodem.h" #include "xmodem.h"
#include "SPILock.h"
#ifdef FSCom #ifdef FSCom
@ -119,8 +120,11 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting) { if ((xmodemPacket.seq == 0) && !isReceiving && !isTransmitting) {
// NULL packet has the destination filename // NULL packet has the destination filename
memcpy(filename, &xmodemPacket.buffer.bytes, xmodemPacket.buffer.size); memcpy(filename, &xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash if (xmodemPacket.control == meshtastic_XModem_Control_SOH) { // Receive this file and put to Flash
spiLock->lock();
file = FSCom.open(filename, FILE_O_WRITE); file = FSCom.open(filename, FILE_O_WRITE);
spiLock->unlock();
if (file) { if (file) {
sendControl(meshtastic_XModem_Control_ACK); sendControl(meshtastic_XModem_Control_ACK);
isReceiving = true; isReceiving = true;
@ -132,14 +136,18 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
break; break;
} else { // Transmit this file from Flash } else { // Transmit this file from Flash
LOG_INFO("XModem: Transmit file %s", filename); LOG_INFO("XModem: Transmit file %s", filename);
spiLock->lock();
file = FSCom.open(filename, FILE_O_READ); file = FSCom.open(filename, FILE_O_READ);
spiLock->unlock();
if (file) { if (file) {
packetno = 1; packetno = 1;
isTransmitting = true; isTransmitting = true;
xmodemStore = meshtastic_XModem_init_zero; xmodemStore = meshtastic_XModem_init_zero;
xmodemStore.control = meshtastic_XModem_Control_SOH; xmodemStore.control = meshtastic_XModem_Control_SOH;
xmodemStore.seq = packetno; xmodemStore.seq = packetno;
spiLock->lock();
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes)); xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
spiLock->unlock();
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size); xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
LOG_DEBUG("XModem: STX Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size); LOG_DEBUG("XModem: STX Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) { if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
@ -159,7 +167,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
if ((xmodemPacket.seq == packetno) && if ((xmodemPacket.seq == packetno) &&
check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) { check(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size, xmodemPacket.crc16)) {
// valid packet // valid packet
spiLock->lock();
file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size); file.write(xmodemPacket.buffer.bytes, xmodemPacket.buffer.size);
spiLock->unlock();
sendControl(meshtastic_XModem_Control_ACK); sendControl(meshtastic_XModem_Control_ACK);
packetno++; packetno++;
break; break;
@ -178,16 +188,21 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
case meshtastic_XModem_Control_EOT: case meshtastic_XModem_Control_EOT:
// End of transmission // End of transmission
sendControl(meshtastic_XModem_Control_ACK); sendControl(meshtastic_XModem_Control_ACK);
spiLock->lock();
file.flush(); file.flush();
file.close(); file.close();
spiLock->unlock();
isReceiving = false; isReceiving = false;
break; break;
case meshtastic_XModem_Control_CAN: case meshtastic_XModem_Control_CAN:
// Cancel transmission and remove file // Cancel transmission and remove file
sendControl(meshtastic_XModem_Control_ACK); sendControl(meshtastic_XModem_Control_ACK);
spiLock->lock();
file.flush(); file.flush();
file.close(); file.close();
FSCom.remove(filename); FSCom.remove(filename);
spiLock->unlock();
isReceiving = false; isReceiving = false;
break; break;
case meshtastic_XModem_Control_ACK: case meshtastic_XModem_Control_ACK:
@ -195,7 +210,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
if (isTransmitting) { if (isTransmitting) {
if (isEOT) { if (isEOT) {
sendControl(meshtastic_XModem_Control_EOT); sendControl(meshtastic_XModem_Control_EOT);
spiLock->lock();
file.close(); file.close();
spiLock->unlock();
LOG_INFO("XModem: Finished send file %s", filename); LOG_INFO("XModem: Finished send file %s", filename);
isTransmitting = false; isTransmitting = false;
isEOT = false; isEOT = false;
@ -206,7 +223,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
xmodemStore = meshtastic_XModem_init_zero; xmodemStore = meshtastic_XModem_init_zero;
xmodemStore.control = meshtastic_XModem_Control_SOH; xmodemStore.control = meshtastic_XModem_Control_SOH;
xmodemStore.seq = packetno; xmodemStore.seq = packetno;
spiLock->lock();
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes)); xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
spiLock->unlock();
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size); xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
LOG_DEBUG("XModem: ACK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size); LOG_DEBUG("XModem: ACK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) { if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {
@ -224,7 +243,9 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
if (isTransmitting) { if (isTransmitting) {
if (--retrans <= 0) { if (--retrans <= 0) {
sendControl(meshtastic_XModem_Control_CAN); sendControl(meshtastic_XModem_Control_CAN);
spiLock->lock();
file.close(); file.close();
spiLock->unlock();
LOG_INFO("XModem: Retransmit timeout, cancel file %s", filename); LOG_INFO("XModem: Retransmit timeout, cancel file %s", filename);
isTransmitting = false; isTransmitting = false;
break; break;
@ -232,8 +253,11 @@ void XModemAdapter::handlePacket(meshtastic_XModem xmodemPacket)
xmodemStore = meshtastic_XModem_init_zero; xmodemStore = meshtastic_XModem_init_zero;
xmodemStore.control = meshtastic_XModem_Control_SOH; xmodemStore.control = meshtastic_XModem_Control_SOH;
xmodemStore.seq = packetno; xmodemStore.seq = packetno;
spiLock->lock();
file.seek((packetno - 1) * sizeof(meshtastic_XModem_buffer_t::bytes)); file.seek((packetno - 1) * sizeof(meshtastic_XModem_buffer_t::bytes));
xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes)); xmodemStore.buffer.size = file.read(xmodemStore.buffer.bytes, sizeof(meshtastic_XModem_buffer_t::bytes));
spiLock->unlock();
xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size); xmodemStore.crc16 = crc16_ccitt(xmodemStore.buffer.bytes, xmodemStore.buffer.size);
LOG_DEBUG("XModem: NAK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size); LOG_DEBUG("XModem: NAK Notify Send packet %d, %d Bytes", packetno, xmodemStore.buffer.size);
if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) { if (xmodemStore.buffer.size < sizeof(meshtastic_XModem_buffer_t::bytes)) {

View File

@ -178,7 +178,7 @@ build_flags = ${mesh_tab_base.build_flags}
-D LGFX_TOUCH_Y_MIN=0 -D LGFX_TOUCH_Y_MIN=0
-D LGFX_TOUCH_Y_MAX=479 -D LGFX_TOUCH_Y_MAX=479
-D LGFX_TOUCH_ROTATION=0 -D LGFX_TOUCH_ROTATION=0
-D LGFX_TOUCH_I2C_FREQ=1000000 -D LGFX_TOUCH_I2C_FREQ=400000
; 3.5" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005006893699919.html ; 3.5" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005006893699919.html
[env:mesh-tab-3-5-IPS-capacitive] [env:mesh-tab-3-5-IPS-capacitive]
@ -204,7 +204,7 @@ build_flags = ${mesh_tab_base.build_flags}
-D LGFX_TOUCH_Y_MIN=0 -D LGFX_TOUCH_Y_MIN=0
-D LGFX_TOUCH_Y_MAX=479 -D LGFX_TOUCH_Y_MAX=479
-D LGFX_TOUCH_ROTATION=1 -D LGFX_TOUCH_ROTATION=1
-D LGFX_TOUCH_I2C_FREQ=1000000 -D LGFX_TOUCH_I2C_FREQ=400000
; 4.0" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005007082906950.html ; 4.0" IPS TFT ILI9488 / FT6236: https://vi.aliexpress.com/item/1005007082906950.html
[env:mesh-tab-4-0-IPS-capacitive] [env:mesh-tab-4-0-IPS-capacitive]
@ -230,4 +230,4 @@ build_flags = ${mesh_tab_base.build_flags}
-D LGFX_TOUCH_Y_MIN=0 -D LGFX_TOUCH_Y_MIN=0
-D LGFX_TOUCH_Y_MAX=479 -D LGFX_TOUCH_Y_MAX=479
-D LGFX_TOUCH_ROTATION=1 -D LGFX_TOUCH_ROTATION=1
-D LGFX_TOUCH_I2C_FREQ=1000000 -D LGFX_TOUCH_I2C_FREQ=400000