WIP: S&F Progress

This commit is contained in:
Thomas Göttgens 2022-12-21 12:57:42 +01:00
parent 34c73da886
commit ae2ca1d89c
5 changed files with 255 additions and 198 deletions

@ -1 +1 @@
Subproject commit 737d1fc01bd7f57e48e9b8cd53b780b314b09c5b Subproject commit c70bbf033aee8e0ae0c2cf5c4e1b60ad5782f56f

View File

@ -1,5 +1,5 @@
/* Automatically generated nanopb constant definitions */ /* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.4.6 */ /* Generated by nanopb-0.4.7 */
#include "storeforward.pb.h" #include "storeforward.pb.h"
#if PB_PROTO_HEADER_VERSION != 40 #if PB_PROTO_HEADER_VERSION != 40

View File

@ -1,5 +1,5 @@
/* Automatically generated nanopb header */ /* Automatically generated nanopb header */
/* Generated by nanopb-0.4.6 */ /* Generated by nanopb-0.4.7 */
#ifndef PB_STOREFORWARD_PB_H_INCLUDED #ifndef PB_STOREFORWARD_PB_H_INCLUDED
#define PB_STOREFORWARD_PB_H_INCLUDED #define PB_STOREFORWARD_PB_H_INCLUDED
@ -10,88 +10,124 @@
#endif #endif
/* Enum definitions */ /* Enum definitions */
/* 001 - 063 = From Router
064 - 127 = From Client */
typedef enum _StoreAndForward_RequestResponse { typedef enum _StoreAndForward_RequestResponse {
/* Unset/unused */
StoreAndForward_RequestResponse_UNSET = 0, StoreAndForward_RequestResponse_UNSET = 0,
/* Router is an in error state. */
StoreAndForward_RequestResponse_ROUTER_ERROR = 1, StoreAndForward_RequestResponse_ROUTER_ERROR = 1,
/* Router heartbeat */
StoreAndForward_RequestResponse_ROUTER_HEARTBEAT = 2, StoreAndForward_RequestResponse_ROUTER_HEARTBEAT = 2,
/* Router has requested the client respond. This can work as a
"are you there" message. */
StoreAndForward_RequestResponse_ROUTER_PING = 3, StoreAndForward_RequestResponse_ROUTER_PING = 3,
/* The response to a "Ping" */
StoreAndForward_RequestResponse_ROUTER_PONG = 4, StoreAndForward_RequestResponse_ROUTER_PONG = 4,
/* Router is currently busy. Please try again later. */
StoreAndForward_RequestResponse_ROUTER_BUSY = 5, StoreAndForward_RequestResponse_ROUTER_BUSY = 5,
/* Router is responding to a request for history. */
StoreAndForward_RequestResponse_ROUTER_HISTORY = 6, StoreAndForward_RequestResponse_ROUTER_HISTORY = 6,
StoreAndForward_RequestResponse_CLIENT_ERROR = 101, /* Client is an in error state. */
StoreAndForward_RequestResponse_CLIENT_HISTORY = 102, StoreAndForward_RequestResponse_CLIENT_ERROR = 64,
StoreAndForward_RequestResponse_CLIENT_STATS = 103, /* Client has requested a replay from the router. */
StoreAndForward_RequestResponse_CLIENT_PING = 104, StoreAndForward_RequestResponse_CLIENT_HISTORY = 65,
StoreAndForward_RequestResponse_CLIENT_PONG = 105, /* Client has requested stats from the router. */
StoreAndForward_RequestResponse_CLIENT_STATS = 66,
/* Client has requested the router respond. This can work as a
"are you there" message. */
StoreAndForward_RequestResponse_CLIENT_PING = 67,
/* The response to a "Ping" */
StoreAndForward_RequestResponse_CLIENT_PONG = 68,
/* Client has requested that the router abort processing the client's request */
StoreAndForward_RequestResponse_CLIENT_ABORT = 106 StoreAndForward_RequestResponse_CLIENT_ABORT = 106
} StoreAndForward_RequestResponse; } StoreAndForward_RequestResponse;
/* Struct definitions */ /* Struct definitions */
typedef struct _StoreAndForward_Heartbeat { /* TODO: REPLACE */
uint32_t period; typedef struct _StoreAndForward_Statistics {
uint32_t secondary; /* Number of messages we have ever seen */
} StoreAndForward_Heartbeat; uint32_t messages_total;
/* Number of messages we have currently saved our history. */
uint32_t messages_saved;
/* Maximum number of messages we will save */
uint32_t messages_max;
/* Router uptime in seconds */
uint32_t up_time;
/* Number of times any client sent a request to the S&F. */
uint32_t requests;
/* Number of times the history was requested. */
uint32_t requests_history;
/* Is the heartbeat enabled on the server? */
bool heartbeat;
/* Is the heartbeat enabled on the server? */
uint32_t return_max;
/* Is the heartbeat enabled on the server? */
uint32_t return_window;
} StoreAndForward_Statistics;
/* TODO: REPLACE */
typedef struct _StoreAndForward_History { typedef struct _StoreAndForward_History {
/* Number of that will be sent to the client */
uint32_t history_messages; uint32_t history_messages;
/* The window of messages that was used to filter the history client requested */
uint32_t window; uint32_t window;
/* The window of messages that was used to filter the history client requested */
uint32_t last_request; uint32_t last_request;
} StoreAndForward_History; } StoreAndForward_History;
typedef struct _StoreAndForward_Statistics { /* TODO: REPLACE */
uint32_t messages_total; typedef struct _StoreAndForward_Heartbeat {
uint32_t messages_saved; /* Number of that will be sent to the client */
uint32_t messages_max; uint32_t period;
uint32_t up_time; /* If set, this is not the primary Store & Forward router on the mesh */
uint32_t requests; uint32_t secondary;
uint32_t requests_history; } StoreAndForward_Heartbeat;
bool heartbeat;
uint32_t return_max;
uint32_t return_window;
} StoreAndForward_Statistics;
/* TODO: REPLACE */ /* TODO: REPLACE */
typedef struct _StoreAndForward { typedef struct _StoreAndForward {
/* TODO: REPLACE */ /* TODO: REPLACE */
StoreAndForward_RequestResponse rr; StoreAndForward_RequestResponse rr;
/* TODO: REPLACE */ pb_size_t which_variant;
bool has_stats; union {
StoreAndForward_Statistics stats; /* TODO: REPLACE */
/* TODO: REPLACE */ StoreAndForward_Statistics stats;
bool has_history; /* TODO: REPLACE */
StoreAndForward_History history; StoreAndForward_History history;
/* TODO: REPLACE */ /* TODO: REPLACE */
bool has_heartbeat; StoreAndForward_Heartbeat heartbeat;
StoreAndForward_Heartbeat heartbeat; /* Empty Payload */
bool empty;
} variant;
} StoreAndForward; } StoreAndForward;
/* Helper constants for enums */
#define _StoreAndForward_RequestResponse_MIN StoreAndForward_RequestResponse_UNSET
#define _StoreAndForward_RequestResponse_MAX StoreAndForward_RequestResponse_CLIENT_ABORT
#define _StoreAndForward_RequestResponse_ARRAYSIZE ((StoreAndForward_RequestResponse)(StoreAndForward_RequestResponse_CLIENT_ABORT+1))
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* Helper constants for enums */
#define _StoreAndForward_RequestResponse_MIN StoreAndForward_RequestResponse_UNSET
#define _StoreAndForward_RequestResponse_MAX StoreAndForward_RequestResponse_CLIENT_ABORT
#define _StoreAndForward_RequestResponse_ARRAYSIZE ((StoreAndForward_RequestResponse)(StoreAndForward_RequestResponse_CLIENT_ABORT+1))
#define StoreAndForward_rr_ENUMTYPE StoreAndForward_RequestResponse
/* Initializer values for message structs */ /* Initializer values for message structs */
#define StoreAndForward_init_default {_StoreAndForward_RequestResponse_MIN, false, StoreAndForward_Statistics_init_default, false, StoreAndForward_History_init_default, false, StoreAndForward_Heartbeat_init_default} #define StoreAndForward_init_default {_StoreAndForward_RequestResponse_MIN, 0, {StoreAndForward_Statistics_init_default}}
#define StoreAndForward_Statistics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0} #define StoreAndForward_Statistics_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define StoreAndForward_History_init_default {0, 0, 0} #define StoreAndForward_History_init_default {0, 0, 0}
#define StoreAndForward_Heartbeat_init_default {0, 0} #define StoreAndForward_Heartbeat_init_default {0, 0}
#define StoreAndForward_init_zero {_StoreAndForward_RequestResponse_MIN, false, StoreAndForward_Statistics_init_zero, false, StoreAndForward_History_init_zero, false, StoreAndForward_Heartbeat_init_zero} #define StoreAndForward_init_zero {_StoreAndForward_RequestResponse_MIN, 0, {StoreAndForward_Statistics_init_zero}}
#define StoreAndForward_Statistics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0} #define StoreAndForward_Statistics_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0}
#define StoreAndForward_History_init_zero {0, 0, 0} #define StoreAndForward_History_init_zero {0, 0, 0}
#define StoreAndForward_Heartbeat_init_zero {0, 0} #define StoreAndForward_Heartbeat_init_zero {0, 0}
/* Field tags (for use in manual encoding/decoding) */ /* Field tags (for use in manual encoding/decoding) */
#define StoreAndForward_Heartbeat_period_tag 1
#define StoreAndForward_Heartbeat_secondary_tag 2
#define StoreAndForward_History_history_messages_tag 1
#define StoreAndForward_History_window_tag 2
#define StoreAndForward_History_last_request_tag 3
#define StoreAndForward_Statistics_messages_total_tag 1 #define StoreAndForward_Statistics_messages_total_tag 1
#define StoreAndForward_Statistics_messages_saved_tag 2 #define StoreAndForward_Statistics_messages_saved_tag 2
#define StoreAndForward_Statistics_messages_max_tag 3 #define StoreAndForward_Statistics_messages_max_tag 3
@ -101,22 +137,29 @@ extern "C" {
#define StoreAndForward_Statistics_heartbeat_tag 7 #define StoreAndForward_Statistics_heartbeat_tag 7
#define StoreAndForward_Statistics_return_max_tag 8 #define StoreAndForward_Statistics_return_max_tag 8
#define StoreAndForward_Statistics_return_window_tag 9 #define StoreAndForward_Statistics_return_window_tag 9
#define StoreAndForward_History_history_messages_tag 1
#define StoreAndForward_History_window_tag 2
#define StoreAndForward_History_last_request_tag 3
#define StoreAndForward_Heartbeat_period_tag 1
#define StoreAndForward_Heartbeat_secondary_tag 2
#define StoreAndForward_rr_tag 1 #define StoreAndForward_rr_tag 1
#define StoreAndForward_stats_tag 2 #define StoreAndForward_stats_tag 2
#define StoreAndForward_history_tag 3 #define StoreAndForward_history_tag 3
#define StoreAndForward_heartbeat_tag 4 #define StoreAndForward_heartbeat_tag 4
#define StoreAndForward_empty_tag 5
/* Struct field encoding specification for nanopb */ /* Struct field encoding specification for nanopb */
#define StoreAndForward_FIELDLIST(X, a) \ #define StoreAndForward_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, rr, 1) \ X(a, STATIC, SINGULAR, UENUM, rr, 1) \
X(a, STATIC, OPTIONAL, MESSAGE, stats, 2) \ X(a, STATIC, ONEOF, MESSAGE, (variant,stats,variant.stats), 2) \
X(a, STATIC, OPTIONAL, MESSAGE, history, 3) \ X(a, STATIC, ONEOF, MESSAGE, (variant,history,variant.history), 3) \
X(a, STATIC, OPTIONAL, MESSAGE, heartbeat, 4) X(a, STATIC, ONEOF, MESSAGE, (variant,heartbeat,variant.heartbeat), 4) \
X(a, STATIC, ONEOF, BOOL, (variant,empty,variant.empty), 5)
#define StoreAndForward_CALLBACK NULL #define StoreAndForward_CALLBACK NULL
#define StoreAndForward_DEFAULT NULL #define StoreAndForward_DEFAULT NULL
#define StoreAndForward_stats_MSGTYPE StoreAndForward_Statistics #define StoreAndForward_variant_stats_MSGTYPE StoreAndForward_Statistics
#define StoreAndForward_history_MSGTYPE StoreAndForward_History #define StoreAndForward_variant_history_MSGTYPE StoreAndForward_History
#define StoreAndForward_heartbeat_MSGTYPE StoreAndForward_Heartbeat #define StoreAndForward_variant_heartbeat_MSGTYPE StoreAndForward_Heartbeat
#define StoreAndForward_Statistics_FIELDLIST(X, a) \ #define StoreAndForward_Statistics_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, messages_total, 1) \ X(a, STATIC, SINGULAR, UINT32, messages_total, 1) \
@ -159,7 +202,7 @@ extern const pb_msgdesc_t StoreAndForward_Heartbeat_msg;
#define StoreAndForward_Heartbeat_size 12 #define StoreAndForward_Heartbeat_size 12
#define StoreAndForward_History_size 18 #define StoreAndForward_History_size 18
#define StoreAndForward_Statistics_size 50 #define StoreAndForward_Statistics_size 50
#define StoreAndForward_size 88 #define StoreAndForward_size 54
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */

View File

@ -22,41 +22,31 @@ int32_t StoreForwardModule::runOnce()
if (this->busy) { if (this->busy) {
// Only send packets if the channel is less than 25% utilized. // Only send packets if the channel is less than 25% utilized.
if (airTime->channelUtilizationPercent() < polite_channel_util_percent) { if (airTime->channelUtilizationPercent() < polite_channel_util_percent) {
// DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index);
storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); storeForwardModule->sendPayload(this->busyTo, this->packetHistoryTXQueue_index);
if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) { if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
strcpy(this->routerMessage, "** S&F - Done"); // Tell the client we're done sending
storeForwardModule->sendMessage(this->busyTo, this->routerMessage); StoreAndForward sf = StoreAndForward_init_zero;
sf.rr = StoreAndForward_RequestResponse_ROUTER_PING;
// DEBUG_MSG("--- --- --- In busy loop - Done \n"); storeForwardModule->sendMessage(this->busyTo, sf);
DEBUG_MSG("*** S&F - Done. (ROUTER_PING)\n");
this->packetHistoryTXQueue_index = 0; this->packetHistoryTXQueue_index = 0;
this->busy = false; this->busy = false;
} else { } else {
this->packetHistoryTXQueue_index++; this->packetHistoryTXQueue_index++;
} }
} else { } else {
DEBUG_MSG("Channel utilization is too high. Retrying later.\n"); DEBUG_MSG("*** Channel utilization is too high. Retrying later.\n");
} }
DEBUG_MSG("SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate); DEBUG_MSG("*** SF bitrate = %f bytes / sec\n", myNodeInfo.bitrate);
} else if (millis() - lastHeartbeat > 300000) { } else if ((millis() - lastHeartbeat > (heartbeatInterval * 1000)) && (airTime->channelUtilizationPercent() < polite_channel_util_percent)) {
lastHeartbeat = millis(); lastHeartbeat = millis();
DEBUG_MSG("Sending heartbeat\n"); DEBUG_MSG("*** Sending heartbeat\n");
StoreAndForward sf; StoreAndForward sf;
sf.rr = StoreAndForward_RequestResponse_ROUTER_HEARTBEAT; sf.rr = StoreAndForward_RequestResponse_ROUTER_HEARTBEAT;
sf.has_heartbeat = true; sf.variant.heartbeat.period = 300;
sf.heartbeat.period = 300; sf.variant.heartbeat.secondary = 0; // TODO we always have one primary router for now
sf.heartbeat.secondary = 0; // TODO we always have one primary router for now storeForwardModule->sendMessage(NODENUM_BROADCAST, sf);
MeshPacket *p = allocDataProtobuf(sf);
p->to = NODENUM_BROADCAST;
p->decoded.want_response = false;
p->priority = MeshPacket_Priority_MIN;
service.sendToMesh(p);
} }
return (this->packetTimeMax); return (this->packetTimeMax);
} }
@ -74,7 +64,7 @@ void StoreForwardModule::populatePSRAM()
https://learn.upesy.com/en/programmation/psram.html#psram-tab https://learn.upesy.com/en/programmation/psram.html#psram-tab
*/ */
DEBUG_MSG("Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize()); DEBUG_MSG("*** Before PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
this->packetHistoryTXQueue = this->packetHistoryTXQueue =
static_cast<PacketHistoryStruct *>(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct))); static_cast<PacketHistoryStruct *>(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct)));
@ -83,46 +73,35 @@ void StoreForwardModule::populatePSRAM()
Note: This needs to be done after every thing that would use PSRAM Note: This needs to be done after every thing that would use PSRAM
*/ */
uint32_t numberOfPackets = (this->records ? this->records : (((ESP.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct))); uint32_t numberOfPackets = (this->records ? this->records : (((ESP.getFreePsram() / 3) * 2) / sizeof(PacketHistoryStruct)));
this->records = numberOfPackets;
this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct))); this->packetHistory = static_cast<PacketHistoryStruct *>(ps_calloc(numberOfPackets, sizeof(PacketHistoryStruct)));
DEBUG_MSG("After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize()); DEBUG_MSG("*** After PSRAM initilization: heap %d/%d PSRAM %d/%d\n", ESP.getFreeHeap(), ESP.getHeapSize(), ESP.getFreePsram(), ESP.getPsramSize());
DEBUG_MSG("numberOfPackets for packetHistory - %u\n", numberOfPackets); DEBUG_MSG("*** numberOfPackets for packetHistory - %u\n", numberOfPackets);
} }
void StoreForwardModule::historyReport()
{
DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent);
}
/*
*
*/
void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to) void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to)
{ {
// uint32_t packetsSent = 0;
uint32_t queueSize = storeForwardModule->historyQueueCreate(msAgo, to); uint32_t queueSize = storeForwardModule->historyQueueCreate(msAgo, to);
if (queueSize) { if (queueSize) {
snprintf(this->routerMessage, 80, "** S&F - Sending %u message(s)", queueSize); DEBUG_MSG ("*** S&F - Sending %u message(s)\n", queueSize);
storeForwardModule->sendMessage(to, this->routerMessage);
this->busy = true; // runOnce() will pickup the next steps once busy = true. this->busy = true; // runOnce() will pickup the next steps once busy = true.
this->busyTo = to; this->busyTo = to;
} else { } else {
strcpy(this->routerMessage, "** S&F - No history to send"); DEBUG_MSG ("*** S&F - No history to send\n");
storeForwardModule->sendMessage(to, this->routerMessage);
} }
StoreAndForward sf = StoreAndForward_init_zero;
sf.rr = StoreAndForward_RequestResponse_ROUTER_HISTORY;
sf.which_variant = StoreAndForward_history_tag;
sf.variant.history.history_messages = queueSize;
storeForwardModule->sendMessage(to, sf);
} }
uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to) uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
{ {
// uint32_t packetHistoryTXQueueIndex = 0;
this->packetHistoryTXQueue_size = 0; this->packetHistoryTXQueue_size = 0;
for (int i = 0; i < this->packetHistoryCurrent; i++) { for (int i = 0; i < this->packetHistoryCurrent; i++) {
@ -133,7 +112,7 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
DEBUG_MSG("SF historyQueueCreate - math %d\n", (millis() - msAgo)); DEBUG_MSG("SF historyQueueCreate - math %d\n", (millis() - msAgo));
*/ */
if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) { if (this->packetHistory[i].time && (this->packetHistory[i].time < (millis() - msAgo))) {
DEBUG_MSG("SF historyQueueCreate - Time matches - ok\n"); DEBUG_MSG("*** SF historyQueueCreate - Time matches - ok\n");
/* /*
Copy the messages that were received by the router in the last msAgo Copy the messages that were received by the router in the last msAgo
to the packetHistoryTXQueue structure. to the packetHistoryTXQueue structure.
@ -144,7 +123,6 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
if ((this->packetHistory[i].to & NODENUM_BROADCAST) == NODENUM_BROADCAST || if ((this->packetHistory[i].to & NODENUM_BROADCAST) == NODENUM_BROADCAST ||
((this->packetHistory[i].to & NODENUM_BROADCAST) == to)) { ((this->packetHistory[i].to & NODENUM_BROADCAST) == to)) {
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].time = this->packetHistory[i].time;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].to = this->packetHistory[i].to;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel; this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel;
@ -153,9 +131,8 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
Constants_DATA_PAYLOAD_LEN); Constants_DATA_PAYLOAD_LEN);
this->packetHistoryTXQueue_size++; this->packetHistoryTXQueue_size++;
DEBUG_MSG("PacketHistoryStruct time=%d\n", this->packetHistory[i].time); DEBUG_MSG("*** PacketHistoryStruct time=%d\n", this->packetHistory[i].time);
DEBUG_MSG("PacketHistoryStruct msg=%.*s\n", this->packetHistory[i].payload); DEBUG_MSG("*** PacketHistoryStruct msg=%s\n", this->packetHistory[i].payload);
// DEBUG_MSG("PacketHistoryStruct msg=%.*s\n", this->packetHistoryTXQueue[packetHistoryTXQueueIndex].payload);
} }
} }
} }
@ -174,6 +151,7 @@ void StoreForwardModule::historyAdd(const MeshPacket &mp)
memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, Constants_DATA_PAYLOAD_LEN); memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, Constants_DATA_PAYLOAD_LEN);
this->packetHistoryCurrent++; this->packetHistoryCurrent++;
this->packetHistoryMax++;
} }
MeshPacket *StoreForwardModule::allocReply() MeshPacket *StoreForwardModule::allocReply()
@ -184,7 +162,7 @@ MeshPacket *StoreForwardModule::allocReply()
void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index) void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index)
{ {
DEBUG_MSG("Sending S&F Payload\n"); DEBUG_MSG("*** Sending S&F Payload\n");
MeshPacket *p = allocReply(); MeshPacket *p = allocReply();
p->to = dest; p->to = dest;
@ -203,12 +181,14 @@ void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index)
service.sendToMesh(p); service.sendToMesh(p);
} }
void StoreForwardModule::sendMessage(NodeNum dest, char *str) void StoreForwardModule::sendMessage(NodeNum dest, StoreAndForward payload)
{ {
MeshPacket *p = allocReply(); MeshPacket *p = allocDataProtobuf(payload);
p->to = dest; p->to = dest;
p->priority = MeshPacket_Priority_MIN;
// FIXME - Determine if the delayed packet is broadcast or delayed. For now, assume // FIXME - Determine if the delayed packet is broadcast or delayed. For now, assume
// everything is broadcast. // everything is broadcast.
p->delayed = MeshPacket_Delayed_DELAYED_BROADCAST; p->delayed = MeshPacket_Delayed_DELAYED_BROADCAST;
@ -216,60 +196,59 @@ void StoreForwardModule::sendMessage(NodeNum dest, char *str)
// Let's assume that if the router received the S&F request that the client is in range. // Let's assume that if the router received the S&F request that the client is in range.
// TODO: Make this configurable. // TODO: Make this configurable.
p->want_ack = false; p->want_ack = false;
p->decoded.want_response = false;
p->decoded.payload.size = strlen(str); // You must specify how many bytes are in the reply
memcpy(p->decoded.payload.bytes, str, strlen(str));
service.sendToMesh(p); service.sendToMesh(p);
// HardwareMessage_init_default // HardwareMessage_init_default
} }
void StoreForwardModule::statsSend(uint32_t to)
{
StoreAndForward sf;
sf.which_variant = StoreAndForward_stats_tag;
sf.variant.stats.messages_total = this->packetHistoryMax;
sf.variant.stats.messages_saved = this->packetHistoryCurrent;
sf.variant.stats.messages_max = this->records;
sf.variant.stats.up_time = millis() / 1000;
sf.variant.stats.requests = this->requests;
sf.variant.stats.requests_history = this->requests_history;
sf.variant.stats.heartbeat = this->heartbeat;
sf.variant.stats.return_max = this->historyReturnMax;
sf.variant.stats.return_window = this->historyReturnWindow;
DEBUG_MSG("*** Sending S&F Stats\n");
storeForwardModule->sendMessage(to, sf);
}
ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp) ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
{ {
#ifdef ARCH_ESP32 #ifdef ARCH_ESP32
if (moduleConfig.store_forward.enabled) { if (moduleConfig.store_forward.enabled) {
DEBUG_MSG("--- S&F Received something\n");
// The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT // The router node should not be sending messages as a client. Unless he is a ROUTER_CLIENT
if ((getFrom(&mp) != nodeDB.getNodeNum()) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) { if ((getFrom(&mp) != nodeDB.getNodeNum()) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) { if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n"); storeForwardModule->historyAdd(mp);
DEBUG_MSG("*** S&F stored. Message history contains %u records now.\n", this->packetHistoryCurrent);
auto &p = mp.decoded;
if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 0x00)) {
DEBUG_MSG("--- --- --- Request to send\n");
// Send the last 60 minutes of messages.
if (this->busy) {
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
} else {
storeForwardModule->historySend(1000 * 60, getFrom(&mp));
}
} else if ((p.payload.bytes[0] == 'S') && (p.payload.bytes[1] == 'F') && (p.payload.bytes[2] == 'm') &&
(p.payload.bytes[3] == 0x00)) {
strlcpy(this->routerMessage,
"01234567890123456789012345678901234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789012345678901234567890123456789"
"01234567890123456789012345678901234567890123456789012345678901234567890123456",
sizeof(this->routerMessage));
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
} else {
storeForwardModule->historyAdd(mp);
}
} else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) { } else if (mp.decoded.portnum == PortNum_STORE_FORWARD_APP) {
DEBUG_MSG("Packet came from an PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum); auto &p = mp.decoded;
StoreAndForward scratch;
} else { StoreAndForward *decoded = NULL;
DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum); if (mp.which_payload_variant == MeshPacket_decoded_tag) {
} if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &StoreAndForward_msg, &scratch)) {
decoded = &scratch;
} else {
DEBUG_MSG("Error decoding protobuf module!\n");
// if we can't decode it, nobody can process it!
return ProcessMessage::STOP;
}
return handleReceivedProtobuf(mp, decoded) ? ProcessMessage::STOP : ProcessMessage::CONTINUE;
}
} // all others are irrelevant
} }
} }
@ -285,95 +264,115 @@ bool StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndFo
return false; return false;
} }
if (mp.decoded.portnum != PortNum_STORE_FORWARD_APP) { requests++;
DEBUG_MSG("Packet came from port %u\n", mp.decoded.portnum);
return false;
} else {
DEBUG_MSG("Packet came from PortNum_STORE_FORWARD_APP port %u\n", mp.decoded.portnum);
switch (p->rr) { switch (p->rr) {
case StoreAndForward_RequestResponse_CLIENT_ERROR: case StoreAndForward_RequestResponse_CLIENT_ERROR:
case StoreAndForward_RequestResponse_CLIENT_ABORT:
if(is_server) { if(is_server) {
// Do nothing // stop sending stuff, the client wants to abort or has another error
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n"); if ((this->busy) && (this->busyTo == getFrom(&mp))) {
DEBUG_MSG("*** Client in ERROR or ABORT requested\n");
this->packetHistoryTXQueue_index = 0;
this->busy = false;
}
} }
break; break;
case StoreAndForward_RequestResponse_CLIENT_HISTORY: case StoreAndForward_RequestResponse_CLIENT_HISTORY:
if(is_server) { if(is_server) {
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_HISTORY\n"); requests_history++;
DEBUG_MSG("*** Client Request to send HISTORY\n");
// Send the last 60 minutes of messages. // Send the last 60 minutes of messages.
if (this->busy) { if (this->busy) {
strcpy(this->routerMessage, "** S&F - Busy. Try again shortly."); StoreAndForward sf = StoreAndForward_init_zero;
storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage); sf.rr = StoreAndForward_RequestResponse_ROUTER_BUSY;
storeForwardModule->sendMessage(getFrom(&mp), sf);
DEBUG_MSG("*** S&F - Busy. Try again shortly.\n");
} else { } else {
storeForwardModule->historySend(1000 * 60, getFrom(&mp)); if ((p->which_variant == StoreAndForward_history_tag) && (p->variant.history.window > 0)){
storeForwardModule->historySend(p->variant.history.window * 1000 * 60, getFrom(&mp)); // window is in minutes
} else {
storeForwardModule->historySend(60 * 1000 * 60, getFrom(&mp)); // defaults to 60 minutes
}
} }
} }
break; break;
case StoreAndForward_RequestResponse_CLIENT_PING: case StoreAndForward_RequestResponse_CLIENT_PING:
if(is_server) { if(is_server) {
// Do nothing DEBUG_MSG("*** StoreAndForward_RequestResponse_CLIENT_PING\n");
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PING\n"); // respond with a ROUTER PONG
StoreAndForward sf = StoreAndForward_init_zero;
sf.rr = StoreAndForward_RequestResponse_ROUTER_PONG;
storeForwardModule->sendMessage(getFrom(&mp), sf);
} }
break; break;
case StoreAndForward_RequestResponse_CLIENT_PONG: case StoreAndForward_RequestResponse_CLIENT_PONG:
if(is_server) { if(is_server) {
// Do nothing DEBUG_MSG("*** StoreAndForward_RequestResponse_CLIENT_PONG\n");
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PONG\n"); // The Client is alive, update NodeDB
nodeDB.updateFrom(mp);
} }
break; break;
case StoreAndForward_RequestResponse_CLIENT_STATS: case StoreAndForward_RequestResponse_CLIENT_STATS:
if(is_server) { if(is_server) {
// Do nothing DEBUG_MSG("*** Client Request to send STATS\n");
DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_STATS\n"); if (this->busy) {
StoreAndForward sf = StoreAndForward_init_zero;
sf.rr = StoreAndForward_RequestResponse_ROUTER_BUSY;
storeForwardModule->sendMessage(getFrom(&mp), sf);
DEBUG_MSG("*** S&F - Busy. Try again shortly.\n");
} else {
storeForwardModule->statsSend(getFrom(&mp));
}
} }
break; break;
case StoreAndForward_RequestResponse_ROUTER_BUSY: case StoreAndForward_RequestResponse_ROUTER_BUSY:
if(is_client) { if(is_client) {
// Do nothing DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_BUSY\n");
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_BUSY\n"); // retry in messages_saved * packetTimeMax ms
retry_delay = millis() + packetHistoryCurrent * packetTimeMax;
} }
break; break;
case StoreAndForward_RequestResponse_ROUTER_ERROR: case StoreAndForward_RequestResponse_ROUTER_ERROR:
if(is_client) { if(is_client) {
// Do nothing DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_ERROR\n");
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_ERROR\n"); // retry in messages_saved * packetTimeMax * 2 ms
retry_delay = millis() + packetHistoryCurrent * packetTimeMax * 2;
} }
break; break;
case StoreAndForward_RequestResponse_ROUTER_PONG:
// A router responded, this is equal to receiving a heartbeat
case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT: case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT:
if(is_client) { if(is_client) {
// Do nothing // register heartbeat and interval
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_HEARTBEAT\n"); if (p->which_variant == StoreAndForward_heartbeat_tag) {
heartbeatInterval = p->variant.heartbeat.period;
}
lastHeartbeat = millis();
DEBUG_MSG("*** StoreAndForward Heartbeat received\n");
} }
break; break;
case StoreAndForward_RequestResponse_ROUTER_PING: case StoreAndForward_RequestResponse_ROUTER_PING:
if(is_client) { if(is_client) {
// Do nothing DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_PING\n");
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PING\n"); // respond with a CLIENT PONG
} StoreAndForward sf = StoreAndForward_init_zero;
break; sf.rr = StoreAndForward_RequestResponse_CLIENT_PONG;
storeForwardModule->sendMessage(getFrom(&mp), sf);
case StoreAndForward_RequestResponse_ROUTER_PONG:
if(is_client) {
// Do nothing
DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PONG\n");
} }
break; break;
default: default:
assert(0); // unexpected state - FIXME, make an error code and reboot assert(0); // unexpected state - FIXME, make an error code and reboot
}
} }
return true; // There's no need for others to look at this message. return true; // There's no need for others to look at this message.
} }
@ -398,7 +397,7 @@ StoreForwardModule::StoreForwardModule()
// Router // Router
if ((config.device.role == Config_DeviceConfig_Role_ROUTER) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) { if ((config.device.role == Config_DeviceConfig_Role_ROUTER) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
DEBUG_MSG("Initializing Store & Forward Module in Router mode\n"); DEBUG_MSG("*** Initializing Store & Forward Module in Router mode\n");
if (ESP.getPsramSize() > 0) { if (ESP.getPsramSize() > 0) {
if (ESP.getFreePsram() >= 1024 * 1024) { if (ESP.getFreePsram() >= 1024 * 1024) {
@ -424,19 +423,19 @@ StoreForwardModule::StoreForwardModule()
this->populatePSRAM(); this->populatePSRAM();
is_server = true; is_server = true;
} else { } else {
DEBUG_MSG("Device has less than 1M of PSRAM free.\n"); DEBUG_MSG("*** Device has less than 1M of PSRAM free.\n");
DEBUG_MSG("Store & Forward Module - disabling server.\n"); DEBUG_MSG("*** Store & Forward Module - disabling server.\n");
} }
} else { } else {
DEBUG_MSG("Device doesn't have PSRAM.\n"); DEBUG_MSG("*** Device doesn't have PSRAM.\n");
DEBUG_MSG("Store & Forward Module - disabling server.\n"); DEBUG_MSG("*** Store & Forward Module - disabling server.\n");
} }
// Client // Client
} }
if ((config.device.role == Config_DeviceConfig_Role_CLIENT) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) { if ((config.device.role == Config_DeviceConfig_Role_CLIENT) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
is_client = true; is_client = true;
DEBUG_MSG("Initializing Store & Forward Module in Client mode\n"); DEBUG_MSG("*** Initializing Store & Forward Module in Client mode\n");
} }
} }
#endif #endif

View File

@ -24,10 +24,9 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
uint32_t busyTo = 0; uint32_t busyTo = 0;
char routerMessage[Constants_DATA_PAYLOAD_LEN] = {0}; char routerMessage[Constants_DATA_PAYLOAD_LEN] = {0};
uint32_t receivedRecord[50][2] = {{0}};
PacketHistoryStruct *packetHistory = 0; PacketHistoryStruct *packetHistory = 0;
uint32_t packetHistoryCurrent = 0; uint32_t packetHistoryCurrent = 0;
uint32_t packetHistoryMax = 0;
PacketHistoryStruct *packetHistoryTXQueue = 0; PacketHistoryStruct *packetHistoryTXQueue = 0;
uint32_t packetHistoryTXQueue_size = 0; uint32_t packetHistoryTXQueue_size = 0;
@ -35,20 +34,21 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
uint32_t packetTimeMax = 5000; uint32_t packetTimeMax = 5000;
unsigned long lastHeartbeat = 0;
bool is_client = false; bool is_client = false;
bool is_server = false; bool is_server = false;
public: public:
StoreForwardModule(); StoreForwardModule();
unsigned long lastHeartbeat = 0;
uint32_t heartbeatInterval = 300;
/** /**
Update our local reference of when we last saw that node. Update our local reference of when we last saw that node.
@return 0 if we have never seen that node before otherwise return the last time we saw the node. @return 0 if we have never seen that node before otherwise return the last time we saw the node.
*/ */
void historyAdd(const MeshPacket &mp); void historyAdd(const MeshPacket &mp);
void historyReport(); void statsSend(uint32_t to);
void historySend(uint32_t msAgo, uint32_t to); void historySend(uint32_t msAgo, uint32_t to);
uint32_t historyQueueCreate(uint32_t msAgo, uint32_t to); uint32_t historyQueueCreate(uint32_t msAgo, uint32_t to);
@ -57,12 +57,21 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
* Send our payload into the mesh * Send our payload into the mesh
*/ */
void sendPayload(NodeNum dest = NODENUM_BROADCAST, uint32_t packetHistory_index = 0); void sendPayload(NodeNum dest = NODENUM_BROADCAST, uint32_t packetHistory_index = 0);
void sendMessage(NodeNum dest, char *str); void sendMessage(NodeNum dest, StoreAndForward payload);
virtual MeshPacket *allocReply() override; virtual MeshPacket *allocReply() override;
/* /*
Override the wantPortnum method. -Override the wantPacket method.
*/ */
virtual bool wantPortnum(PortNum p) { return true; }; virtual bool wantPacket(const MeshPacket *p) override
{
switch(p->decoded.portnum) {
case PortNum_TEXT_MESSAGE_APP:
case PortNum_STORE_FORWARD_APP:
return true;
default:
return false;
}
}
private: private:
void populatePSRAM(); void populatePSRAM();
@ -73,6 +82,12 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
uint32_t records = 0; // Calculated uint32_t records = 0; // Calculated
bool heartbeat = false; // No heartbeat. bool heartbeat = false; // No heartbeat.
// stats
uint32_t requests = 0;
uint32_t requests_history = 0;
uint32_t retry_delay = 0;
protected: protected:
virtual int32_t runOnce() override; virtual int32_t runOnce() override;