diff --git a/src/FSCommon.cpp b/src/FSCommon.cpp
index f215be80f..371a93c11 100644
--- a/src/FSCommon.cpp
+++ b/src/FSCommon.cpp
@@ -23,11 +23,16 @@ SPIClass SPI_HSPI(HSPI);
#else
#define SDHandler SPI
#endif
-
+#elif defined(ARCH_NRF52)
+#if defined(SDCARD_USE_SPI1)
+#define SDHandler SPI1
+#elif defined(SDCARD_USE_SPI)
+#define SDHandler SPI
+#endif // NRF52 SPI or SPI1
+#endif // ESP32/NRF52
#ifndef SD_SPI_FREQUENCY
#define SD_SPI_FREQUENCY 4000000U
#endif
-
#endif // HAS_SDCARD
/**
@@ -309,7 +314,13 @@ void setupSDCard()
{
#if defined(HAS_SDCARD) && !defined(SDCARD_USE_SOFT_SPI)
concurrency::LockGuard g(spiLock);
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52))
+#if (defined(ARCH_ESP32))
SDHandler.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
+#elif (defined(ARCH_NRF52))
+ SDHandler.begin();
+#endif
+
if (!SD.begin(SDCARD_CS, SDHandler, SD_SPI_FREQUENCY)) {
LOG_DEBUG("No SD_MMC card detected");
return;
@@ -319,20 +330,23 @@ void setupSDCard()
LOG_DEBUG("No SD_MMC card attached");
return;
}
- LOG_DEBUG("SD_MMC Card Type: ");
if (cardType == CARD_MMC) {
- LOG_DEBUG("MMC");
+ LOG_DEBUG("SD_MMC Card Type: MMC");
} else if (cardType == CARD_SD) {
- LOG_DEBUG("SDSC");
+ LOG_DEBUG("SD_MMC Card Type: SDSC");
} else if (cardType == CARD_SDHC) {
- LOG_DEBUG("SDHC");
+ LOG_DEBUG("SD_MMC Card Type: SDHC");
} else {
- LOG_DEBUG("UNKNOWN");
+ LOG_DEBUG("SD_MMC Card Type: UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
LOG_DEBUG("SD Card Size: %lu MB", (uint32_t)cardSize);
LOG_DEBUG("Total space: %lu MB", (uint32_t)(SD.totalBytes() / (1024 * 1024)));
- LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024)));
+ LOG_INFO("Now scanning free clusters on SD card, this may take some time...");
+ delay(100); // let serial print the above statement properly
+ LOG_DEBUG("Used space: %lu MB", (uint32_t)(SD.usedBytes() / (1024 * 1024))); // This might take some time during boot
+
+#endif
#endif
}
\ No newline at end of file
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 61999ee79..fba3e75e9 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -49,6 +49,9 @@ along with this program. If not, see .
#include "modules/ExternalNotificationModule.h"
#include "modules/TextMessageModule.h"
#include "modules/WaypointModule.h"
+#if !MESHTASTIC_EXCLUDE_STOREFORWARD
+#include "modules/StoreForwardModule.h"
+#endif
#include "sleep.h"
#include "target_specific.h"
@@ -58,11 +61,9 @@ along with this program. If not, see .
#ifdef ARCH_ESP32
#include "esp_task_wdt.h"
-#include "modules/StoreForwardModule.h"
#endif
#if ARCH_PORTDUINO
-#include "modules/StoreForwardModule.h"
#include "platform/portduino/PortduinoGlue.h"
#endif
@@ -2495,9 +2496,9 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
display->setColor(WHITE);
// Draw the channel name
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
+#if !MESHTASTIC_EXCLUDE_STOREFORWARD
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
if (moduleConfig.store_forward.enabled) {
-#ifdef ARCH_ESP32
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
@@ -2524,6 +2525,9 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
imgSF);
#endif
}
+#else
+ // No store and forward, show a exclamation mark
+ if (false) {
#endif
} else {
// TODO: Raspberry Pi supports more than just the one screen size
diff --git a/src/main.cpp b/src/main.cpp
index c12707cdb..f69bde5cc 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -724,6 +724,8 @@ void setup()
i2cScanner.reset();
#endif
+ // initSPI() must have called at this point (must be before screen and lora)
+
#ifdef HAS_SDCARD
setupSDCard();
#endif
@@ -817,7 +819,6 @@ void setup()
drv.setMode(DRV2605_MODE_INTTRIG);
#endif
- // Init our SPI controller (must be before screen and lora)
#ifdef ARCH_RP2040
#ifdef HW_SPI1_DEVICE
SPI1.setSCK(LORA_SCK);
diff --git a/src/memGet.cpp b/src/memGet.cpp
index ef1102f1e..c7078fac4 100644
--- a/src/memGet.cpp
+++ b/src/memGet.cpp
@@ -57,6 +57,8 @@ uint32_t MemGet::getFreePsram()
{
#ifdef ARCH_ESP32
return ESP.getFreePsram();
+#elif (defined(HAS_SDCARD) && defined(ARCH_ESP32))
+ return SD.totalBytes() - SD.usedBytes();
#elif defined(ARCH_PORTDUINO)
return 4194252;
#else
@@ -73,6 +75,8 @@ uint32_t MemGet::getPsramSize()
{
#ifdef ARCH_ESP32
return ESP.getPsramSize();
+#elif (defined(HAS_SDCARD) && defined(ARCH_ESP32))
+ return SD.totalBytes();
#elif defined(ARCH_PORTDUINO)
return 4194252;
#else
diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp
index 297c7b2ed..7aaab9f3c 100644
--- a/src/mesh/MeshService.cpp
+++ b/src/mesh/MeshService.cpp
@@ -283,7 +283,6 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
{
perhapsDecode(p);
-#ifdef ARCH_ESP32
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
if (moduleConfig.store_forward.enabled && storeForwardModule->isServer() &&
p->decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) {
@@ -291,7 +290,6 @@ void MeshService::sendToPhone(meshtastic_MeshPacket *p)
fromNum++; // Notify observers for packet from radio
return;
}
-#endif
#endif
if (toPhoneQueue.numFree() == 0) {
diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h
index e2e430c03..e0e9c22b9 100644
--- a/src/mesh/MeshService.h
+++ b/src/mesh/MeshService.h
@@ -13,11 +13,9 @@
#if defined(ARCH_PORTDUINO)
#include "../platform/portduino/SimRadio.h"
#endif
-#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
#include "modules/StoreForwardModule.h"
#endif
-#endif
extern Allocator &queueStatusPool;
extern Allocator &mqttClientProxyMessagePool;
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 0a79f94a8..0156efa46 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -21,6 +21,9 @@
#include "mesh-pb-constants.h"
#include "meshUtils.h"
#include "modules/NeighborInfoModule.h"
+// #if !MESHTASTIC_EXCLUDE_STOREFORWARD
+// #include "modules/StoreForwardModule.h"
+// #endif
#include
#include
#include
@@ -31,8 +34,6 @@
#if HAS_WIFI
#include "mesh/wifi/WiFiAPClient.h"
#endif
-#include "SPILock.h"
-#include "modules/StoreForwardModule.h"
#include
#include
#include
@@ -41,8 +42,10 @@
#include
#endif
-#ifdef ARCH_PORTDUINO
+#include "SPILock.h"
#include "modules/StoreForwardModule.h"
+
+#ifdef ARCH_PORTDUINO
#include "platform/portduino/PortduinoGlue.h"
#endif
diff --git a/src/mesh/RF95Interface.cpp b/src/mesh/RF95Interface.cpp
index 943a79a5f..d72befbf1 100644
--- a/src/mesh/RF95Interface.cpp
+++ b/src/mesh/RF95Interface.cpp
@@ -188,7 +188,7 @@ bool RF95Interface::init()
#endif
if (res == RADIOLIB_ERR_NONE)
- res = lora->setCRC(RADIOLIB_SX126X_LORA_CRC_ON);
+ res = lora->setCRC(true);
if (res == RADIOLIB_ERR_NONE)
startReceive(); // start receiving
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index fac2ca976..442b286c9 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -69,7 +69,6 @@
#if !MESHTASTIC_EXCLUDE_GENERIC_THREAD_MODULE
#include "modules/GenericThreadModule.h"
#endif
-
#ifdef ARCH_ESP32
#if defined(USE_SX1280) && !MESHTASTIC_EXCLUDE_AUDIO
#include "modules/esp32/AudioModule.h"
@@ -77,9 +76,6 @@
#if !MESHTASTIC_EXCLUDE_PAXCOUNTER
#include "modules/esp32/PaxcounterModule.h"
#endif
-#if !MESHTASTIC_EXCLUDE_STOREFORWARD
-#include "modules/StoreForwardModule.h"
-#endif
#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO)
#if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION
@@ -233,7 +229,7 @@ void setupModules()
paxcounterModule = new PaxcounterModule();
#endif
#endif
-#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
+#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(HAS_SDCARD)
#if !MESHTASTIC_EXCLUDE_STOREFORWARD
storeForwardModule = new StoreForwardModule();
#endif
diff --git a/src/modules/StoreForwardModule.cpp b/src/modules/StoreForwardModule.cpp
index 0a6e1b4c4..994d08cfc 100644
--- a/src/modules/StoreForwardModule.cpp
+++ b/src/modules/StoreForwardModule.cpp
@@ -32,7 +32,7 @@ StoreForwardModule *storeForwardModule;
int32_t StoreForwardModule::runOnce()
{
-#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
+#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(HAS_SDCARD)
if (moduleConfig.store_forward.enabled && is_server) {
// Send out the message queue.
if (this->busy) {
@@ -89,6 +89,32 @@ void StoreForwardModule::populatePSRAM()
LOG_DEBUG("After PSRAM init: heap %d/%d PSRAM %d/%d", memGet.getFreeHeap(), memGet.getHeapSize(), memGet.getFreePsram(),
memGet.getPsramSize());
LOG_DEBUG("numberOfPackets for packetHistory - %u", numberOfPackets);
+ this->storageType = StorageType::ST_PSRAM;
+}
+
+/**
+ * if we have an SDCARD, format it for store&forward use
+ */
+void StoreForwardModule::populateSDCard()
+{
+#if defined(HAS_SDCARD)
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52))
+ spiLock->lock();
+ if (SD.cardType() != CARD_NONE) {
+ if (!SD.exists("/storeforward")) {
+ LOG_INFO("Creating StoreForward directory");
+ SD.mkdir("/storeforward");
+ }
+ this->storageType = StorageType::ST_SDCARD;
+ uint32_t numberOfPackets = (this->records ? this->records : (((SD.totalBytes() / 3) * 2) / sizeof(PacketHistoryStruct)));
+ this->records = numberOfPackets;
+ // only allocate space for one temp copy
+ this->packetHistory = (PacketHistoryStruct *)malloc(sizeof(PacketHistoryStruct));
+ LOG_DEBUG("numberOfPackets for packetHistory - %u", numberOfPackets);
+ }
+ spiLock->unlock();
+#endif // ARCH_ESP32 || ARCH_NRF52
+#endif // HAS_SDCARD
}
/**
@@ -135,14 +161,42 @@ uint32_t StoreForwardModule::getNumAvailablePackets(NodeNum dest, uint32_t last_
lastRequest.emplace(dest, 0);
}
for (uint32_t i = lastRequest[dest]; i < this->packetHistoryTotalCount; i++) {
- if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) {
- // Client is only interested in packets not from itself and only in broadcast packets or packets towards it.
- if (this->packetHistory[i].from != dest &&
- (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == dest)) {
- count++;
+ if (this->storageType == StorageType::ST_PSRAM) {
+ if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) {
+ // Client is only interested in packets not from itself and only in broadcast packets or packets towards it.
+ if (this->packetHistory[i].from != dest &&
+ (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == dest)) {
+ count++;
+ }
}
+ } else if (this->storageType == StorageType::ST_SDCARD) {
+#if defined(HAS_SDCARD)
+#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
+ spiLock->lock();
+ auto handler = SD.open("/storeforward/" + String(i), FILE_READ);
+ if (handler) {
+ if (handler.read((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct)) !=
+ sizeof(PacketHistoryStruct)) {
+ LOG_ERROR("SD card reading error");
+ }
+ handler.close();
+ if (this->packetHistory[0].time && (this->packetHistory[0].time > last_time)) {
+
+ // Client is only interested in packets not from itself and only in broadcast packets or packets towards it.
+ if (this->packetHistory[0].from != dest &&
+ (this->packetHistory[0].to == NODENUM_BROADCAST || this->packetHistory[0].to == dest)) {
+ count++;
+ }
+ }
+ }
+ spiLock->unlock();
+#endif
+#endif
+ } else {
+ LOG_ERROR("S&F: Unknown storage type");
}
}
+
return count;
}
@@ -187,23 +241,47 @@ void StoreForwardModule::historyAdd(const meshtastic_MeshPacket &mp)
const auto &p = mp.decoded;
if (this->packetHistoryTotalCount == this->records) {
- LOG_WARN("S&F - PSRAM Full. Starting overwrite");
+ LOG_WARN("S&F - Storage Full. Starting overwrite");
this->packetHistoryTotalCount = 0;
for (auto &i : lastRequest) {
i.second = 0; // Clear the last request index for each client device
}
}
- this->packetHistory[this->packetHistoryTotalCount].time = getTime();
- this->packetHistory[this->packetHistoryTotalCount].to = mp.to;
- this->packetHistory[this->packetHistoryTotalCount].channel = mp.channel;
- this->packetHistory[this->packetHistoryTotalCount].from = getFrom(&mp);
- this->packetHistory[this->packetHistoryTotalCount].id = mp.id;
- this->packetHistory[this->packetHistoryTotalCount].reply_id = p.reply_id;
- this->packetHistory[this->packetHistoryTotalCount].emoji = (bool)p.emoji;
- this->packetHistory[this->packetHistoryTotalCount].payload_size = p.payload.size;
- memcpy(this->packetHistory[this->packetHistoryTotalCount].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
-
+ if (this->storageType == StorageType::ST_PSRAM) {
+ this->packetHistory[this->packetHistoryTotalCount].time = getTime();
+ this->packetHistory[this->packetHistoryTotalCount].to = mp.to;
+ this->packetHistory[this->packetHistoryTotalCount].channel = mp.channel;
+ this->packetHistory[this->packetHistoryTotalCount].from = getFrom(&mp);
+ this->packetHistory[this->packetHistoryTotalCount].id = mp.id;
+ this->packetHistory[this->packetHistoryTotalCount].reply_id = p.reply_id;
+ this->packetHistory[this->packetHistoryTotalCount].emoji = (bool)p.emoji;
+ this->packetHistory[this->packetHistoryTotalCount].payload_size = p.payload.size;
+ memcpy(this->packetHistory[this->packetHistoryTotalCount].payload, p.payload.bytes,
+ meshtastic_Constants_DATA_PAYLOAD_LEN);
+ } else if (this->storageType == StorageType::ST_SDCARD) {
+// Save to SDCARD
+#if defined(HAS_SDCARD)
+#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
+ this->packetHistory[0].time = getTime();
+ this->packetHistory[0].to = mp.to;
+ this->packetHistory[0].channel = mp.channel;
+ this->packetHistory[0].from = getFrom(&mp);
+ this->packetHistory[0].id = mp.id;
+ this->packetHistory[0].reply_id = p.reply_id;
+ this->packetHistory[0].emoji = (bool)p.emoji;
+ this->packetHistory[0].payload_size = p.payload.size;
+ memcpy(this->packetHistory[0].payload, p.payload.bytes, meshtastic_Constants_DATA_PAYLOAD_LEN);
+ spiLock->lock();
+ auto handler = SD.open("/storeforward/" + String(this->packetHistoryTotalCount), FILE_WRITE, true);
+ handler.write((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct));
+ handler.close();
+ spiLock->unlock();
+#endif
+#endif
+ } else {
+ LOG_ERROR("S&F: Unknown storage type");
+ }
this->packetHistoryTotalCount++;
}
@@ -236,50 +314,108 @@ bool StoreForwardModule::sendPayload(NodeNum dest, uint32_t last_time)
meshtastic_MeshPacket *StoreForwardModule::preparePayload(NodeNum dest, uint32_t last_time, bool local)
{
for (uint32_t i = lastRequest[dest]; i < this->packetHistoryTotalCount; i++) {
- if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) {
- /* Copy the messages that were received by the server in the last msAgo
- to the packetHistoryTXQueue structure.
- Client not interested in packets from itself and only in broadcast packets or packets towards it. */
- if (this->packetHistory[i].from != dest &&
- (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == dest)) {
+ if (this->storageType == StorageType::ST_PSRAM) {
- meshtastic_MeshPacket *p = allocDataPacket();
+ if (this->packetHistory[i].time && (this->packetHistory[i].time > last_time)) {
+ /* Copy the messages that were received by the server in the last msAgo
+ to the packetHistoryTXQueue structure.
+ Client not interested in packets from itself and only in broadcast packets or packets towards it. */
+ if (this->packetHistory[i].from != dest &&
+ (this->packetHistory[i].to == NODENUM_BROADCAST || this->packetHistory[i].to == dest)) {
- p->to = local ? this->packetHistory[i].to : dest; // PhoneAPI can handle original `to`
- p->from = this->packetHistory[i].from;
- p->id = this->packetHistory[i].id;
- p->channel = this->packetHistory[i].channel;
- p->decoded.reply_id = this->packetHistory[i].reply_id;
- p->rx_time = this->packetHistory[i].time;
- p->decoded.emoji = (uint32_t)this->packetHistory[i].emoji;
+ meshtastic_MeshPacket *p = allocDataPacket();
- // Let's assume that if the server received the S&F request that the client is in range.
- // TODO: Make this configurable.
- p->want_ack = false;
+ p->to = local ? this->packetHistory[i].to : dest; // PhoneAPI can handle original `to`
+ p->from = this->packetHistory[i].from;
+ p->id = this->packetHistory[i].id;
+ p->channel = this->packetHistory[i].channel;
+ p->decoded.reply_id = this->packetHistory[i].reply_id;
+ p->rx_time = this->packetHistory[i].time;
+ p->decoded.emoji = (uint32_t)this->packetHistory[i].emoji;
+
+ // Let's assume that if the server received the S&F request that the client is in range.
+ // TODO: Make this configurable.
+ p->want_ack = false;
+
+ if (local) { // PhoneAPI gets normal TEXT_MESSAGE_APP
+ p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
+ memcpy(p->decoded.payload.bytes, this->packetHistory[i].payload, this->packetHistory[i].payload_size);
+ p->decoded.payload.size = this->packetHistory[i].payload_size;
- if (local) { // PhoneAPI gets normal TEXT_MESSAGE_APP
- p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
- memcpy(p->decoded.payload.bytes, this->packetHistory[i].payload, this->packetHistory[i].payload_size);
- p->decoded.payload.size = this->packetHistory[i].payload_size;
- } else {
- meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero;
- sf.which_variant = meshtastic_StoreAndForward_text_tag;
- sf.variant.text.size = this->packetHistory[i].payload_size;
- memcpy(sf.variant.text.bytes, this->packetHistory[i].payload, this->packetHistory[i].payload_size);
- if (this->packetHistory[i].to == NODENUM_BROADCAST) {
- sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST;
} else {
- sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT;
+ meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero;
+ sf.which_variant = meshtastic_StoreAndForward_text_tag;
+ sf.variant.text.size = this->packetHistory[i].payload_size;
+ memcpy(sf.variant.text.bytes, this->packetHistory[i].payload, this->packetHistory[i].payload_size);
+ if (this->packetHistory[i].to == NODENUM_BROADCAST) {
+ sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST;
+ } else {
+ sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT;
+ }
+
+ p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
+ &meshtastic_StoreAndForward_msg, &sf);
}
- p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes),
- &meshtastic_StoreAndForward_msg, &sf);
+ lastRequest[dest] = i + 1; // Update the last request index for the client device
+
+ return p;
}
-
- lastRequest[dest] = i + 1; // Update the last request index for the client device
-
- return p;
}
+ } else if (this->storageType == StorageType::ST_SDCARD) {
+#if defined(HAS_SDCARD)
+#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
+ spiLock->lock();
+ auto handler = SD.open("/storeforward/" + String(i), FILE_READ);
+ if (handler) {
+ handler.read((uint8_t *)&this->packetHistory[0], sizeof(PacketHistoryStruct));
+ handler.close();
+ spiLock->unlock();
+ if (this->packetHistory[0].time && (this->packetHistory[0].time > last_time)) {
+ if (this->packetHistory[0].from != dest &&
+ (this->packetHistory[0].to == NODENUM_BROADCAST || this->packetHistory[0].to == dest)) {
+
+ meshtastic_MeshPacket *p = allocDataPacket();
+
+ p->to = local ? this->packetHistory[0].to : dest; // PhoneAPI can handle original `to`
+ p->from = this->packetHistory[0].from;
+ p->channel = this->packetHistory[0].channel;
+ p->rx_time = this->packetHistory[0].time;
+
+ // Let's assume that if the server received the S&F request that the client is in range.
+ p->want_ack = false;
+
+ if (local) { // PhoneAPI gets normal TEXT_MESSAGE_APP
+ p->decoded.portnum = meshtastic_PortNum_TEXT_MESSAGE_APP;
+ memcpy(p->decoded.payload.bytes, this->packetHistory[0].payload, this->packetHistory[0].payload_size);
+ p->decoded.payload.size = this->packetHistory[0].payload_size;
+ } else {
+ meshtastic_StoreAndForward sf = meshtastic_StoreAndForward_init_zero;
+ sf.which_variant = meshtastic_StoreAndForward_text_tag;
+ sf.variant.text.size = this->packetHistory[0].payload_size;
+ memcpy(sf.variant.text.bytes, this->packetHistory[0].payload, this->packetHistory[0].payload_size);
+ if (this->packetHistory[0].to == NODENUM_BROADCAST) {
+ sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_BROADCAST;
+ } else {
+ sf.rr = meshtastic_StoreAndForward_RequestResponse_ROUTER_TEXT_DIRECT;
+ }
+
+ p->decoded.payload.size = pb_encode_to_bytes(
+ p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &meshtastic_StoreAndForward_msg, &sf);
+ }
+
+ lastRequest[dest] = i + 1; // Update the last request index for the client device
+
+ return p;
+ }
+ }
+ } else {
+ spiLock->unlock();
+ }
+#endif
+#endif
+ } else {
+ LOG_ERROR("S&F: Unknown storage type");
}
}
return nullptr;
@@ -383,7 +519,7 @@ void StoreForwardModule::statsSend(uint32_t to)
*/
ProcessMessage StoreForwardModule::handleReceived(const meshtastic_MeshPacket &mp)
{
-#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
+#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(HAS_SDCARD)
if (moduleConfig.store_forward.enabled) {
if ((mp.decoded.portnum == meshtastic_PortNum_TEXT_MESSAGE_APP) && is_server) {
@@ -562,7 +698,7 @@ StoreForwardModule::StoreForwardModule()
ProtobufModule("StoreForward", meshtastic_PortNum_STORE_FORWARD_APP, &meshtastic_StoreAndForward_msg)
{
-#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO)
+#if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) || defined(HAS_SDCARD)
isPromiscuous = true; // Brown chicken brown cow
@@ -613,7 +749,14 @@ StoreForwardModule::StoreForwardModule()
} else {
LOG_INFO("S&F: device doesn't have PSRAM, Disable");
}
-
+#ifdef HAS_SDCARD
+ // If we have an SDCARD, format it for store&forward use
+ if (SD.cardType() != CARD_NONE) {
+ this->populateSDCard();
+ LOG_INFO("S&F: SDCARD initialized");
+ is_server = true;
+ }
+#endif
// Client
} else {
is_client = true;
diff --git a/src/modules/StoreForwardModule.h b/src/modules/StoreForwardModule.h
index 30db1625c..1e65c1cb0 100644
--- a/src/modules/StoreForwardModule.h
+++ b/src/modules/StoreForwardModule.h
@@ -9,6 +9,11 @@
#include
#include
+#ifdef HAS_SDCARD
+#include "SPILock.h"
+#include
+#endif
+
struct PacketHistoryStruct {
uint32_t time;
uint32_t to;
@@ -21,6 +26,9 @@ struct PacketHistoryStruct {
pb_size_t payload_size;
};
+// enum for the storage type
+enum StorageType { ST_PSRAM, ST_SDCARD };
+
class StoreForwardModule : private concurrency::OSThread, public ProtobufModule
{
bool busy = 0;
@@ -83,6 +91,10 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
private:
void populatePSRAM();
+ void populateSDCard();
+
+ // Storage Type
+ StorageType storageType = ST_PSRAM;
// S&F Defaults
uint32_t historyReturnMax = 25; // Return maximum of 25 records by default.
diff --git a/src/xmodem.h b/src/xmodem.h
index 4cfcb43e1..1e7b7a94f 100644
--- a/src/xmodem.h
+++ b/src/xmodem.h
@@ -61,7 +61,9 @@ class XModemAdapter
uint16_t packetno = 0;
-#if defined(ARCH_NRF52) || defined(ARCH_STM32WL)
+#if defined(ARCH_NRF52)
+ Adafruit_LittleFS_Namespace::File file = Adafruit_LittleFS_Namespace::File(FSCom);
+#elif defined(ARCH_STM32WL)
File file = File(FSCom);
#else
File file;
diff --git a/variants/CDEBYTE_EoRa-S3/variant.h b/variants/CDEBYTE_EoRa-S3/variant.h
index 5da99667b..854996332 100644
--- a/variants/CDEBYTE_EoRa-S3/variant.h
+++ b/variants/CDEBYTE_EoRa-S3/variant.h
@@ -6,7 +6,7 @@
// SD card - TODO: test, currently untested, copied from T3S3 variant
#define HAS_SDCARD
-#define SDCARD_USE_SPI1
+#define SDCARD_USE_HSPI
// TODO: rename this to make this SD-card specific
#define SPI_CS 13
#define SPI_SCK 14
diff --git a/variants/bpi_picow_esp32_s3/variant.h b/variants/bpi_picow_esp32_s3/variant.h
index d8d9413d7..fc9064436 100644
--- a/variants/bpi_picow_esp32_s3/variant.h
+++ b/variants/bpi_picow_esp32_s3/variant.h
@@ -5,7 +5,7 @@
// #define HAS_SCREEN 0
// #define HAS_SDCARD
-// #define SDCARD_USE_SPI1
+// #define SDCARD_USE_HSPI
#define USE_SSD1306
#define I2C_SDA 12
diff --git a/variants/dreamcatcher/variant.h b/variants/dreamcatcher/variant.h
index 7835979e1..1e04a2b26 100644
--- a/variants/dreamcatcher/variant.h
+++ b/variants/dreamcatcher/variant.h
@@ -70,7 +70,7 @@
#endif
#define HAS_SDCARD // Have SPI interface SD card slot
-#define SDCARD_USE_SPI1
+#define SDCARD_USE_HSPI
#define LORA_RESET 3
#define LORA_SCK 12
diff --git a/variants/my_esp32s3_diy_eink/variant.h b/variants/my_esp32s3_diy_eink/variant.h
index 024f912dd..c60e2b0ce 100644
--- a/variants/my_esp32s3_diy_eink/variant.h
+++ b/variants/my_esp32s3_diy_eink/variant.h
@@ -4,7 +4,7 @@
// #define HAS_SCREEN 0
// #define HAS_SDCARD
-// #define SDCARD_USE_SPI1
+// #define SDCARD_USE_HSPI
// #define USE_SSD1306
diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini
index f2d68e704..a64cd43bf 100644
--- a/variants/rak4631/platformio.ini
+++ b/variants/rak4631/platformio.ini
@@ -19,6 +19,8 @@ lib_deps =
https://github.com/RAKWireless/RAK13800-W5100S/archive/1.0.2.zip
rakwireless/RAKwireless NCP5623 RGB LED library@^1.0.2
https://github.com/RAKWireless/RAK12034-BMX160/archive/dcead07ffa267d3c906e9ca4a1330ab989e957e2.zip
+ https://github.com/Woutvstk/SdFat_wrapper25.git#6f8f48d56c15cbeac753560dfeede4a487f81f4c
+
; If not set we will default to uploading over serial (first it forces bootloader entry by talking 1200bps to cdcacm)
; Note: as of 6/2013 the serial/bootloader based programming takes approximately 30 seconds
diff --git a/variants/rak4631/variant.h b/variants/rak4631/variant.h
index 0da1c04ea..d73e64655 100644
--- a/variants/rak4631/variant.h
+++ b/variants/rak4631/variant.h
@@ -108,11 +108,14 @@ static const uint8_t AREF = PIN_AREF;
* SPI Interfaces
*/
#define SPI_INTERFACES_COUNT 2
+#define SPI_32MHZ_INTERFACE 0 // 0: use SPIM3 for SPI and SPIM2 for SPI1; 1: the opposite
+// SPI pins for SX1262
#define PIN_SPI_MISO (45)
#define PIN_SPI_MOSI (44)
#define PIN_SPI_SCK (43)
+// SPI1 pins for external(rak4630) spi (incl. SDCard)
#define PIN_SPI1_MISO (29) // (0 + 29)
#define PIN_SPI1_MOSI (30) // (0 + 30)
#define PIN_SPI1_SCK (3) // (0 + 3)
@@ -122,6 +125,19 @@ static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK;
+// SD card SPI pin definitions
+
+#define HAS_SDCARD 1
+#define SDCARD_USE_SPI1 1
+
+#define SDCARD_CS (26)
+
+// Some settings for the SdFat library to optimize flash usage
+#define SDFAT_FILE_TYPE 1 // only support FAT16/FAT32, not exFAT
+#define CHECK_FLASH_PROGRAMMING \
+ 0 // this reduces flash usage but may cause higher power usage when sd card is idle TODO:Check if power usage is higher
+#define MAINTAIN_FREE_CLUSTER_COUNT 1 // maintain free cluster count
+
/*
* eink display pins
*/
diff --git a/variants/tbeam-s3-core/variant.h b/variants/tbeam-s3-core/variant.h
index cc706459f..fd7649265 100644
--- a/variants/tbeam-s3-core/variant.h
+++ b/variants/tbeam-s3-core/variant.h
@@ -58,7 +58,7 @@
#define GPS_1PPS_PIN 6
#define HAS_SDCARD // Have SPI interface SD card slot
-#define SDCARD_USE_SPI1
+#define SDCARD_USE_HSPI
// PCF8563 RTC Module
// #define PCF8563_RTC 0x51 //Putting definitions in variant. h does not compile correctly
diff --git a/variants/tlora_t3s3_epaper/variant.h b/variants/tlora_t3s3_epaper/variant.h
index 1ed505420..ca1edb0e8 100644
--- a/variants/tlora_t3s3_epaper/variant.h
+++ b/variants/tlora_t3s3_epaper/variant.h
@@ -1,5 +1,5 @@
#define HAS_SDCARD
-#define SDCARD_USE_SPI1
+#define SDCARD_USE_HSPI
// Display (E-Ink)
#define PIN_EINK_CS 15
diff --git a/variants/tlora_t3s3_v1/variant.h b/variants/tlora_t3s3_v1/variant.h
index babe44a58..63caaaf12 100644
--- a/variants/tlora_t3s3_v1/variant.h
+++ b/variants/tlora_t3s3_v1/variant.h
@@ -1,5 +1,5 @@
#define HAS_SDCARD
-#define SDCARD_USE_SPI1
+#define SDCARD_USE_HSPI
#define USE_SSD1306
@@ -76,4 +76,4 @@
#endif
#define HAS_SDCARD // Have SPI interface SD card slot
-#define SDCARD_USE_SPI1
\ No newline at end of file
+#define SDCARD_USE_HSPI
\ No newline at end of file
diff --git a/variants/tlora_v2_1_16/platformio.ini b/variants/tlora_v2_1_16/platformio.ini
index 4253cc6af..04828dca3 100644
--- a/variants/tlora_v2_1_16/platformio.ini
+++ b/variants/tlora_v2_1_16/platformio.ini
@@ -3,6 +3,11 @@ extends = esp32_base
board = ttgo-lora32-v21
board_check = true
build_flags =
- ${esp32_base.build_flags} -D TLORA_V2_1_16 -I variants/tlora_v2_1_16
+ ${esp32_base.build_flags}
+ -D TLORA_V2_1_16
+ -I variants/tlora_v2_1_16
-DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely.
-upload_speed = 115200
\ No newline at end of file
+ -DRADIOLIB_EXCLUDE_SX128X=1
+ -DRADIOLIB_EXCLUDE_SX126X=1
+ -DRADIOLIB_EXCLUDE_LR11X0=1
+upload_speed = 115200
diff --git a/variants/tlora_v2_1_16/variant.h b/variants/tlora_v2_1_16/variant.h
index 48c069ab7..9607620ea 100644
--- a/variants/tlora_v2_1_16/variant.h
+++ b/variants/tlora_v2_1_16/variant.h
@@ -22,4 +22,15 @@
#define LORA_DIO1 33 // https://www.thethingsnetwork.org/forum/t/big-esp32-sx127x-topic-part-3/18436
#endif
-#define LORA_DIO2 32 // Not really used
\ No newline at end of file
+#define LORA_DIO2 32 // Not really used
+
+/*
+ * Use SD Card for Store and Forward
+ */
+#define HAS_SDCARD
+#define SDCARD_USE_HSPI
+#define SPI_MOSI 15
+#define SPI_MISO 2
+#define SPI_SCK 14
+#define SPI_CS 13
+#define SDCARD_CS SPI_CS
\ No newline at end of file
diff --git a/variants/unphone/variant.h b/variants/unphone/variant.h
index eaf142721..9932d3c59 100644
--- a/variants/unphone/variant.h
+++ b/variants/unphone/variant.h
@@ -51,6 +51,9 @@
#undef GPS_RX_PIN
#undef GPS_TX_PIN
+// #define HAS_SDCARD 1 // causes hang if defined
+#define SDCARD_USE_HSPI
+
#define SD_SPI_FREQUENCY 25000000
#define SDCARD_CS 43