diff --git a/boards/tlora-t3s3-v1.json b/boards/tlora-t3s3-v1.json
new file mode 100644
index 00000000..36a54ad2
--- /dev/null
+++ b/boards/tlora-t3s3-v1.json
@@ -0,0 +1,47 @@
+{
+ "build": {
+ "arduino": {
+ "ldscript": "esp32s3_out.ld"
+ },
+ "core": "esp32",
+ "extra_flags": [
+ "-DLILYGO_T3S3_V1",
+ "-DARDUINO_USB_CDC_ON_BOOT=1",
+ "-DARDUINO_USB_MODE=0",
+ "-DARDUINO_RUNNING_CORE=1",
+ "-DARDUINO_EVENT_RUNNING_CORE=1"
+ ],
+ "f_cpu": "240000000L",
+ "f_flash": "80000000L",
+ "flash_mode": "dio",
+ "hwids": [
+ [
+ "0X303A",
+ "0x1001"
+ ]
+ ],
+ "mcu": "esp32s3",
+ "variant": "tlora-t3s3-v1"
+ },
+ "connectivity": [
+ "wifi"
+ ],
+ "debug": {
+ "openocd_target": "esp32s3.cfg"
+ },
+ "frameworks": [
+ "arduino",
+ "espidf"
+ ],
+ "name": "LilyGo TLora-T3S3-V1",
+ "upload": {
+ "flash_size": "4MB",
+ "maximum_ram_size": 327680,
+ "maximum_size": 4194304,
+ "wait_for_upload_port": true,
+ "require_upload_port": true,
+ "speed": 921600
+ },
+ "url": "http://www.lilygo.cn/",
+ "vendor": "LilyGo"
+}
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
index 4461d1a5..e58656dd 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -65,7 +65,8 @@ lib_deps =
https://github.com/meshtastic/ArduinoThread.git#72921ac222eed6f526ba1682023cee290d9aa1b3
nanopb/Nanopb@^0.4.6
erriez/ErriezCRC32@^1.0.1
- jgromes/RadioLib@^5.5.0
+; jgromes/RadioLib@^5.5.1
+ https://github.com/jgromes/RadioLib.git#395844922c5d88d5db0481a9c91479931172428d
; Used for the code analysis in PIO Home / Inspect
check_tool = cppcheck
@@ -81,6 +82,7 @@ framework = arduino
lib_deps =
${env.lib_deps}
mprograms/QMC5883LCompass@^1.1.1
+ end2endzone/NonBlockingRTTTL@^1.3.0
https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#52b5282639d08a8cbd4b748363089eed6102dc76
build_flags = ${env.build_flags} -Os -DRADIOLIB_SPI_PARANOID=0
diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp
index e60056cc..5bea8d79 100644
--- a/src/PowerFSM.cpp
+++ b/src/PowerFSM.cpp
@@ -327,9 +327,7 @@ void PowerFSM_setup()
powerFSM.add_timed_transition(&stateON, &stateDARK, getConfiguredOrDefaultMs(config.display.screen_on_secs, default_screen_on_secs), NULL, "Screen-on timeout");
#ifdef ARCH_ESP32
- // On most boards we use light-sleep to be our main state, but on NRF52 we just stay in DARK
State *lowPowerState = &stateLS;
-
// We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally)
// See: https://github.com/meshtastic/firmware/issues/1071
diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp
index b7854b2c..e7355db2 100644
--- a/src/SerialConsole.cpp
+++ b/src/SerialConsole.cpp
@@ -25,7 +25,7 @@ void consolePrintf(const char *format, ...)
#endif
}
-SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
+SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole")
{
assert(!console);
console = this;
@@ -46,6 +46,10 @@ SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port)
emitRebooted();
}
+int32_t SerialConsole::runOnce()
+{
+ return runOncePart();
+}
// For the serial port we can't really detect if any client is on the other side, so instead just look for recent messages
bool SerialConsole::checkIsConnected()
diff --git a/src/SerialConsole.h b/src/SerialConsole.h
index e7b8af34..d1f2abac 100644
--- a/src/SerialConsole.h
+++ b/src/SerialConsole.h
@@ -6,7 +6,7 @@
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
*/
-class SerialConsole : public StreamAPI, public RedirectablePrint
+class SerialConsole : public StreamAPI, public RedirectablePrint, private concurrency::OSThread
{
public:
SerialConsole();
@@ -24,6 +24,8 @@ class SerialConsole : public StreamAPI, public RedirectablePrint
return RedirectablePrint::write(c);
}
+ virtual int32_t runOnce() override;
+
protected:
/// Check the current underlying physical link to see if the client is currently connected
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 8d342945..7b34aee5 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -35,7 +35,7 @@ along with this program. If not, see .
#include "mesh/Channels.h"
#include "mesh/generated/deviceonly.pb.h"
#include "modules/TextMessageModule.h"
-
+#include "modules/ExternalNotificationModule.h"
#include "sleep.h"
#include "target_specific.h"
#include "utils.h"
@@ -1071,7 +1071,13 @@ int32_t Screen::runOnce()
handleSetOn(false);
break;
case Cmd::ON_PRESS:
- handleOnPress();
+ // If a nag notification is running, stop it
+ if (externalNotificationModule->nagCycleCutoff != UINT32_MAX) {
+ externalNotificationModule->stopNow();
+ } else {
+ // Don't advance the screen if we just wanted to switch off the nag notification
+ handleOnPress();
+ }
break;
case Cmd::START_BLUETOOTH_PIN_SCREEN:
handleStartBluetoothPinScreen(cmd.bluetooth_pin);
@@ -1400,7 +1406,7 @@ void DebugInfo::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
if (moduleConfig.store_forward.enabled) {
-#if 0
+#ifdef ARCH_ESP32
if (millis() - storeForwardModule->lastHeartbeat > (storeForwardModule->heartbeatInterval * 1200)) { //no heartbeat, overlap a bit
#if defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ST7735_CS)
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8, imgQuestionL1);
diff --git a/src/main.cpp b/src/main.cpp
index c0fcaf96..f999ac70 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -242,7 +242,6 @@ void setup()
digitalWrite(PIN_3V3_EN, 1);
#endif
-
// Currently only the tbeam has a PMU
// PMU initialization needs to be placed before scanI2Cdevice
power = new Power();
@@ -462,17 +461,6 @@ if((config.lora.region == Config_LoRaConfig_RegionCode_LORA_24) && (!rIf->wideLo
}
}
-if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (rIf->wideLora())){
- DEBUG_MSG("Warning: Radio chip only supports 2.4GHz LoRa. Adjusting Region.\n");
- config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
- nodeDB.saveToDisk(SEGMENT_CONFIG);
- if(!rIf->reconfigure()) {
- DEBUG_MSG("Reconfigure failed, rebooting\n");
- screen->startRebootScreen();
- rebootAtMsec = millis() + 5000;
- }
-}
-
#if HAS_WIFI || HAS_ETHERNET
mqttInit();
#endif
diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp
index 92573590..e2182030 100644
--- a/src/mesh/FloodingRouter.cpp
+++ b/src/mesh/FloodingRouter.cpp
@@ -17,7 +17,7 @@ ErrorCode FloodingRouter::send(MeshPacket *p)
return Router::send(p);
}
-bool FloodingRouter::shouldFilterReceived(MeshPacket *p)
+bool FloodingRouter::shouldFilterReceived(const MeshPacket *p)
{
if (wasSeenRecently(p)) { // Note: this will also add a recent packet record
printPacket("Ignoring incoming msg, because we've already seen it", p);
@@ -34,7 +34,8 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
// do not flood direct message that is ACKed
DEBUG_MSG("Receiving an ACK not for me, but don't need to rebroadcast this direct message anymore.\n");
Router::cancelSending(p->to, p->decoded.request_id); // cancel rebroadcast for this DM
- } else if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
+ }
+ if ((p->to != getNodeNum()) && (p->hop_limit > 0) && (getFrom(p) != getNodeNum())) {
if (p->id != 0) {
if (config.device.role != Config_DeviceConfig_Role_CLIENT_MUTE) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it
diff --git a/src/mesh/FloodingRouter.h b/src/mesh/FloodingRouter.h
index 7e6271fc..01b51c9a 100644
--- a/src/mesh/FloodingRouter.h
+++ b/src/mesh/FloodingRouter.h
@@ -51,7 +51,7 @@ class FloodingRouter : public Router, protected PacketHistory
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
*/
- virtual bool shouldFilterReceived(MeshPacket *p) override;
+ virtual bool shouldFilterReceived(const MeshPacket *p) override;
/**
* Look for broadcasts we need to rebroadcast
diff --git a/src/mesh/MeshModule.cpp b/src/mesh/MeshModule.cpp
index ca1fb5b5..8019cda1 100644
--- a/src/mesh/MeshModule.cpp
+++ b/src/mesh/MeshModule.cpp
@@ -44,11 +44,11 @@ MeshPacket *MeshModule::allocAckNak(Routing_Error err, NodeNum to, PacketId idFr
// auto p = allocDataProtobuf(c);
MeshPacket *p = router->allocForSending();
p->decoded.portnum = PortNum_ROUTING_APP;
- p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Routing_fields, &c);
+ p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Routing_msg, &c);
p->priority = MeshPacket_Priority_ACK;
- p->hop_limit = 0; // Assume just immediate neighbors for now
+ p->hop_limit = config.lora.hop_limit; // Flood ACK back to original sender
p->to = to;
p->decoded.request_id = idFrom;
p->channel = chIndex;
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 1e40b8d9..b9107515 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -401,7 +401,7 @@ bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_
void NodeDB::loadFromDisk()
{
// static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM
- if (!loadProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate)) {
+ if (!loadProto(prefFileName, DeviceState_size, sizeof(DeviceState), &DeviceState_msg, &devicestate)) {
installDefaultDeviceState(); // Our in RAM copy might now be corrupt
} else {
if (devicestate.version < DEVICESTATE_MIN_VER) {
@@ -412,7 +412,7 @@ void NodeDB::loadFromDisk()
}
}
- if (!loadProto(configFileName, LocalConfig_size, sizeof(LocalConfig), LocalConfig_fields, &config)) {
+ if (!loadProto(configFileName, LocalConfig_size, sizeof(LocalConfig), &LocalConfig_msg, &config)) {
installDefaultConfig(); // Our in RAM copy might now be corrupt
} else {
if (config.version < DEVICESTATE_MIN_VER) {
@@ -423,7 +423,7 @@ void NodeDB::loadFromDisk()
}
}
- if (!loadProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), LocalModuleConfig_fields, &moduleConfig)) {
+ if (!loadProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(LocalModuleConfig), &LocalModuleConfig_msg, &moduleConfig)) {
installDefaultModuleConfig(); // Our in RAM copy might now be corrupt
} else {
if (moduleConfig.version < DEVICESTATE_MIN_VER) {
@@ -434,7 +434,7 @@ void NodeDB::loadFromDisk()
}
}
- if (!loadProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), ChannelFile_fields, &channelFile)) {
+ if (!loadProto(channelFileName, ChannelFile_size, sizeof(ChannelFile), &ChannelFile_msg, &channelFile)) {
installDefaultChannels(); // Our in RAM copy might now be corrupt
} else {
if (channelFile.version < DEVICESTATE_MIN_VER) {
@@ -445,12 +445,12 @@ void NodeDB::loadFromDisk()
}
}
- if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), OEMStore_fields, &oemStore))
+ if (loadProto(oemConfigFile, OEMStore_size, sizeof(OEMStore), &OEMStore_msg, &oemStore))
DEBUG_MSG("Loaded OEMStore\n");
}
/** Save a protobuf from a file, return true for success */
-bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, const void *dest_struct)
+bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct)
{
bool okay = false;
#ifdef FSCom
@@ -498,7 +498,7 @@ void NodeDB::saveChannelsToDisk()
#ifdef FSCom
FSCom.mkdir("/prefs");
#endif
- saveProto(channelFileName, ChannelFile_size, sizeof(channelFile), ChannelFile_fields, &channelFile);
+ saveProto(channelFileName, ChannelFile_size, &ChannelFile_msg, &channelFile);
}
}
@@ -508,7 +508,7 @@ void NodeDB::saveDeviceStateToDisk()
#ifdef FSCom
FSCom.mkdir("/prefs");
#endif
- saveProto(prefFileName, DeviceState_size, sizeof(devicestate), DeviceState_fields, &devicestate);
+ saveProto(prefFileName, DeviceState_size, &DeviceState_msg, &devicestate);
}
}
@@ -530,7 +530,7 @@ void NodeDB::saveToDisk(int saveWhat)
config.has_power = true;
config.has_network = true;
config.has_bluetooth = true;
- saveProto(configFileName, LocalConfig_size, sizeof(config), LocalConfig_fields, &config);
+ saveProto(configFileName, LocalConfig_size, &LocalConfig_msg, &config);
}
if (saveWhat & SEGMENT_MODULECONFIG) {
@@ -541,7 +541,7 @@ void NodeDB::saveToDisk(int saveWhat)
moduleConfig.has_serial = true;
moduleConfig.has_store_forward = true;
moduleConfig.has_telemetry = true;
- saveProto(moduleConfigFileName, LocalModuleConfig_size, sizeof(moduleConfig), LocalModuleConfig_fields, &moduleConfig);
+ saveProto(moduleConfigFileName, LocalModuleConfig_size, &LocalModuleConfig_msg, &moduleConfig);
}
if (saveWhat & SEGMENT_CHANNELS) {
diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp
index ea08bf76..b50f93bf 100644
--- a/src/mesh/PhoneAPI.cpp
+++ b/src/mesh/PhoneAPI.cpp
@@ -77,7 +77,7 @@ bool PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
// return (lastContactMsec != 0) &&
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
- if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
+ if (pb_decode_from_bytes(buf, bufLength, &ToRadio_msg, &toRadioScratch)) {
switch (toRadioScratch.which_payload_variant) {
case ToRadio_packet_tag:
return handleToRadioPacket(toRadioScratch.packet);
@@ -291,7 +291,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf)
// Do we have a message from the mesh?
if (fromRadioScratch.which_payload_variant != 0) {
// Encapsulate as a FromRadio packet
- size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch);
+ size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, &FromRadio_msg, &fromRadioScratch);
DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payload_variant, numbytes);
return numbytes;
diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp
index 4a40c660..222e5d14 100644
--- a/src/mesh/RadioInterface.cpp
+++ b/src/mesh/RadioInterface.cpp
@@ -175,7 +175,7 @@ uint32_t RadioInterface::getRetransmissionMsec(const MeshPacket *p)
{
assert(slotTimeMsec); // Better be non zero
static uint8_t bytes[MAX_RHPACKETLEN];
- size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
+ size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
uint32_t packetAirtime = getPacketTime(numbytes + sizeof(PacketHeader));
// Make sure enough time has elapsed for this packet to be sent and an ACK is received.
// DEBUG_MSG("Waiting for flooding message with airtime %d and slotTime is %d\n", packetAirtime, slotTimeMsec);
diff --git a/src/mesh/RadioLibRF95.h b/src/mesh/RadioLibRF95.h
index ff8164ef..7fbaff78 100644
--- a/src/mesh/RadioLibRF95.h
+++ b/src/mesh/RadioLibRF95.h
@@ -66,10 +66,5 @@ class RadioLibRF95: public SX1278 {
// since default current limit for SX126x/127x in updated RadioLib is 60mA
// use the previous value
float currentLimit = 100;
-
-#ifndef RADIOLIB_GODMODE
- private:
-#endif
-
};
diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp
index 7933a792..22f3692b 100644
--- a/src/mesh/ReliableRouter.cpp
+++ b/src/mesh/ReliableRouter.cpp
@@ -27,7 +27,7 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
return FloodingRouter::send(p);
}
-bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
+bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
{
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
if (p->from == getNodeNum()) {
@@ -37,9 +37,8 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
// the original sending process.
- // FIXME - we might want to turn off this "optimization", it does save lots of airtime but it assumes that once we've
- // heard one one adjacent node hear our packet that a) probably other adjacent nodes heard it and b) we can trust those
- // nodes to reach our destination. Both of which might be incorrect.
+ // This "optimization", does save lots of airtime. For DMs, you also get a real ACK back
+ // from the intended recipient.
auto key = GlobalPacketId(getFrom(p), p->id);
auto old = findPendingPacket(key);
if (old) {
@@ -54,16 +53,11 @@ bool ReliableRouter::shouldFilterReceived(MeshPacket *p)
}
}
- /* send acks for repeated packets that want acks and are destined for us
- * this way if an ACK is dropped and a packet is resent we'll ACK the resent packet
- * make sure wasSeenRecently _doesn't_ update
- * finding the channel requires decoding the packet. */
- if (p->want_ack && (p->to == getNodeNum()) && wasSeenRecently(p, false) && !MeshModule::currentReply) {
- if (perhapsDecode(p)) {
- sendAckNak(Routing_Error_NONE, getFrom(p), p->id, p->channel);
- DEBUG_MSG("acking a repeated want_ack packet\n");
- }
- } else if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
+ /* Resend implicit ACKs for repeated packets (assuming the original packet was sent with HOP_RELIABLE)
+ * this way if an implicit ACK is dropped and a packet is resent we'll rebroadcast again.
+ * Resending real ACKs is omitted, as you might receive a packet multiple times due to flooding and
+ * flooding this ACK back to the original sender already adds redundancy. */
+ if (wasSeenRecently(p, false) && p->hop_limit == HOP_RELIABLE && !MeshModule::currentReply && p->to != nodeDB.getNodeNum()) {
// retransmission on broadcast has hop_limit still equal to HOP_RELIABLE
DEBUG_MSG("Resending implicit ack for a repeated floodmsg\n");
MeshPacket *tosend = packetPool.allocCopy(*p);
diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h
index ff304cdd..65f486e5 100644
--- a/src/mesh/ReliableRouter.h
+++ b/src/mesh/ReliableRouter.h
@@ -96,7 +96,7 @@ class ReliableRouter : public FloodingRouter
/**
* We hook this method so we can see packets before FloodingRouter says they should be discarded
*/
- virtual bool shouldFilterReceived(MeshPacket *p) override;
+ virtual bool shouldFilterReceived(const MeshPacket *p) override;
/**
* Add p to the list of packets to retransmit occasionally. We will free it once we stop retransmitting.
diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp
index 5ce26f49..66e21d21 100644
--- a/src/mesh/Router.cpp
+++ b/src/mesh/Router.cpp
@@ -306,7 +306,7 @@ bool perhapsDecode(MeshPacket *p)
// Take those raw bytes and convert them back into a well structured protobuf we can understand
memset(&p->decoded, 0, sizeof(p->decoded));
- if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) {
+ if (!pb_decode_from_bytes(bytes, rawSize, &Data_msg, &p->decoded)) {
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n");
} else if (p->decoded.portnum == PortNum_UNKNOWN_APP) {
DEBUG_MSG("Invalid portnum (bad psk?)!\n");
@@ -360,7 +360,7 @@ Routing_Error perhapsEncode(MeshPacket *p)
if (p->which_payload_variant == MeshPacket_decoded_tag) {
static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union
- size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded);
+ size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), &Data_msg, &p->decoded);
// Only allow encryption on the text message app.
// TODO: Allow modules to opt into compression.
diff --git a/src/mesh/Router.h b/src/mesh/Router.h
index 3f079d92..f7748bb2 100644
--- a/src/mesh/Router.h
+++ b/src/mesh/Router.h
@@ -90,7 +90,7 @@ class Router : protected concurrency::OSThread
* Called immedately on receiption, before any further processing.
* @return true to abandon the packet
*/
- virtual bool shouldFilterReceived(MeshPacket *p) { return false; }
+ virtual bool shouldFilterReceived(const MeshPacket *p) { return false; }
/**
* Every (non duplicate) packet this node receives will be passed through this method. This allows subclasses to
diff --git a/src/mesh/SX128xInterface.cpp b/src/mesh/SX128xInterface.cpp
index 0a51d618..d056ab8d 100644
--- a/src/mesh/SX128xInterface.cpp
+++ b/src/mesh/SX128xInterface.cpp
@@ -1,5 +1,6 @@
#include "configuration.h"
#include "SX128xInterface.h"
+#include "mesh/NodeDB.h"
#include "error.h"
// Particular boards might define a different max power based on what their hardware can do
@@ -50,6 +51,20 @@ bool SX128xInterface::init()
// \todo Display actual typename of the adapter, not just `SX128x`
DEBUG_MSG("SX128x init result %d\n", res);
+ if((config.lora.region != Config_LoRaConfig_RegionCode_LORA_24) && (res == RADIOLIB_ERR_INVALID_FREQUENCY)) {
+ DEBUG_MSG("Warning: Radio chip only supports 2.4GHz LoRa. Adjusting Region and rebooting.\n");
+ config.lora.region = Config_LoRaConfig_RegionCode_LORA_24;
+ nodeDB.saveToDisk(SEGMENT_CONFIG);
+ delay(2000);
+#if defined(ARCH_ESP32)
+ ESP.restart();
+#elif defined(ARCH_NRF52)
+ NVIC_SystemReset();
+#else
+ DEBUG_MSG("FIXME implement reboot for this platform. Skipping for now.\n");
+#endif
+ }
+
DEBUG_MSG("Frequency set to %f\n", getFreq());
DEBUG_MSG("Bandwidth set to %f\n", bw);
DEBUG_MSG("Power output set to %d\n", power);
@@ -223,13 +238,9 @@ bool SX128xInterface::isChannelActive()
template
bool SX128xInterface::isActivelyReceiving()
{
-#ifdef RADIOLIB_GODMODE
uint16_t irq = lora.getIrqStatus();
bool hasPreamble = (irq & RADIOLIB_SX128X_IRQ_HEADER_VALID);
return hasPreamble;
-#else
- return isChannelActive();
-#endif
}
template
diff --git a/src/mesh/SX128xInterface.h b/src/mesh/SX128xInterface.h
index 5a6ed95f..2010a65c 100644
--- a/src/mesh/SX128xInterface.h
+++ b/src/mesh/SX128xInterface.h
@@ -27,9 +27,7 @@ class SX128xInterface : public RadioLibInterface
/// Prepare hardware for sleep. Call this _only_ for deep sleep, not needed for light sleep.
virtual bool sleep() override;
-#ifdef RADIOLIB_GODMODE
bool isIRQPending() override { return lora.getIrqStatus() != 0; }
-#endif
protected:
diff --git a/src/mesh/StreamAPI.cpp b/src/mesh/StreamAPI.cpp
index 0b959ddc..57911cf7 100644
--- a/src/mesh/StreamAPI.cpp
+++ b/src/mesh/StreamAPI.cpp
@@ -6,7 +6,7 @@
#define START2 0xc3
#define HEADER_LEN 4
-int32_t StreamAPI::runOnce()
+int32_t StreamAPI::runOncePart()
{
auto result = readStream();
writeStream();
@@ -115,7 +115,7 @@ void StreamAPI::emitRebooted()
fromRadioScratch.rebooted = true;
// DEBUG_MSG("Emitting reboot packet for serial shell\n");
- emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, FromRadio_fields, &fromRadioScratch));
+ emitTxBuffer(pb_encode_to_bytes(txBuf + HEADER_LEN, FromRadio_size, &FromRadio_msg, &fromRadioScratch));
}
/// Hookable to find out when connection changes
diff --git a/src/mesh/StreamAPI.h b/src/mesh/StreamAPI.h
index 0f36ecb0..3196e96f 100644
--- a/src/mesh/StreamAPI.h
+++ b/src/mesh/StreamAPI.h
@@ -28,7 +28,7 @@ valid utf8 encoding. This makes it a bit easier to start a device outputting reg
after it has received a valid packet from the PC, turn off unencoded debug printing and switch to this packet encoding.
*/
-class StreamAPI : public PhoneAPI, protected concurrency::OSThread
+class StreamAPI : public PhoneAPI
{
/**
* The stream we read/write from
@@ -42,13 +42,13 @@ class StreamAPI : public PhoneAPI, protected concurrency::OSThread
uint32_t lastRxMsec = 0;
public:
- StreamAPI(Stream *_stream) : concurrency::OSThread("StreamAPI"), stream(_stream) {}
+ StreamAPI(Stream *_stream) : stream(_stream) {}
/**
* Currently we require frequent invocation from loop() to check for arrived serial packets and to send new packets to the
* phone.
*/
- virtual int32_t runOnce() override;
+ virtual int32_t runOncePart();
private:
/**
diff --git a/src/mesh/eth/ethServerAPI.cpp b/src/mesh/eth/ethServerAPI.cpp
index bb7dd927..3b3b6bbc 100644
--- a/src/mesh/eth/ethServerAPI.cpp
+++ b/src/mesh/eth/ethServerAPI.cpp
@@ -14,7 +14,7 @@ void initApiServer(int port)
}
}
-ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), client(_client)
+ethServerAPI::ethServerAPI(EthernetClient &_client) : StreamAPI(&client), concurrency::OSThread("ethServerAPI"), client(_client)
{
DEBUG_MSG("Incoming ethernet connection\n");
}
@@ -42,7 +42,7 @@ bool ethServerAPI::checkIsConnected()
int32_t ethServerAPI::runOnce()
{
if (client.connected()) {
- return StreamAPI::runOnce();
+ return StreamAPI::runOncePart();
} else {
DEBUG_MSG("Client dropped connection, suspending API service\n");
enabled = false; // we no longer need to run
diff --git a/src/mesh/eth/ethServerAPI.h b/src/mesh/eth/ethServerAPI.h
index c92ab2f1..962841c8 100644
--- a/src/mesh/eth/ethServerAPI.h
+++ b/src/mesh/eth/ethServerAPI.h
@@ -7,7 +7,7 @@
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
*/
-class ethServerAPI : public StreamAPI
+class ethServerAPI : public StreamAPI, private concurrency::OSThread
{
private:
EthernetClient client;
diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h
index 6fa6c8d3..31e7817a 100644
--- a/src/mesh/generated/mesh.pb.h
+++ b/src/mesh/generated/mesh.pb.h
@@ -54,6 +54,8 @@ typedef enum _HardwareModel {
HardwareModel_NANO_G1 = 14,
/* TODO: REPLACE */
HardwareModel_TLORA_V2_1_1P8 = 15,
+ /* TODO: REPLACE */
+ HardwareModel_TLORA_T3_S3 = 16,
/* B&Q Consulting Station Edition G1: https://uniteng.com/wiki/doku.php?id=meshtastic:station */
HardwareModel_STATION_G1 = 25,
/* Less common/prototype boards listed here (needs one more byte over the air) */
diff --git a/src/mesh/generated/storeforward.pb.h b/src/mesh/generated/storeforward.pb.h
index 625fb273..0f076194 100644
--- a/src/mesh/generated/storeforward.pb.h
+++ b/src/mesh/generated/storeforward.pb.h
@@ -10,8 +10,8 @@
#endif
/* Enum definitions */
-/* 1 - 99 = From Router
- 101 - 199 = From Client */
+/* 001 - 063 = From Router
+ 064 - 127 = From Client */
typedef enum _StoreAndForward_RequestResponse {
/* Unset/unused */
StoreAndForward_RequestResponse_UNSET = 0,
@@ -28,17 +28,19 @@ typedef enum _StoreAndForward_RequestResponse {
StoreAndForward_RequestResponse_ROUTER_BUSY = 5,
/* Router is responding to a request for history. */
StoreAndForward_RequestResponse_ROUTER_HISTORY = 6,
+ /* Router is responding to a request for stats. */
+ StoreAndForward_RequestResponse_ROUTER_STATS = 7,
/* Client is an in error state. */
- StoreAndForward_RequestResponse_CLIENT_ERROR = 101,
+ StoreAndForward_RequestResponse_CLIENT_ERROR = 64,
/* Client has requested a replay from the router. */
- StoreAndForward_RequestResponse_CLIENT_HISTORY = 102,
+ StoreAndForward_RequestResponse_CLIENT_HISTORY = 65,
/* Client has requested stats from the router. */
- StoreAndForward_RequestResponse_CLIENT_STATS = 103,
+ StoreAndForward_RequestResponse_CLIENT_STATS = 66,
/* Client has requested the router respond. This can work as a
"are you there" message. */
- StoreAndForward_RequestResponse_CLIENT_PING = 104,
+ StoreAndForward_RequestResponse_CLIENT_PING = 67,
/* The response to a "Ping" */
- StoreAndForward_RequestResponse_CLIENT_PONG = 105,
+ StoreAndForward_RequestResponse_CLIENT_PONG = 68,
/* Client has requested that the router abort processing the client's request */
StoreAndForward_RequestResponse_CLIENT_ABORT = 106
} StoreAndForward_RequestResponse;
@@ -88,15 +90,17 @@ typedef struct _StoreAndForward_Heartbeat {
typedef struct _StoreAndForward {
/* TODO: REPLACE */
StoreAndForward_RequestResponse rr;
- /* TODO: REPLACE */
- bool has_stats;
- StoreAndForward_Statistics stats;
- /* TODO: REPLACE */
- bool has_history;
- StoreAndForward_History history;
- /* TODO: REPLACE */
- bool has_heartbeat;
- StoreAndForward_Heartbeat heartbeat;
+ pb_size_t which_variant;
+ union {
+ /* TODO: REPLACE */
+ StoreAndForward_Statistics stats;
+ /* TODO: REPLACE */
+ StoreAndForward_History history;
+ /* TODO: REPLACE */
+ StoreAndForward_Heartbeat heartbeat;
+ /* Empty Payload */
+ bool empty;
+ } variant;
} StoreAndForward;
@@ -116,11 +120,11 @@ extern "C" {
/* 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_History_init_default {0, 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_History_init_zero {0, 0, 0}
#define StoreAndForward_Heartbeat_init_zero {0, 0}
@@ -144,18 +148,20 @@ extern "C" {
#define StoreAndForward_stats_tag 2
#define StoreAndForward_history_tag 3
#define StoreAndForward_heartbeat_tag 4
+#define StoreAndForward_empty_tag 5
/* Struct field encoding specification for nanopb */
#define StoreAndForward_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UENUM, rr, 1) \
-X(a, STATIC, OPTIONAL, MESSAGE, stats, 2) \
-X(a, STATIC, OPTIONAL, MESSAGE, history, 3) \
-X(a, STATIC, OPTIONAL, MESSAGE, heartbeat, 4)
+X(a, STATIC, ONEOF, MESSAGE, (variant,stats,variant.stats), 2) \
+X(a, STATIC, ONEOF, MESSAGE, (variant,history,variant.history), 3) \
+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_DEFAULT NULL
-#define StoreAndForward_stats_MSGTYPE StoreAndForward_Statistics
-#define StoreAndForward_history_MSGTYPE StoreAndForward_History
-#define StoreAndForward_heartbeat_MSGTYPE StoreAndForward_Heartbeat
+#define StoreAndForward_variant_stats_MSGTYPE StoreAndForward_Statistics
+#define StoreAndForward_variant_history_MSGTYPE StoreAndForward_History
+#define StoreAndForward_variant_heartbeat_MSGTYPE StoreAndForward_Heartbeat
#define StoreAndForward_Statistics_FIELDLIST(X, a) \
X(a, STATIC, SINGULAR, UINT32, messages_total, 1) \
@@ -198,7 +204,7 @@ extern const pb_msgdesc_t StoreAndForward_Heartbeat_msg;
#define StoreAndForward_Heartbeat_size 12
#define StoreAndForward_History_size 18
#define StoreAndForward_Statistics_size 50
-#define StoreAndForward_size 88
+#define StoreAndForward_size 54
#ifdef __cplusplus
} /* extern "C" */
diff --git a/src/mesh/wifi/WiFiServerAPI.cpp b/src/mesh/wifi/WiFiServerAPI.cpp
index 34a15f71..78936176 100644
--- a/src/mesh/wifi/WiFiServerAPI.cpp
+++ b/src/mesh/wifi/WiFiServerAPI.cpp
@@ -14,7 +14,7 @@ void initApiServer(int port)
}
}
-WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), client(_client)
+WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : StreamAPI(&client), concurrency::OSThread("WiFiServerAPI"), client(_client)
{
DEBUG_MSG("Incoming wifi connection\n");
}
@@ -42,7 +42,7 @@ bool WiFiServerAPI::checkIsConnected()
int32_t WiFiServerAPI::runOnce()
{
if (client.connected()) {
- return StreamAPI::runOnce();
+ return StreamAPI::runOncePart();
} else {
DEBUG_MSG("Client dropped connection, suspending API service\n");
enabled = false; // we no longer need to run
diff --git a/src/mesh/wifi/WiFiServerAPI.h b/src/mesh/wifi/WiFiServerAPI.h
index 84a23be0..81240881 100644
--- a/src/mesh/wifi/WiFiServerAPI.h
+++ b/src/mesh/wifi/WiFiServerAPI.h
@@ -7,7 +7,7 @@
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs
* (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs).
*/
-class WiFiServerAPI : public StreamAPI
+class WiFiServerAPI : public StreamAPI, private concurrency::OSThread
{
private:
WiFiClient client;
diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp
index 0b617ade..2ed050f6 100644
--- a/src/modules/AdminModule.cpp
+++ b/src/modules/AdminModule.cpp
@@ -515,7 +515,7 @@ void AdminModule::saveChanges(int saveWhat, bool shouldReboot)
}
}
-AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, AdminMessage_fields)
+AdminModule::AdminModule() : ProtobufModule("Admin", PortNum_ADMIN_APP, &AdminMessage_msg)
{
// restrict to the admin channel for rx
boundChannel = Channels::adminChannel;
diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp
index d148768a..4357ee2c 100644
--- a/src/modules/CannedMessageModule.cpp
+++ b/src/modules/CannedMessageModule.cpp
@@ -45,8 +45,7 @@ CannedMessageModule *cannedMessageModule;
// TODO: move it into NodeDB.h!
extern bool loadProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields, void *dest_struct);
-extern bool saveProto(const char *filename, size_t protoSize, size_t objSize, const pb_msgdesc_t *fields,
- const void *dest_struct);
+extern bool saveProto(const char *filename, size_t protoSize, const pb_msgdesc_t *fields, const void *dest_struct);
CannedMessageModule::CannedMessageModule()
: SinglePortModule("canned", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread("CannedMessageModule")
@@ -480,7 +479,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st
void CannedMessageModule::loadProtoForModule()
{
if (!loadProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessagesConfigFile),
- CannedMessageModuleConfig_fields, &cannedMessageModuleConfig)) {
+ &CannedMessageModuleConfig_msg, &cannedMessageModuleConfig)) {
installDefaultCannedMessageModuleConfig();
}
}
@@ -499,8 +498,8 @@ bool CannedMessageModule::saveProtoForModule()
FS.mkdir("/prefs");
#endif
- okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size, sizeof(cannedMessageModuleConfig),
- CannedMessageModuleConfig_fields, &cannedMessageModuleConfig);
+ okay &= saveProto(cannedMessagesConfigFile, CannedMessageModuleConfig_size,
+ &CannedMessageModuleConfig_msg, &cannedMessageModuleConfig);
return okay;
}
diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp
index 5a95ceec..6c31fdab 100644
--- a/src/modules/ExternalNotificationModule.cpp
+++ b/src/modules/ExternalNotificationModule.cpp
@@ -11,41 +11,9 @@
#define PIN_BUZZER false
#endif
-//#include
-
/*
-
Documentation:
- https://github.com/meshtastic/firmware/blob/master/docs/software/modules/ExternalNotificationModule.md
-
- This module supports:
- https://github.com/meshtastic/firmware/issues/654
-
-
- Quick reference:
-
- moduleConfig.external_notification.enabled
- 0 = Disabled (Default)
- 1 = Enabled
-
- moduleConfig.external_notification.active
- 0 = Active Low (Default)
- 1 = Active High
-
- moduleConfig.external_notification.alert_message
- 0 = Disabled (Default)
- 1 = Alert when a text message comes
-
- moduleConfig.external_notification.alert_bell
- 0 = Disabled (Default)
- 1 = Alert when the bell character is received
-
- moduleConfig.external_notification.output
- GPIO of the output. (Default = 13)
-
- moduleConfig.external_notification.output_ms
- Amount of time in ms for the alert. Default is 1000.
-
+ https://meshtastic.org/docs/settings/moduleconfig/external-notification
*/
// Default configurations
@@ -58,59 +26,113 @@
#define ASCII_BELL 0x07
-bool externalCurrentState = 0;
-uint32_t externalTurnedOn = 0;
+ExternalNotificationModule *externalNotificationModule;
+
+bool externalCurrentState[3] = {};
+
+uint32_t externalTurnedOn[3] = {};
int32_t ExternalNotificationModule::runOnce()
{
- /*
- Uncomment the preferences below if you want to use the module
- without having to configure it from the PythonAPI or WebUI.
- */
-
- // moduleConfig.external_notification.enabled = 1;
- // moduleConfig.external_notification.alert_message = 1;
-
- // moduleConfig.external_notification.active = 1;
- // moduleConfig.external_notification.alert_bell = 1;
- // moduleConfig.external_notification.output_ms = 1000;
- // moduleConfig.external_notification.output = 13;
-
- if (externalCurrentState && !moduleConfig.external_notification.use_pwm) {
+ if (!moduleConfig.external_notification.enabled) {
+ return INT32_MAX; // we don't need this thread here...
+ } else {
+ if ((nagCycleCutoff < millis()) && !rtttl::isPlaying()) {
+ nagCycleCutoff = UINT32_MAX;
+ DEBUG_MSG("Turning off external notification: ");
+ for (int i = 0; i < 2; i++) {
+ if (getExternal(i)) {
+ setExternalOff(i);
+ externalTurnedOn[i] = 0;
+ DEBUG_MSG("%d ", i);
+ }
+ }
+ DEBUG_MSG("\n");
+ return INT32_MAX; // save cycles till we're needed again
+ }
// If the output is turned on, turn it back off after the given period of time.
- if (externalTurnedOn + (moduleConfig.external_notification.output_ms
+ if (nagCycleCutoff != UINT32_MAX) {
+ if (externalTurnedOn[0] + (moduleConfig.external_notification.output_ms
? moduleConfig.external_notification.output_ms
- : EXT_NOTIFICATION_MODULE_OUTPUT_MS) <
- millis()) {
- DEBUG_MSG("Turning off external notification\n");
- setExternalOff();
+ : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
+ getExternal(0) ? setExternalOff(0) : setExternalOn(0);
+ }
+ if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms
+ ? moduleConfig.external_notification.output_ms
+ : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
+ getExternal(1) ? setExternalOff(1) : setExternalOn(1);
+ }
+ if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms
+ ? moduleConfig.external_notification.output_ms
+ : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) {
+ getExternal(2) ? setExternalOff(2) : setExternalOn(2);
+ }
+ }
+
+ // now let the PWM buzzer play
+ if (moduleConfig.external_notification.use_pwm) {
+ if (rtttl::isPlaying()) {
+ rtttl::play();
+ } else if (nagCycleCutoff >= millis()) {
+ // start the song again if we have time left
+ rtttl::begin(config.device.buzzer_gpio, pwmRingtone);
+ }
}
- }
- if (moduleConfig.external_notification.use_pwm)
- return INT32_MAX; // we don't need this thread here...
- else
return 25;
+ }
}
-void ExternalNotificationModule::setExternalOn()
+void ExternalNotificationModule::setExternalOn(uint8_t index)
{
- externalCurrentState = 1;
- externalTurnedOn = millis();
+ externalCurrentState[index] = 1;
+ externalTurnedOn[index] = millis();
- digitalWrite(output,
- (moduleConfig.external_notification.active ? true : false));
+ switch(index) {
+ case 1:
+ if(moduleConfig.external_notification.output_vibra)
+ digitalWrite(moduleConfig.external_notification.output_vibra, true);
+ break;
+ case 2:
+ if(moduleConfig.external_notification.output_buzzer)
+ digitalWrite(moduleConfig.external_notification.output_buzzer, true);
+ break;
+ default:
+ digitalWrite(output, (moduleConfig.external_notification.active ? true : false));
+ break;
+ }
}
-void ExternalNotificationModule::setExternalOff()
+void ExternalNotificationModule::setExternalOff(uint8_t index)
{
- externalCurrentState = 0;
+ externalCurrentState[index] = 0;
+ externalTurnedOn[index] = millis();
- digitalWrite(output,
- (moduleConfig.external_notification.active ? false : true));
+ switch(index) {
+ case 1:
+ if(moduleConfig.external_notification.output_vibra)
+ digitalWrite(moduleConfig.external_notification.output_vibra, false);
+ break;
+ case 2:
+ if(moduleConfig.external_notification.output_buzzer)
+ digitalWrite(moduleConfig.external_notification.output_buzzer, false);
+ break;
+ default:
+ digitalWrite(output, (moduleConfig.external_notification.active ? false : true));
+ break;
+ }
}
-// --------
+bool ExternalNotificationModule::getExternal(uint8_t index)
+{
+ return externalCurrentState[index];
+}
+
+void ExternalNotificationModule::stopNow() {
+ rtttl::stop();
+ nagCycleCutoff = 1; // small value
+ setIntervalFromNow(0);
+}
ExternalNotificationModule::ExternalNotificationModule()
: SinglePortModule("ExternalNotificationModule", PortNum_TEXT_MESSAGE_APP), concurrency::OSThread(
@@ -121,13 +143,18 @@ ExternalNotificationModule::ExternalNotificationModule()
without having to configure it from the PythonAPI or WebUI.
*/
- // moduleConfig.external_notification.enabled = 1;
- // moduleConfig.external_notification.alert_message = 1;
+ // moduleConfig.external_notification.enabled = true;
+ // moduleConfig.external_notification.alert_message = true;
+ // moduleConfig.external_notification.alert_message_buzzer = true;
+ // moduleConfig.external_notification.alert_message_vibra = true;
- // moduleConfig.external_notification.active = 1;
+ // moduleConfig.external_notification.active = true;
// moduleConfig.external_notification.alert_bell = 1;
// moduleConfig.external_notification.output_ms = 1000;
- // moduleConfig.external_notification.output = 13;
+ // moduleConfig.external_notification.output = 4; // RAK4631 IO4
+ // moduleConfig.external_notification.output_buzzer = 10; // RAK4631 IO6
+ // moduleConfig.external_notification.output_vibra = 28; // RAK4631 IO7
+ // moduleConfig.external_notification.nag_timeout = 300;
if (moduleConfig.external_notification.enabled) {
@@ -137,19 +164,30 @@ ExternalNotificationModule::ExternalNotificationModule()
? moduleConfig.external_notification.output
: EXT_NOTIFICATION_MODULE_OUTPUT;
- if (!moduleConfig.external_notification.use_pwm) {
- // Set the direction of a pin
- DEBUG_MSG("Using Pin %i in digital mode\n", output);
- pinMode(output, OUTPUT);
- // Turn off the pin
- setExternalOff();
- } else {
- config.device.buzzer_gpio = config.device.buzzer_gpio
- ? config.device.buzzer_gpio
- : PIN_BUZZER;
-
- // in PWM Mode we force the buzzer pin if it is set
- DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
+ // Set the direction of a pin
+ DEBUG_MSG("Using Pin %i in digital mode\n", output);
+ pinMode(output, OUTPUT);
+ setExternalOff(0);
+ externalTurnedOn[0] = 0;
+ if(moduleConfig.external_notification.output_vibra) {
+ DEBUG_MSG("Using Pin %i for vibra motor\n", moduleConfig.external_notification.output_vibra);
+ pinMode(moduleConfig.external_notification.output_vibra, OUTPUT);
+ setExternalOff(1);
+ externalTurnedOn[1] = 0;
+ }
+ if(moduleConfig.external_notification.output_buzzer) {
+ if (!moduleConfig.external_notification.use_pwm) {
+ DEBUG_MSG("Using Pin %i for buzzer\n", moduleConfig.external_notification.output_buzzer);
+ pinMode(moduleConfig.external_notification.output_buzzer, OUTPUT);
+ setExternalOff(2);
+ externalTurnedOn[2] = 0;
+ } else {
+ config.device.buzzer_gpio = config.device.buzzer_gpio
+ ? config.device.buzzer_gpio
+ : PIN_BUZZER;
+ // in PWM Mode we force the buzzer pin if it is set
+ DEBUG_MSG("Using Pin %i in PWM mode\n", config.device.buzzer_gpio);
+ }
}
} else {
DEBUG_MSG("External Notification Module Disabled\n");
@@ -163,30 +201,91 @@ ProcessMessage ExternalNotificationModule::handleReceived(const MeshPacket &mp)
if (getFrom(&mp) != nodeDB.getNodeNum()) {
- // TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
- // Need to know if and how this could be a problem.
+ // Check if the message contains a bell character. Don't do this loop for every pin, just once.
+ auto &p = mp.decoded;
+ bool containsBell = false;
+ for (int i = 0; i < p.payload.size; i++) {
+ if (p.payload.bytes[i] == ASCII_BELL) {
+ containsBell = true;
+ }
+ }
+
if (moduleConfig.external_notification.alert_bell) {
- auto &p = mp.decoded;
- DEBUG_MSG("externalNotificationModule - Notification Bell\n");
- for (int i = 0; i < p.payload.size; i++) {
- if (p.payload.bytes[i] == ASCII_BELL) {
- if (!moduleConfig.external_notification.use_pwm) {
- setExternalOn();
- } else {
- playBeep();
- }
+ if (containsBell) {
+ DEBUG_MSG("externalNotificationModule - Notification Bell\n");
+ setExternalOn(0);
+ if (moduleConfig.external_notification.nag_timeout) {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
+ } else {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
+ }
+ }
+ }
+
+ if (moduleConfig.external_notification.alert_bell_vibra) {
+ if (containsBell) {
+ DEBUG_MSG("externalNotificationModule - Notification Bell (Vibra)\n");
+ setExternalOn(1);
+ if (moduleConfig.external_notification.nag_timeout) {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
+ } else {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
+ }
+ }
+ }
+
+ if (moduleConfig.external_notification.alert_bell_buzzer) {
+ if (containsBell) {
+ DEBUG_MSG("externalNotificationModule - Notification Bell (Buzzer)\n");
+ if (!moduleConfig.external_notification.use_pwm) {
+ setExternalOn(2);
+ } else {
+ rtttl::begin(config.device.buzzer_gpio, pwmRingtone);
+ }
+ if (moduleConfig.external_notification.nag_timeout) {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
+ } else {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
}
if (moduleConfig.external_notification.alert_message) {
DEBUG_MSG("externalNotificationModule - Notification Module\n");
- if (!moduleConfig.external_notification.use_pwm) {
- setExternalOn();
+ setExternalOn(0);
+ if (moduleConfig.external_notification.nag_timeout) {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
} else {
- playBeep();
+ nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
}
}
+
+ if (!moduleConfig.external_notification.use_pwm) {
+ if (moduleConfig.external_notification.alert_message_vibra) {
+ DEBUG_MSG("externalNotificationModule - Notification Module (Vibra)\n");
+ setExternalOn(1);
+ if (moduleConfig.external_notification.nag_timeout) {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
+ } else {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
+ }
+ }
+
+ if (moduleConfig.external_notification.alert_message_buzzer) {
+ DEBUG_MSG("externalNotificationModule - Notification Module (Buzzer)\n");
+ if (!moduleConfig.external_notification.use_pwm) {
+ setExternalOn(2);
+ } else {
+ rtttl::begin(config.device.buzzer_gpio, pwmRingtone);
+ }
+ if (moduleConfig.external_notification.nag_timeout) {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.nag_timeout * 1000;
+ } else {
+ nagCycleCutoff = millis() + moduleConfig.external_notification.output_ms;
+ }
+ }
+ }
+ setIntervalFromNow(0); // run once so we know if we should do something
}
} else {
diff --git a/src/modules/ExternalNotificationModule.h b/src/modules/ExternalNotificationModule.h
index b5ab64b3..04de235c 100644
--- a/src/modules/ExternalNotificationModule.h
+++ b/src/modules/ExternalNotificationModule.h
@@ -3,6 +3,7 @@
#include "SinglePortModule.h"
#include "concurrency/OSThread.h"
#include "configuration.h"
+#include
#include
#include
@@ -17,18 +18,23 @@ class ExternalNotificationModule : public SinglePortModule, private concurrency:
public:
ExternalNotificationModule();
- void setExternalOn();
- void setExternalOff();
- void getExternal();
+ uint32_t nagCycleCutoff = UINT32_MAX;
+
+ void setExternalOn(uint8_t index = 0);
+ void setExternalOff(uint8_t index = 0);
+ bool getExternal(uint8_t index = 0);
+
+ void stopNow();
+
+ char pwmRingtone[Constants_DATA_PAYLOAD_LEN] = "a:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p,16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#";
protected:
- // virtual MeshPacket *allocReply();
-
/** Called to handle a particular incoming message
-
@return ProcessMessage::STOP if you've guaranteed you've handled this message and no other handlers should be considered for it
*/
virtual ProcessMessage handleReceived(const MeshPacket &mp) override;
virtual int32_t runOnce() override;
};
+
+extern ExternalNotificationModule *externalNotificationModule;
diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp
index ece160ce..96a6c058 100644
--- a/src/modules/Modules.cpp
+++ b/src/modules/Modules.cpp
@@ -24,7 +24,7 @@
#endif
#if defined(ARCH_ESP32) || defined(ARCH_NRF52)
#include "modules/ExternalNotificationModule.h"
-#if !defined(TTGO_T_ECHO)
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
#include "modules/SerialModule.h"
#endif
#endif
@@ -63,13 +63,13 @@ void setupModules()
new DeviceTelemetryModule();
new EnvironmentTelemetryModule();
#endif
-#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO)
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
new SerialModule();
#endif
#ifdef ARCH_ESP32
// Only run on an esp32 based device.
audioModule = new AudioModule();
- new ExternalNotificationModule();
+ externalNotificationModule = new ExternalNotificationModule();
storeForwardModule = new StoreForwardModule();
diff --git a/src/modules/NodeInfoModule.cpp b/src/modules/NodeInfoModule.cpp
index c3d58fd5..1ce1acf3 100644
--- a/src/modules/NodeInfoModule.cpp
+++ b/src/modules/NodeInfoModule.cpp
@@ -51,7 +51,7 @@ MeshPacket *NodeInfoModule::allocReply()
}
NodeInfoModule::NodeInfoModule()
- : ProtobufModule("nodeinfo", PortNum_NODEINFO_APP, User_fields), concurrency::OSThread("NodeInfoModule")
+ : ProtobufModule("nodeinfo", PortNum_NODEINFO_APP, &User_msg), concurrency::OSThread("NodeInfoModule")
{
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
setIntervalFromNow(30 * 1000); // Send our initial owner announcement 30 seconds after we start (to give network time to setup)
diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp
index 5159de27..013f2ee4 100644
--- a/src/modules/PositionModule.cpp
+++ b/src/modules/PositionModule.cpp
@@ -10,7 +10,7 @@
PositionModule *positionModule;
PositionModule::PositionModule()
- : ProtobufModule("position", PortNum_POSITION_APP, Position_fields), concurrency::OSThread("PositionModule")
+ : ProtobufModule("position", PortNum_POSITION_APP, &Position_msg), concurrency::OSThread("PositionModule")
{
isPromiscuous = true; // We always want to update our nodedb, even if we are sniffing on others
setIntervalFromNow(60 * 1000); // Send our initial position 60 seconds after we start (to give GPS time to setup)
diff --git a/src/modules/RemoteHardwareModule.cpp b/src/modules/RemoteHardwareModule.cpp
index 7a859c87..26f1c4db 100644
--- a/src/modules/RemoteHardwareModule.cpp
+++ b/src/modules/RemoteHardwareModule.cpp
@@ -47,7 +47,7 @@ static uint64_t digitalReads(uint64_t mask)
}
RemoteHardwareModule::RemoteHardwareModule()
- : ProtobufModule("remotehardware", PortNum_REMOTE_HARDWARE_APP, HardwareMessage_fields), concurrency::OSThread(
+ : ProtobufModule("remotehardware", PortNum_REMOTE_HARDWARE_APP, &HardwareMessage_msg), concurrency::OSThread(
"remotehardware")
{
}
diff --git a/src/modules/RoutingModule.cpp b/src/modules/RoutingModule.cpp
index 40919eef..8c4eeb4f 100644
--- a/src/modules/RoutingModule.cpp
+++ b/src/modules/RoutingModule.cpp
@@ -41,7 +41,7 @@ void RoutingModule::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom, C
router->sendLocal(p); // we sometimes send directly to the local node
}
-RoutingModule::RoutingModule() : ProtobufModule("routing", PortNum_ROUTING_APP, Routing_fields)
+RoutingModule::RoutingModule() : ProtobufModule("routing", PortNum_ROUTING_APP, &Routing_msg)
{
isPromiscuous = true;
encryptedOk = true;
diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp
index 55ce7b75..eb8f0986 100644
--- a/src/modules/SerialModule.cpp
+++ b/src/modules/SerialModule.cpp
@@ -46,6 +46,8 @@
*/
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+
#define RXD2 16
#define TXD2 17
#define RX_BUFFER 128
@@ -53,13 +55,15 @@
#define BAUD 38400
#define ACK 1
+// API: Defaulting to the formerly removed phone_timeout_secs value of 15 minutes
+#define SERIAL_CONNECTION_TIMEOUT (15 * 60) * 1000UL
+
SerialModule *serialModule;
SerialModuleRadio *serialModuleRadio;
-SerialModule::SerialModule() : concurrency::OSThread("SerialModule") {}
+SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("SerialModule") {}
-char serialBytes[Constants_DATA_PAYLOAD_LEN];
-size_t serialPayloadSize;
+char serialStringChar[Constants_DATA_PAYLOAD_LEN];
SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
{
@@ -80,9 +84,15 @@ SerialModuleRadio::SerialModuleRadio() : MeshModule("SerialModuleRadio")
}
}
+// For the serial2 port we can't really detect if any client is on the other side, so instead just look for recent messages
+bool SerialModule::checkIsConnected()
+{
+ uint32_t now = millis();
+ return (now - lastContactMsec) < SERIAL_CONNECTION_TIMEOUT;
+}
+
int32_t SerialModule::runOnce()
{
-#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
/*
Uncomment the preferences below if you want to use the module
without having to configure it from the PythonAPI or WebUI.
@@ -178,19 +188,32 @@ int32_t SerialModule::runOnce()
firstTime = 0;
+ // in API mode send rebooted sequence
+ if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
+ emitRebooted();
+ }
+
} else {
- // in NMEA mode send out GGA every 2 seconds, Don't read from Port
- if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
+ if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
+ return runOncePart();
+ } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
+ // in NMEA mode send out GGA every 2 seconds, Don't read from Port
if (millis() - lastNmeaTime > 2000) {
lastNmeaTime = millis();
printGGA(outbuf, nodeDB.getNode(myNodeInfo.my_node_num)->position);
Serial2.printf("%s", outbuf);
}
} else {
+ String serialString;
+
while (Serial2.available()) {
- serialPayloadSize = Serial2.readBytes(serialBytes, Constants_DATA_PAYLOAD_LEN);
+ serialString = Serial2.readString();
+ serialString.toCharArray(serialStringChar, Constants_DATA_PAYLOAD_LEN);
+
serialModuleRadio->sendPayload();
+
+ DEBUG_MSG("Received: %s\n", serialStringChar);
}
}
}
@@ -201,9 +224,6 @@ int32_t SerialModule::runOnce()
return INT32_MAX;
}
-#else
- return INT32_MAX;
-#endif
}
MeshPacket *SerialModuleRadio::allocReply()
@@ -215,26 +235,25 @@ MeshPacket *SerialModuleRadio::allocReply()
void SerialModuleRadio::sendPayload(NodeNum dest, bool wantReplies)
{
- Channel *ch = (boundChannel != NULL) ? &channels.getByName(boundChannel) : NULL;
MeshPacket *p = allocReply();
p->to = dest;
- if (ch != NULL) {
- p->channel = ch->index;
- }
p->decoded.want_response = wantReplies;
p->want_ack = ACK;
- p->decoded.payload.size = serialPayloadSize; // You must specify how many bytes are in the reply
- memcpy(p->decoded.payload.bytes, serialBytes, p->decoded.payload.size);
+ p->decoded.payload.size = strlen(serialStringChar); // You must specify how many bytes are in the reply
+ memcpy(p->decoded.payload.bytes, serialStringChar, p->decoded.payload.size);
service.sendToMesh(p);
}
ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
{
-#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
if (moduleConfig.serial.enabled) {
+ if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
+ // in API mode we don't care about stuff from radio.
+ return ProcessMessage::CONTINUE;
+ }
auto &p = mp.decoded;
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
@@ -262,22 +281,20 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_DEFAULT ||
moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_SIMPLE) {
- Serial2.write(p.payload.bytes, p.payload.size);
+ Serial2.printf("%s", p.payload.bytes);
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_TEXTMSG) {
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
String sender = (node && node->has_user) ? node->user.short_name : "???";
Serial2.println();
Serial2.printf("%s: %s", sender, p.payload.bytes);
Serial2.println();
- } else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_PROTO) {
- // TODO this needs to be implemented
} else if (moduleConfig.serial.mode == ModuleConfig_SerialConfig_Serial_Mode_NMEA) {
// Decode the Payload some more
Position scratch;
Position *decoded = NULL;
if (mp.which_payload_variant == MeshPacket_decoded_tag && mp.decoded.portnum == ourPortNum) {
memset(&scratch, 0, sizeof(scratch));
- if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, Position_fields, &scratch)) {
+ if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, &Position_msg, &scratch)) {
decoded = &scratch;
}
// send position packet as WPL to the serial port
@@ -290,8 +307,6 @@ ProcessMessage SerialModuleRadio::handleReceived(const MeshPacket &mp)
} else {
DEBUG_MSG("Serial Module Disabled\n");
}
-
-#endif
-
return ProcessMessage::CONTINUE; // Let others look at this message also if they want
}
+#endif
diff --git a/src/modules/SerialModule.h b/src/modules/SerialModule.h
index 0130bbe2..c853263b 100644
--- a/src/modules/SerialModule.h
+++ b/src/modules/SerialModule.h
@@ -8,7 +8,9 @@
#include "Router.h"
#include
-class SerialModule : private concurrency::OSThread
+#if (defined(ARCH_ESP32) || defined(ARCH_NRF52)) && !defined(TTGO_T_ECHO) && !defined(CONFIG_IDF_TARGET_ESP32S2)
+
+class SerialModule : public StreamAPI, private concurrency::OSThread
{
bool firstTime = 1;
unsigned long lastNmeaTime = millis();
@@ -19,6 +21,9 @@ class SerialModule : private concurrency::OSThread
protected:
virtual int32_t runOnce() override;
+
+ /// Check the current underlying physical link to see if the client is currently connected
+ virtual bool checkIsConnected() override;
};
extern SerialModule *serialModule;
@@ -65,3 +70,5 @@ class SerialModuleRadio : public MeshModule
};
extern SerialModuleRadio *serialModuleRadio;
+
+#endif
diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp
index 7668a1f1..11955f3f 100644
--- a/src/modules/Telemetry/EnvironmentTelemetry.cpp
+++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp
@@ -159,7 +159,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt
const char *lastSender = getSenderShortName(*lastMeasurementPacket);
auto &p = lastMeasurementPacket->decoded;
- if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, Telemetry_fields, &lastMeasurement)) {
+ if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, &Telemetry_msg, &lastMeasurement)) {
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
DEBUG_MSG("Unable to decode last packet");
diff --git a/src/modules/TraceRouteModule.cpp b/src/modules/TraceRouteModule.cpp
index 1c5fd97d..fcb23466 100644
--- a/src/modules/TraceRouteModule.cpp
+++ b/src/modules/TraceRouteModule.cpp
@@ -24,14 +24,14 @@ void TraceRouteModule::updateRoute(MeshPacket* p)
RouteDiscovery scratch;
RouteDiscovery *updated = NULL;
memset(&scratch, 0, sizeof(scratch));
- pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, RouteDiscovery_fields, &scratch);
+ pb_decode_from_bytes(incoming.payload.bytes, incoming.payload.size, &RouteDiscovery_msg, &scratch);
updated = &scratch;
appendMyID(updated);
printRoute(updated, p->from, NODENUM_BROADCAST);
// Set updated route to the payload of the to be flooded packet
- p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), RouteDiscovery_fields, updated);
+ p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &RouteDiscovery_msg, updated);
}
}
@@ -69,7 +69,7 @@ MeshPacket* TraceRouteModule::allocReply()
RouteDiscovery scratch;
RouteDiscovery *updated = NULL;
memset(&scratch, 0, sizeof(scratch));
- pb_decode_from_bytes(p.payload.bytes, p.payload.size, RouteDiscovery_fields, &scratch);
+ pb_decode_from_bytes(p.payload.bytes, p.payload.size, &RouteDiscovery_msg, &scratch);
updated = &scratch;
printRoute(updated, req.from, req.to);
@@ -81,6 +81,6 @@ MeshPacket* TraceRouteModule::allocReply()
}
-TraceRouteModule::TraceRouteModule() : ProtobufModule("traceroute", PortNum_TRACEROUTE_APP, RouteDiscovery_fields) {
+TraceRouteModule::TraceRouteModule() : ProtobufModule("traceroute", PortNum_TRACEROUTE_APP, &RouteDiscovery_msg) {
ourPortNum = PortNum_TRACEROUTE_APP;
}
diff --git a/src/modules/esp32/StoreForwardModule.cpp b/src/modules/esp32/StoreForwardModule.cpp
index 9d1c44c1..54a250d2 100644
--- a/src/modules/esp32/StoreForwardModule.cpp
+++ b/src/modules/esp32/StoreForwardModule.cpp
@@ -22,41 +22,32 @@ int32_t StoreForwardModule::runOnce()
if (this->busy) {
// Only send packets if the channel is less than 25% utilized.
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);
-
if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) {
- strcpy(this->routerMessage, "** S&F - Done");
- storeForwardModule->sendMessage(this->busyTo, this->routerMessage);
-
- // DEBUG_MSG("--- --- --- In busy loop - Done \n");
+ // Tell the client we're done sending
+ StoreAndForward sf = StoreAndForward_init_zero;
+ sf.rr = StoreAndForward_RequestResponse_ROUTER_PING;
+ storeForwardModule->sendMessage(this->busyTo, sf);
+ DEBUG_MSG("*** S&F - Done. (ROUTER_PING)\n");
this->packetHistoryTXQueue_index = 0;
this->busy = false;
} else {
this->packetHistoryTXQueue_index++;
}
-
} 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();
- DEBUG_MSG("Sending heartbeat\n");
-
- StoreAndForward sf;
+ DEBUG_MSG("*** Sending heartbeat\n");
+ StoreAndForward sf = StoreAndForward_init_zero;
sf.rr = StoreAndForward_RequestResponse_ROUTER_HEARTBEAT;
- sf.has_heartbeat = true;
- sf.heartbeat.period = 300;
- sf.heartbeat.secondary = 0; // TODO we always have one primary router for now
-
- MeshPacket *p = allocDataProtobuf(sf);
- p->to = NODENUM_BROADCAST;
- p->decoded.want_response = false;
- p->priority = MeshPacket_Priority_MIN;
- service.sendToMesh(p);
+ sf.which_variant = StoreAndForward_heartbeat_tag;
+ sf.variant.heartbeat.period = 300;
+ sf.variant.heartbeat.secondary = 0; // TODO we always have one primary router for now
+ storeForwardModule->sendMessage(NODENUM_BROADCAST, sf);
}
return (this->packetTimeMax);
}
@@ -74,7 +65,7 @@ void StoreForwardModule::populatePSRAM()
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 =
static_cast(ps_calloc(this->historyReturnMax, sizeof(PacketHistoryStruct)));
@@ -83,46 +74,36 @@ void StoreForwardModule::populatePSRAM()
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)));
+ this->records = numberOfPackets;
this->packetHistory = static_cast(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("numberOfPackets for packetHistory - %u\n", numberOfPackets);
+ 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);
}
-void StoreForwardModule::historyReport()
-{
- DEBUG_MSG("Message history contains %u records\n", this->packetHistoryCurrent);
-}
-
-/*
- *
- */
void StoreForwardModule::historySend(uint32_t msAgo, uint32_t to)
{
-
- // uint32_t packetsSent = 0;
-
uint32_t queueSize = storeForwardModule->historyQueueCreate(msAgo, to);
if (queueSize) {
- snprintf(this->routerMessage, 80, "** S&F - Sending %u message(s)", queueSize);
- storeForwardModule->sendMessage(to, this->routerMessage);
-
+ DEBUG_MSG ("*** S&F - Sending %u message(s)\n", queueSize);
this->busy = true; // runOnce() will pickup the next steps once busy = true.
this->busyTo = to;
-
} else {
- strcpy(this->routerMessage, "** S&F - No history to send");
- storeForwardModule->sendMessage(to, this->routerMessage);
+ DEBUG_MSG ("*** S&F - No history to send\n");
}
+ StoreAndForward sf = StoreAndForward_init_zero;
+ sf.rr = StoreAndForward_RequestResponse_ROUTER_HISTORY;
+ sf.which_variant = StoreAndForward_history_tag;
+ sf.variant.history.history_messages = queueSize;
+ sf.variant.history.window = msAgo;
+ storeForwardModule->sendMessage(to, sf);
}
uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
{
- // uint32_t packetHistoryTXQueueIndex = 0;
-
this->packetHistoryTXQueue_size = 0;
for (int i = 0; i < this->packetHistoryCurrent; i++) {
@@ -133,7 +114,7 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
DEBUG_MSG("SF historyQueueCreate - math %d\n", (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
to the packetHistoryTXQueue structure.
@@ -144,7 +125,6 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
if ((this->packetHistory[i].to & NODENUM_BROADCAST) == NODENUM_BROADCAST ||
((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].to = this->packetHistory[i].to;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].from = this->packetHistory[i].from;
this->packetHistoryTXQueue[this->packetHistoryTXQueue_size].channel = this->packetHistory[i].channel;
@@ -153,9 +133,8 @@ uint32_t StoreForwardModule::historyQueueCreate(uint32_t msAgo, uint32_t to)
Constants_DATA_PAYLOAD_LEN);
this->packetHistoryTXQueue_size++;
- 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->packetHistoryTXQueue[packetHistoryTXQueueIndex].payload);
+ DEBUG_MSG("*** PacketHistoryStruct time=%d\n", this->packetHistory[i].time);
+ DEBUG_MSG("*** PacketHistoryStruct msg=%s\n", this->packetHistory[i].payload);
}
}
}
@@ -174,6 +153,7 @@ void StoreForwardModule::historyAdd(const MeshPacket &mp)
memcpy(this->packetHistory[this->packetHistoryCurrent].payload, p.payload.bytes, Constants_DATA_PAYLOAD_LEN);
this->packetHistoryCurrent++;
+ this->packetHistoryMax++;
}
MeshPacket *StoreForwardModule::allocReply()
@@ -184,7 +164,7 @@ MeshPacket *StoreForwardModule::allocReply()
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();
p->to = dest;
@@ -203,12 +183,14 @@ void StoreForwardModule::sendPayload(NodeNum dest, uint32_t packetHistory_index)
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->priority = MeshPacket_Priority_MIN;
+
// FIXME - Determine if the delayed packet is broadcast or delayed. For now, assume
// everything is broadcast.
p->delayed = MeshPacket_Delayed_DELAYED_BROADCAST;
@@ -216,13 +198,37 @@ 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.
// TODO: Make this configurable.
p->want_ack = 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));
+ p->decoded.want_response = false;
service.sendToMesh(p);
+}
- // HardwareMessage_init_default
+void StoreForwardModule::sendMessage(NodeNum dest, StoreAndForward_RequestResponse rr)
+{
+ // Craft an empty response, save some bytes in flash
+ StoreAndForward sf = StoreAndForward_init_zero;
+ sf.rr = rr;
+ storeForwardModule->sendMessage(dest, sf);
+}
+
+void StoreForwardModule::statsSend(uint32_t to)
+{
+ StoreAndForward sf = StoreAndForward_init_zero;
+
+ sf.rr = StoreAndForward_RequestResponse_ROUTER_STATS;
+ 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)
@@ -230,46 +236,28 @@ ProcessMessage StoreForwardModule::handleReceived(const MeshPacket &mp)
#ifdef ARCH_ESP32
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
if ((getFrom(&mp) != nodeDB.getNodeNum()) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
if (mp.decoded.portnum == PortNum_TEXT_MESSAGE_APP) {
- DEBUG_MSG("Packet came from - PortNum_TEXT_MESSAGE_APP\n");
-
- 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);
- }
+ storeForwardModule->historyAdd(mp);
+ DEBUG_MSG("*** S&F stored. Message history contains %u records now.\n", this->packetHistoryCurrent);
} 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);
-
- } else {
- DEBUG_MSG("Packet came from an unknown port %u\n", mp.decoded.portnum);
- }
+ auto &p = mp.decoded;
+ StoreAndForward scratch;
+ StoreAndForward *decoded = NULL;
+ 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 +273,127 @@ bool StoreForwardModule::handleReceivedProtobuf(const MeshPacket &mp, StoreAndFo
return false;
}
- if (mp.decoded.portnum != PortNum_STORE_FORWARD_APP) {
- 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);
-
+ requests++;
switch (p->rr) {
case StoreAndForward_RequestResponse_CLIENT_ERROR:
+ case StoreAndForward_RequestResponse_CLIENT_ABORT:
if(is_server) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_ERROR\n");
+ // stop sending stuff, the client wants to abort or has another error
+ if ((this->busy) && (this->busyTo == getFrom(&mp))) {
+ DEBUG_MSG("*** Client in ERROR or ABORT requested\n");
+ this->packetHistoryTXQueue_index = 0;
+ this->busy = false;
+ }
}
break;
case StoreAndForward_RequestResponse_CLIENT_HISTORY:
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.
if (this->busy) {
- strcpy(this->routerMessage, "** S&F - Busy. Try again shortly.");
- storeForwardModule->sendMessage(getFrom(&mp), this->routerMessage);
+ storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_ROUTER_BUSY);
+ DEBUG_MSG("*** S&F - Busy. Try again shortly.\n");
} 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 * 60000, getFrom(&mp)); // window is in minutes
+ } else {
+ storeForwardModule->historySend(historyReturnWindow * 60000, getFrom(&mp)); // defaults to 4 hours
+ }
}
}
break;
case StoreAndForward_RequestResponse_CLIENT_PING:
if(is_server) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_PING\n");
+ DEBUG_MSG("*** StoreAndForward_RequestResponse_CLIENT_PING\n");
+ // respond with a ROUTER PONG
+ storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_ROUTER_PONG);
}
break;
case StoreAndForward_RequestResponse_CLIENT_PONG:
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;
case StoreAndForward_RequestResponse_CLIENT_STATS:
if(is_server) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_CLIENT_STATS\n");
- }
- break;
-
- case StoreAndForward_RequestResponse_ROUTER_BUSY:
- if(is_client) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_BUSY\n");
+ DEBUG_MSG("*** Client Request to send STATS\n");
+ if (this->busy) {
+ storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_ROUTER_BUSY);
+ DEBUG_MSG("*** S&F - Busy. Try again shortly.\n");
+ } else {
+ storeForwardModule->statsSend(getFrom(&mp));
+ }
}
break;
case StoreAndForward_RequestResponse_ROUTER_ERROR:
+ case StoreAndForward_RequestResponse_ROUTER_BUSY:
if(is_client) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_ERROR\n");
+ DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_BUSY\n");
+ // retry in messages_saved * packetTimeMax ms
+ retry_delay = millis() + packetHistoryCurrent * packetTimeMax * (StoreAndForward_RequestResponse_ROUTER_ERROR ? 2 : 1);
}
break;
+ case StoreAndForward_RequestResponse_ROUTER_PONG:
+ // A router responded, this is equal to receiving a heartbeat
case StoreAndForward_RequestResponse_ROUTER_HEARTBEAT:
if(is_client) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_HEARTBEAT\n");
+ // register heartbeat and interval
+ if (p->which_variant == StoreAndForward_heartbeat_tag) {
+ heartbeatInterval = p->variant.heartbeat.period;
+ }
+ lastHeartbeat = millis();
+ DEBUG_MSG("*** StoreAndForward Heartbeat received\n");
}
break;
case StoreAndForward_RequestResponse_ROUTER_PING:
if(is_client) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PING\n");
+ DEBUG_MSG("*** StoreAndForward_RequestResponse_ROUTER_PING\n");
+ // respond with a CLIENT PONG
+ storeForwardModule->sendMessage(getFrom(&mp), StoreAndForward_RequestResponse_CLIENT_PONG);
}
break;
- case StoreAndForward_RequestResponse_ROUTER_PONG:
+ case StoreAndForward_RequestResponse_ROUTER_STATS:
if(is_client) {
- // Do nothing
- DEBUG_MSG("StoreAndForward_RequestResponse_ROUTER_PONG\n");
+ DEBUG_MSG("*** Router Response STATS\n");
+ // These fields only have informational purpose on a client. Fill them to consume later.
+ if (p->which_variant == StoreAndForward_stats_tag) {
+ this->packetHistoryMax = p->variant.stats.messages_total;
+ this->packetHistoryCurrent = p->variant.stats.messages_saved;
+ this->records = p->variant.stats.messages_max;
+ this->requests = p->variant.stats.requests;
+ this->requests_history = p->variant.stats.requests_history;
+ this->heartbeat = p->variant.stats.heartbeat;
+ this->historyReturnMax = p->variant.stats.return_max;
+ this->historyReturnWindow = p->variant.stats.return_window;
+ }
+ }
+ break;
+
+ case StoreAndForward_RequestResponse_ROUTER_HISTORY:
+ if(is_client) {
+ // These fields only have informational purpose on a client. Fill them to consume later.
+ if (p->which_variant == StoreAndForward_history_tag) {
+ this->historyReturnWindow = p->variant.history.window / 60000;
+ DEBUG_MSG("*** Router Response HISTORY - Sending %d messages from last %d minutes\n", p->variant.history.history_messages, this->historyReturnWindow);
+ }
}
break;
default:
assert(0); // unexpected state - FIXME, make an error code and reboot
- }
}
-
return true; // There's no need for others to look at this message.
}
@@ -398,7 +418,7 @@ StoreForwardModule::StoreForwardModule()
// Router
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.getFreePsram() >= 1024 * 1024) {
@@ -424,19 +444,19 @@ StoreForwardModule::StoreForwardModule()
this->populatePSRAM();
is_server = true;
} else {
- DEBUG_MSG("Device has less than 1M of PSRAM free.\n");
- DEBUG_MSG("Store & Forward Module - disabling server.\n");
+ DEBUG_MSG("*** Device has less than 1M of PSRAM free.\n");
+ DEBUG_MSG("*** Store & Forward Module - disabling server.\n");
}
} else {
- DEBUG_MSG("Device doesn't have PSRAM.\n");
- DEBUG_MSG("Store & Forward Module - disabling server.\n");
+ DEBUG_MSG("*** Device doesn't have PSRAM.\n");
+ DEBUG_MSG("*** Store & Forward Module - disabling server.\n");
}
// Client
}
if ((config.device.role == Config_DeviceConfig_Role_CLIENT) || (config.device.role == Config_DeviceConfig_Role_ROUTER_CLIENT)) {
is_client = true;
- DEBUG_MSG("Initializing Store & Forward Module in Client mode\n");
+ DEBUG_MSG("*** Initializing Store & Forward Module in Client mode\n");
}
}
#endif
diff --git a/src/modules/esp32/StoreForwardModule.h b/src/modules/esp32/StoreForwardModule.h
index 32d3cddc..c9cb72a5 100644
--- a/src/modules/esp32/StoreForwardModule.h
+++ b/src/modules/esp32/StoreForwardModule.h
@@ -24,10 +24,9 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
uint32_t busyTo = 0;
char routerMessage[Constants_DATA_PAYLOAD_LEN] = {0};
- uint32_t receivedRecord[50][2] = {{0}};
-
PacketHistoryStruct *packetHistory = 0;
uint32_t packetHistoryCurrent = 0;
+ uint32_t packetHistoryMax = 0;
PacketHistoryStruct *packetHistoryTXQueue = 0;
uint32_t packetHistoryTXQueue_size = 0;
@@ -35,20 +34,21 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
uint32_t packetTimeMax = 5000;
- unsigned long lastHeartbeat = 0;
-
bool is_client = false;
bool is_server = false;
public:
StoreForwardModule();
+ unsigned long lastHeartbeat = 0;
+ uint32_t heartbeatInterval = 300;
+
/**
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.
*/
void historyAdd(const MeshPacket &mp);
- void historyReport();
+ void statsSend(uint32_t to);
void historySend(uint32_t msAgo, uint32_t to);
uint32_t historyQueueCreate(uint32_t msAgo, uint32_t to);
@@ -57,12 +57,23 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
* Send our payload into the mesh
*/
void sendPayload(NodeNum dest = NODENUM_BROADCAST, uint32_t packetHistory_index = 0);
- void sendMessage(NodeNum dest, char *str);
+ void sendMessage(NodeNum dest, StoreAndForward &payload);
+ void sendMessage(NodeNum dest, StoreAndForward_RequestResponse rr);
+
virtual MeshPacket *allocReply() override;
/*
- Override the wantPortnum method.
- */
- virtual bool wantPortnum(PortNum p) { return true; };
+ -Override the wantPacket method.
+ */
+ 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:
void populatePSRAM();
@@ -73,6 +84,12 @@ class StoreForwardModule : private concurrency::OSThread, public ProtobufModule<
uint32_t records = 0; // Calculated
bool heartbeat = false; // No heartbeat.
+ // stats
+ uint32_t requests = 0;
+ uint32_t requests_history = 0;
+
+ uint32_t retry_delay = 0;
+
protected:
virtual int32_t runOnce() override;
diff --git a/src/platform/esp32/architecture.h b/src/platform/esp32/architecture.h
index f80008ca..212df9f4 100644
--- a/src/platform/esp32/architecture.h
+++ b/src/platform/esp32/architecture.h
@@ -88,6 +88,8 @@
#define HW_VENDOR HardwareModel_HELTEC_V3
#elif defined(HELTEC_WSL_V3)
#define HW_VENDOR HardwareModel_HELTEC_WSL_V3
+#elif defined(TLORA_T3S3_V1)
+ #define HW_VENDOR HardwareModel_TLORA_T3_S3
#endif
//
diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp
index b3af114e..06427a6d 100644
--- a/src/platform/portduino/SimRadio.cpp
+++ b/src/platform/portduino/SimRadio.cpp
@@ -201,7 +201,7 @@ void SimRadio::startSend(MeshPacket * txp)
} else {
DEBUG_MSG("Payload size is larger than compressed message allows! Sending empty payload.\n");
}
- p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), Compressed_fields, &c);
+ p->decoded.payload.size = pb_encode_to_bytes(p->decoded.payload.bytes, sizeof(p->decoded.payload.bytes), &Compressed_msg, &c);
p->decoded.portnum = PortNum_SIMULATOR_APP;
service.sendToPhone(p); // Sending back to simulator
}
diff --git a/variants/tlora_t3s3_v1/pins_arduino.h b/variants/tlora_t3s3_v1/pins_arduino.h
new file mode 100644
index 00000000..9b8eba7c
--- /dev/null
+++ b/variants/tlora_t3s3_v1/pins_arduino.h
@@ -0,0 +1,34 @@
+#ifndef Pins_Arduino_h
+#define Pins_Arduino_h
+
+#include
+
+#define USB_VID 0x303a
+#define USB_PID 0x1001
+
+#define EXTERNAL_NUM_INTERRUPTS 46
+#define NUM_DIGITAL_PINS 48
+#define NUM_ANALOG_INPUTS 20
+
+#define analogInputToDigitalPin(p) (((p)<20)?(analogChannelToDigitalPin(p)):-1)
+#define digitalPinToInterrupt(p) (((p)<48)?(p):-1)
+#define digitalPinHasPWM(p) (p < 46)
+
+// The default Wire will be mapped to PMU and RTC
+static const uint8_t SDA = 18;
+static const uint8_t SCL = 17;
+
+// Default SPI will be mapped to Radio
+static const uint8_t SS = 7;
+static const uint8_t MOSI = 6;
+static const uint8_t MISO = 3;
+static const uint8_t SCK = 5;
+
+#define SPI_MOSI (11)
+#define SPI_SCK (14)
+#define SPI_MISO (2)
+#define SPI_CS (13)
+
+#define SDCARD_CS SPI_CS
+
+#endif /* Pins_Arduino_h */
diff --git a/variants/tlora_t3s3_v1/platformio.ini b/variants/tlora_t3s3_v1/platformio.ini
new file mode 100644
index 00000000..aa818919
--- /dev/null
+++ b/variants/tlora_t3s3_v1/platformio.ini
@@ -0,0 +1,9 @@
+[env:tlora-t3s3-v1]
+extends = esp32s3_base
+board = tlora-t3s3-v1
+lib_deps =
+ ${esp32_base.lib_deps}
+ caveman99/ESP32 Codec2@^1.0.1
+
+build_flags =
+ ${esp32_base.build_flags} -D TLORA_T3S3_V1 -I variants/tlora_t3s3_v1
\ No newline at end of file
diff --git a/variants/tlora_t3s3_v1/variant.h b/variants/tlora_t3s3_v1/variant.h
new file mode 100644
index 00000000..64874dac
--- /dev/null
+++ b/variants/tlora_t3s3_v1/variant.h
@@ -0,0 +1,54 @@
+#undef GPS_RX_PIN
+#undef GPS_TX_PIN
+
+#define HAS_SDCARD
+#define SDCARD_USE_SPI1
+
+#define USE_SSD1306
+
+#define BATTERY_PIN 1 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage
+// ratio of voltage divider = 2.0 (R42=100k, R43=100k)
+#define ADC_MULTIPLIER 2.11 // 2.0 + 10% for correction of display undervoltage.
+
+#define I2C_SDA 18 // I2C pins for this board
+#define I2C_SCL 17
+
+#define LED_PIN 37 // If defined we will blink this LED
+#define BUTTON_PIN 0 // If defined, this will be used for user button presses,
+
+#define BUTTON_NEED_PULLUP
+
+// TTGO uses a common pinout for their SX1262 vs RF95 modules - both can be enabled and we will probe at runtime for RF95 and if
+// not found then probe for SX1262
+#define USE_RF95 // RFM95/SX127x
+#define USE_SX1262
+#define USE_SX1280
+
+#define RF95_SCK 5
+#define RF95_MISO 3
+#define RF95_MOSI 6
+#define RF95_NSS 7
+
+#define LORA_RESET 8
+#define LORA_DIO0 9
+#define LORA_DIO1 9
+#define LORA_DIO2 33 // SX1262 BUSY
+#define LORA_DIO3 34 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled
+
+#ifdef USE_SX1262
+#define SX126X_CS RF95_NSS // FIXME - we really should define LORA_CS instead
+#define SX126X_DIO1 LORA_DIO1
+#define SX126X_BUSY 36
+#define SX126X_RESET LORA_RESET
+#define SX126X_RXEN 21
+#define SX126X_TXEN 10
+#endif
+
+#ifdef USE_SX1280
+#define SX128X_CS RF95_NSS
+#define SX128X_DIO1 LORA_DIO1
+#define SX128X_BUSY 36
+#define SX128X_RESET LORA_RESET
+#define SX128X_RXEN 21
+#define SX128X_TXEN 10
+#endif
\ No newline at end of file
diff --git a/variants/tlora_v2_1_18/platformio.ini b/variants/tlora_v2_1_18/platformio.ini
index 9c79fa25..c61b8a28 100644
--- a/variants/tlora_v2_1_18/platformio.ini
+++ b/variants/tlora_v2_1_18/platformio.ini
@@ -5,7 +5,5 @@ lib_deps =
${esp32_base.lib_deps}
caveman99/ESP32 Codec2@^1.0.1
-; the RADIOLIB_GODMODE flag can be removed once the next version of RadioLib is released. (>5.5.0)
-
build_flags =
- ${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18 -D RADIOLIB_GODMODE
\ No newline at end of file
+ ${esp32_base.build_flags} -D TLORA_V2_1_18 -I variants/tlora_v2_1_18
\ No newline at end of file