diff --git a/images/Insufficient space.png b/images/Insufficient space.png new file mode 100644 index 000000000..e67722979 Binary files /dev/null and b/images/Insufficient space.png differ diff --git a/images/platformio-erase.png b/images/platformio-erase.png new file mode 100644 index 000000000..38543e3ac Binary files /dev/null and b/images/platformio-erase.png differ diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index b3fac2ab8..f7a2bc415 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -114,7 +114,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) // Count the packet toward our TX airtime utilization. // We only count it if it can be added to the TX queue. airTime->logAirtime(TX_LOG, xmitMsec); - // airTime.logAirtime(TX_LOG, xmitMsec); // We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent // in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio @@ -245,13 +244,14 @@ void RadioLibInterface::handleReceiveInterrupt() size_t length = iface->getPacketLength(); xmitMsec = getPacketTime(length); - airTime->logAirtime(RX_ALL_LOG, xmitMsec); - // airTime.logAirtime(RX_ALL_LOG, xmitMsec); int state = iface->readData(radiobuf, length); if (state != ERR_NONE) { DEBUG_MSG("ignoring received packet due to error=%d\n", state); rxBad++; + + airTime->logAirtime(RX_ALL_LOG, xmitMsec); + } else { // Skip the 4 headers that are at the beginning of the rxBuf int32_t payloadLen = length - sizeof(PacketHeader); @@ -261,6 +261,7 @@ void RadioLibInterface::handleReceiveInterrupt() if (payloadLen < 0) { DEBUG_MSG("ignoring received packet too short\n"); rxBad++; + airTime->logAirtime(RX_ALL_LOG, xmitMsec); } else { const PacketHeader *h = (PacketHeader *)radiobuf; @@ -288,9 +289,8 @@ void RadioLibInterface::handleReceiveInterrupt() printPacket("Lora RX", mp); - xmitMsec = getPacketTime(mp); + //xmitMsec = getPacketTime(mp); airTime->logAirtime(RX_LOG, xmitMsec); - // airTime.logAirtime(RX_LOG, xmitMsec); deliverToReceiver(mp); } @@ -300,7 +300,7 @@ void RadioLibInterface::handleReceiveInterrupt() /** start an immediate transmit */ void RadioLibInterface::startSend(MeshPacket *txp) { - printPacket("Starting low level send", txp); + printPacket("Starting low level send", txp); if (disabled) { DEBUG_MSG("startSend is dropping tx packet because we are disabled\n"); packetPool.release(txp); diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 738d1df7e..65f1f5f03 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -4,15 +4,16 @@ #include "plugins/RemoteHardwarePlugin.h" #include "plugins/ReplyPlugin.h" #include "plugins/TextMessagePlugin.h" -#ifndef NO_ESP32 -#include "plugins/esp32/EnvironmentalMeasurementPlugin.h" -#include "plugins/esp32/RangeTestPlugin.h" -#endif #include "plugins/SerialPlugin.h" -#include "plugins/StoreForwardPlugin.h" #include "plugins/TextMessagePlugin.h" #include "plugins/RoutingPlugin.h" #include "plugins/AdminPlugin.h" +#ifndef NO_ESP32 +#include "plugins/SerialPlugin.h" +#include "plugins/esp32/EnvironmentalMeasurementPlugin.h" +#include "plugins/esp32/RangeTestPlugin.h" +#include "plugins/esp32/StoreForwardPlugin.h" +#endif /** * Create plugin instances here. If you are adding a new plugin, you must 'new' it here (or somewhere else) diff --git a/src/plugins/StoreForwardPlugin.cpp b/src/plugins/StoreForwardPlugin.cpp deleted file mode 100644 index af9bf5ecd..000000000 --- a/src/plugins/StoreForwardPlugin.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "StoreForwardPlugin.h" -#include "MeshService.h" -#include "NodeDB.h" -#include "RTC.h" -#include "Router.h" -#include "configuration.h" -#include -#include - -StoreForwardPlugin *storeForwardPlugin; -StoreForwardPluginRadio *storeForwardPluginRadio; - -StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {} - -int32_t StoreForwardPlugin::runOnce() -{ - -#ifndef NO_ESP32 - - /* - Uncomment the preferences below if you want to use the plugin - without having to configure it from the PythonAPI or WebUI. - */ - - // radioConfig.preferences.store_forward_plugin_enabled = 1; - // radioConfig.preferences.is_router = 1; - - if (radioConfig.preferences.store_forward_plugin_enabled) { - - if (firstTime) { - - /* - */ - - if (radioConfig.preferences.is_router) { - DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n"); - // Router - if (ESP.getPsramSize()) { - if (ESP.getFreePsram() >= 1024 * 1024) { - // Do the startup here - storeForwardPluginRadio = new StoreForwardPluginRadio(); - - firstTime = 0; - - } else { - DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); - DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); - - return (INT32_MAX); - } - - } else { - DEBUG_MSG("Device doesn't have PSRAM.\n"); - DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); - - return (INT32_MAX); - } - - } else { - DEBUG_MSG("Initializing Store & Forward Plugin - Enabled but is_router is not turned on.\n"); - DEBUG_MSG( - "Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n"); - // Non-Router - - return (30 * 1000); - } - - } else { - // What do we do if it's not our first time? - - // Maybe some cleanup functions? - } - - } else { - DEBUG_MSG("Store & Forward Plugin - Disabled\n"); - - return (INT32_MAX); - } - -#endif - return (INT32_MAX); -} - -// We saw a node. -uint32_t StoreForwardPlugin::sawNode(uint32_t node) -{ - - /* - TODO: Move receivedRecord into the PSRAM - - TODO: Gracefully handle the case where we run out of records. - Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back. - - TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). - */ - - DEBUG_MSG("looking for node - %i\n", node); - for (int i = 0; i < 50; i++) { - DEBUG_MSG("Iterating through the seen nodes - %d %d %d\n", i, receivedRecord[i][0], receivedRecord[i][1]); - // First time seeing that node. - if (receivedRecord[i][0] == 0) { - DEBUG_MSG("New node! Woohoo! Win!\n"); - receivedRecord[i][0] = node; - receivedRecord[i][1] = millis(); - - return receivedRecord[i][1]; - } - - // We've seen this node before. - if (receivedRecord[i][0] == node) { - DEBUG_MSG("We've seen this node before\n"); - uint32_t lastSaw = receivedRecord[i][1]; - receivedRecord[i][1] = millis(); - return lastSaw; - } - } - - return 0; -} - -MeshPacket *StoreForwardPluginRadio::allocReply() -{ - - auto reply = allocDataPacket(); // Allocate a packet for sending - - return reply; -} - -void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) -{ - MeshPacket *p = allocReply(); - p->to = dest; - p->decoded.want_response = wantReplies; - - service.sendToMesh(p); -} - -bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) -{ -#ifndef NO_ESP32 - if (radioConfig.preferences.store_forward_plugin_enabled) { - // auto &p = mp.decoded.data; - - if (mp.from != nodeDB.getNodeNum()) { - DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); - printPacket("----- PACKET FROM RADIO", &mp); - // DEBUG_MSG("\n\nStore & Forward Plugin -- Print End ---------- ---------- ---------- ---------- ----------\n"); - uint32_t sawTime = storeForwardPlugin->sawNode(mp.from); - DEBUG_MSG("Last Saw this node %d, %d millis ago\n", mp.from, (millis() - sawTime)); - } - - } else { - DEBUG_MSG("Store & Forward Plugin - Disabled\n"); - } - -#endif - - return true; // Let others look at this message also if they want -} diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp new file mode 100644 index 000000000..d55e076bb --- /dev/null +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -0,0 +1,297 @@ +#include "StoreForwardPlugin.h" +#include "MeshService.h" +#include "NodeDB.h" +#include "RTC.h" +#include "Router.h" +#include "configuration.h" +#include "mesh-pb-constants.h" +#include +#include + +#define STOREFORWARD_MAX_PACKETS 7500 +#define STOREFORWARD_SEND_HISTORY_SHORT 600 + +StoreForwardPlugin *storeForwardPlugin; +StoreForwardPluginRadio *storeForwardPluginRadio; + +StoreForwardPlugin::StoreForwardPlugin() : concurrency::OSThread("StoreForwardPlugin") {} + +int32_t StoreForwardPlugin::runOnce() +{ + +#ifndef NO_ESP32 + + /* + Uncomment the preferences below if you want to use the plugin + without having to configure it from the PythonAPI or WebUI. + */ + + // radioConfig.preferences.store_forward_plugin_enabled = 1; + // radioConfig.preferences.is_router = 1; + + if (radioConfig.preferences.store_forward_plugin_enabled) { + + if (firstTime) { + + /* + */ + + if (radioConfig.preferences.is_router) { + DEBUG_MSG("Initializing Store & Forward Plugin - Enabled\n"); + // Router + if (ESP.getPsramSize()) { + if (ESP.getFreePsram() >= 2048 * 1024) { + // Do the startup here + storeForwardPluginRadio = new StoreForwardPluginRadio(); + + firstTime = 0; + + this->populatePSRAM(); + + // packetHistory[0].bytes; + return (10 * 1000); + + } else { + DEBUG_MSG("Device has less than 2M of PSRAM free. Aborting startup.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + } else { + DEBUG_MSG("Device doesn't have PSRAM.\n"); + DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); + + return (INT32_MAX); + } + + } else { + DEBUG_MSG("Initializing Store & Forward Plugin - Enabled but is_router is not turned on.\n"); + DEBUG_MSG( + "Initializing Store & Forward Plugin - If you want to use this plugin, you must also turn on is_router.\n"); + // Non-Router + + return (30 * 1000); + } + + } else { + // What do we do if it's not our first time? + + // Maybe some cleanup functions? + this->sawNodeReport(); + this->historyReport(); + return (10 * 1000); + } + + } else { + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + + return (INT32_MAX); + } + +#endif + return (INT32_MAX); +} + +void StoreForwardPlugin::populatePSRAM() +{ + /* + For PSRAM usage, see: + https://learn.upesy.com/en/programmation/psram.html#psram-tab + */ + + DEBUG_MSG("Before PSRAM initilization\n"); + + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); + DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); + DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); + DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); + + // PacketHistoryStruct *packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, + // sizeof(PacketHistoryStruct)); + this->packetHistory = (PacketHistoryStruct *)ps_calloc(STOREFORWARD_MAX_PACKETS, sizeof(PacketHistoryStruct)); + DEBUG_MSG("After PSRAM initilization\n"); + + DEBUG_MSG("Total heap: %d\n", ESP.getHeapSize()); + DEBUG_MSG("Free heap: %d\n", ESP.getFreeHeap()); + DEBUG_MSG("Total PSRAM: %d\n", ESP.getPsramSize()); + DEBUG_MSG("Free PSRAM: %d\n", ESP.getFreePsram()); + + DEBUG_MSG("packetHistory Size - %u", sizeof(packetHistory)); +} + +// We saw a node. +uint32_t StoreForwardPlugin::sawNode(uint32_t node) +{ + + /* + TODO: Move receivedRecord into the PSRAM + + TODO: Gracefully handle the case where we run out of records. + Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back. + + TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). + */ + // DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, + // p->want_ack, p->hop_limit); + DEBUG_MSG("looking for node - from-0x%08x\n", node); + for (int i = 0; i < 50; i++) { + // DEBUG_MSG("Iterating through the seen nodes - %u %u %u\n", i, receivedRecord[i][0], receivedRecord[i][1]); + // First time seeing that node. + if (receivedRecord[i][0] == 0) { + // DEBUG_MSG("New node! Woohoo! Win!\n"); + receivedRecord[i][0] = node; + receivedRecord[i][1] = millis(); + + return receivedRecord[i][1]; + } + + // We've seen this node before. + if (receivedRecord[i][0] == node) { + // DEBUG_MSG("We've seen this node before\n"); + uint32_t lastSaw = receivedRecord[i][1]; + receivedRecord[i][1] = millis(); + return lastSaw; + } + } + + return 0; +} + +void StoreForwardPlugin::historyReport() +{ + DEBUG_MSG("Iterating through the message history...\n"); + DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent); + uint32_t startTimer = millis(); + for (int i = 0; i < this->packetHistoryCurrent; i++) { + if (this->packetHistory[i].time) { + // DEBUG_MSG("... time-%u to-0x%08x\n", this->packetHistory[i].time, this->packetHistory[i].to & 0xffffffff); + } + } + DEBUG_MSG("StoreForwardPlugin::historyReport runtime - %u ms\n", millis() - startTimer); +} +void StoreForwardPlugin::historySend(uint32_t msAgo, uint32_t to) +{ + for (int i = 0; i < this->packetHistoryCurrent; i++) { + if (this->packetHistory[i].time) { + // DEBUG_MSG("... time-%u to-0x%08x\n", this->packetHistory[i].time, this->packetHistory[i].to & 0xffffffff); + } + } +} + +void StoreForwardPlugin::historyAdd(const MeshPacket *mp) +{ + auto &p = mp; + + static uint8_t bytes[MAX_RHPACKETLEN]; + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); + assert(numbytes <= MAX_RHPACKETLEN); + + DEBUG_MSG("MP numbytes %u\n", numbytes); + + // destination, source, bytes + // memcpy(p->encrypted.bytes, bytes, numbytes); + memcpy(this->packetHistory[this->packetHistoryCurrent].bytes, bytes, MAX_RHPACKETLEN); + this->packetHistory[this->packetHistoryCurrent].time = millis(); + this->packetHistory[this->packetHistoryCurrent].to = mp->to; + this->packetHistoryCurrent++; +} + +// We saw a node. +void StoreForwardPlugin::sawNodeReport() +{ + + /* + TODO: Move receivedRecord into the PSRAM + + TODO: Gracefully handle the case where we run out of records. + Maybe replace the oldest record that hasn't been seen in a while and assume they won't be back. + + TODO: Implment this as a std::map for quicker lookups (maybe it doesn't matter?). + */ + + DEBUG_MSG("Iterating through the seen nodes in receivedRecord...\n"); + for (int i = 0; i < 50; i++) { + if (receivedRecord[i][1]) { + DEBUG_MSG("... record-%u from-0x%08x secAgo-%u\n", i, receivedRecord[i][0], (millis() - receivedRecord[i][1]) / 1000); + } + } +} + +MeshPacket *StoreForwardPluginRadio::allocReply() +{ + + auto reply = allocDataPacket(); // Allocate a packet for sending + + return reply; +} + +void StoreForwardPluginRadio::sendPayload(NodeNum dest, bool wantReplies) +{ + MeshPacket *p = allocReply(); + p->to = dest; + p->decoded.want_response = wantReplies; + + service.sendToMesh(p); +} + +bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp) +{ +#ifndef NO_ESP32 + if (radioConfig.preferences.store_forward_plugin_enabled) { + + if (mp.from != nodeDB.getNodeNum()) { + // DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n"); + // DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff, + // p->want_ack, p->hop_limit); + printPacket("----- PACKET FROM RADIO -----", &mp); + uint32_t sawTime = storeForwardPlugin->sawNode(mp.from & 0xffffffff); + DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from & 0xffffffff, (millis() - sawTime) / 1000); + + if (mp.decoded.portnum == PortNum_UNKNOWN_APP) { + DEBUG_MSG("Packet came from - PortNum_UNKNOWN_APP\n"); + } else if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) { + DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n"); + + storeForwardPlugin->historyAdd(&mp); + + } else if (mp.decoded.portnum == PortNum_REMOTE_HARDWARE_APP) { + DEBUG_MSG("Packet came from - PortNum_REMOTE_HARDWARE_APP\n"); + } else if (mp.decoded.portnum == PortNum_POSITION_APP) { + DEBUG_MSG("Packet came from - PortNum_POSITION_APP\n"); + } else if (mp.decoded.portnum == PortNum_NODEINFO_APP) { + DEBUG_MSG("Packet came from - PortNum_NODEINFO_APP\n"); + } else if (mp.decoded.portnum == PortNum_REPLY_APP) { + DEBUG_MSG("Packet came from - PortNum_REPLY_APP\n"); + } else if (mp.decoded.portnum == PortNum_IP_TUNNEL_APP) { + DEBUG_MSG("Packet came from - PortNum_IP_TUNNEL_APP\n"); + } else if (mp.decoded.portnum == PortNum_SERIAL_APP) { + DEBUG_MSG("Packet came from - PortNum_SERIAL_APP\n"); + } else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) { + DEBUG_MSG("Packet came from - PortNum_STORE_FORWARD_APP\n"); + } else if (mp.decoded.portnum == PortNum_RANGE_TEST_APP) { + DEBUG_MSG("Packet came from - PortNum_RANGE_TEST_APP\n"); + } else if (mp.decoded.portnum == PortNum_PRIVATE_APP) { + DEBUG_MSG("Packet came from - PortNum_PRIVATE_APP\n"); + } else if (mp.decoded.portnum == PortNum_RANGE_TEST_APP) { + DEBUG_MSG("Packet came from - PortNum_RANGE_TEST_APP\n"); + } else if (mp.decoded.portnum == PortNum_ATAK_FORWARDER) { + DEBUG_MSG("Packet came from - PortNum_ATAK_FORWARDER\n"); + } else { + DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum); + } + + if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) { + // Node has been away for a while. + storeForwardPlugin->historySend(sawTime, mp.from); + } + } + + } else { + DEBUG_MSG("Store & Forward Plugin - Disabled\n"); + } + +#endif + + return true; // Let others look at this message also if they want +} diff --git a/src/plugins/StoreForwardPlugin.h b/src/plugins/esp32/StoreForwardPlugin.h similarity index 79% rename from src/plugins/StoreForwardPlugin.h rename to src/plugins/esp32/StoreForwardPlugin.h index e44d53704..e49b38fe9 100644 --- a/src/plugins/StoreForwardPlugin.h +++ b/src/plugins/esp32/StoreForwardPlugin.h @@ -6,14 +6,23 @@ #include #include + +struct PacketHistoryStruct { + uint32_t time; + uint32_t to; + bool ack; + uint8_t bytes[MAX_RHPACKETLEN]; +}; + class StoreForwardPlugin : private concurrency::OSThread { bool firstTime = 1; - // TODO: Move this into the PSRAM - // TODO: Allow configuration of the maximum number of records. uint32_t receivedRecord[50][2] = {{0}}; + PacketHistoryStruct *packetHistory; + uint32_t packetHistoryCurrent = 0; + public: StoreForwardPlugin(); @@ -22,9 +31,14 @@ class StoreForwardPlugin : private concurrency::OSThread @return 0 if we have never seen that node before otherwise return the last time we saw the node. */ uint32_t sawNode(uint32_t); + void sawNodeReport(); + void historyAdd(const MeshPacket *mp); + void historyReport(); + void historySend(uint32_t msAgo, uint32_t to); + void populatePSRAM(); private: - // Nothing here + // Nothing here protected: virtual int32_t runOnce();