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