diff --git a/.vscode/settings.json b/.vscode/settings.json
index 45052fa77..f78fe51b8 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -49,7 +49,8 @@
"string_view": "cpp",
"cassert": "cpp",
"iterator": "cpp",
- "shared_mutex": "cpp"
+ "shared_mutex": "cpp",
+ "iostream": "cpp"
},
"cSpell.words": [
"Blox",
diff --git a/bin/regen-protos.sh b/bin/regen-protos.sh
index 0f1ae43c6..dd266c54b 100755
--- a/bin/regen-protos.sh
+++ b/bin/regen-protos.sh
@@ -3,4 +3,4 @@
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.1"
# the nanopb tool seems to require that the .options file be in the current directory!
cd proto
-../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto mesh.proto
+../../nanopb-0.4.1-linux-x86/generator-bin/protoc --nanopb_out=-v:../src/mesh -I=../proto portnums.proto mesh.proto
diff --git a/docs/software/TODO.md b/docs/software/TODO.md
index 4173296e1..178583af0 100644
--- a/docs/software/TODO.md
+++ b/docs/software/TODO.md
@@ -2,21 +2,21 @@
You probably don't care about this section - skip to the next one.
+For app cleanup:
+
+* add app handlers in device code (make new app framework)
+* move positions into regular data packets (use new app framework)
+* move user info into regular data packets (use new app framework)
+* test that positions, text messages and user info still work
+* test that position, text messages and user info work properly with new android app and old device code
+* call the plugin setup functions
+
For high speed/lots of devices/short range tasks:
- When guessing numhops for sending: if I've heard from many local (0 hop neighbors) decrease hopcount by 2 rather than 1.
This should nicely help 'router' nodes do the right thing when long range, or if there are many local nodes for short range.
- fix timeouts/delays to be based on packet length at current radio settings
-Nimble tasks:
-
-- readerror.txt stress test bug
-- started RPA long test, jul 22 6pm
-- implement nimble software update api
-- update to latest bins, test OTA again (measure times) and then checkin bins
-- do alpha release
-
-* update protocol description per cyclomies email thread
* update faq with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2
* update faq on recommended android version and phones
* add help link inside the app, reference a page on the wiki
diff --git a/proto b/proto
index 34cc5cca1..95ef92160 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 34cc5cca1d2f48ffa8f7cb8f1fbf7dfa08da8cb5
+Subproject commit 95ef921604cdab46e32adc245a8d72c7bdbbe319
diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp
index 75aa40ae6..a0b6d35aa 100644
--- a/src/graphics/Screen.cpp
+++ b/src/graphics/Screen.cpp
@@ -32,6 +32,7 @@ along with this program. If not, see .
#include "main.h"
#include "mesh-pb-constants.h"
#include "meshwifi/meshwifi.h"
+#include "plugins/TextMessagePlugin.h"
#include "target_specific.h"
#include "utils.h"
@@ -720,6 +721,7 @@ void Screen::setup()
powerStatusObserver.observe(&powerStatus->onNewStatus);
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
+ textMessageObserver.observe(&textMessagePlugin);
}
void Screen::forceDisplay()
@@ -1183,14 +1185,24 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
switch (arg->getStatusType()) {
case STATUS_TYPE_NODE:
- if (showingNormalScreen && (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal())) {
+ if (showingNormalScreen &&
+ nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
setFrames(); // Regen the list of screens
}
nodeDB.updateGUI = false;
- nodeDB.updateTextMessage = false;
break;
}
return 0;
}
+
+int Screen::handleTextMessage(const MeshPacket *arg)
+{
+ if (showingNormalScreen) {
+ setFrames(); // Regen the list of screens (will show new text message)
+ }
+
+ return 0;
+}
+
} // namespace graphics
diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h
index d0bf62286..90e8ad089 100644
--- a/src/graphics/Screen.h
+++ b/src/graphics/Screen.h
@@ -77,6 +77,8 @@ class Screen : public concurrency::OSThread
CallbackObserver(this, &Screen::handleStatusUpdate);
CallbackObserver nodeStatusObserver =
CallbackObserver(this, &Screen::handleStatusUpdate);
+ CallbackObserver textMessageObserver =
+ CallbackObserver(this, &Screen::handleTextMessage);
public:
Screen(uint8_t address, int sda = -1, int scl = -1);
@@ -192,6 +194,7 @@ class Screen : public concurrency::OSThread
DebugInfo *debug_info() { return &debugInfo; }
int handleStatusUpdate(const meshtastic::Status *arg);
+ int handleTextMessage(const MeshPacket *arg);
/// Used to force (super slow) eink displays to draw critical frames
void forceDisplay();
diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp
new file mode 100644
index 000000000..8e99f8d79
--- /dev/null
+++ b/src/mesh/MeshPlugin.cpp
@@ -0,0 +1,22 @@
+#include "MeshPlugin.h"
+#include
+
+std::vector MeshPlugin::plugins;
+
+MeshPlugin::MeshPlugin(const char *_name) : name(_name) {
+ plugins.push_back(this);
+}
+
+MeshPlugin::~MeshPlugin()
+{
+ assert(0); // FIXME - remove from list of plugins once someone needs this feature
+}
+
+void MeshPlugin::callPlugins(const MeshPacket &mp)
+{
+ for (auto i = plugins.begin(); i != plugins.end(); ++i) {
+ if ((*i)->wantPortnum(mp.decoded.data.portnum))
+ if ((*i)->handleReceived(mp))
+ break;
+ }
+}
\ No newline at end of file
diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h
new file mode 100644
index 000000000..812e80c17
--- /dev/null
+++ b/src/mesh/MeshPlugin.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "mesh/MeshTypes.h"
+#include
+/** A baseclass for any mesh "plugin".
+ *
+ * A plugin allows you to add new features to meshtastic device code, without needing to know messaging details.
+ *
+ * A key concept for this is that your plugin should use a particular "portnum" for each message type you want to receive
+ * and handle.
+ *
+ * Interally we use plugins to implement the core meshtastic text messaging and gps position sharing features. You
+ * can use these classes as examples for how to write your own custom plugin. See here: (FIXME)
+ */
+class MeshPlugin
+{
+ const char *name;
+
+ static std::vector plugins;
+
+ public:
+ /** Constructor
+ * name is for debugging output
+ */
+ MeshPlugin(const char *_name);
+
+ virtual ~MeshPlugin();
+
+ /**
+ * Initialize your plugin. This setup function is called once after all hardware and mesh protocol layers have
+ * been initialized
+ */
+ virtual void setup() {}
+
+ /**
+ * @return true if you want to receive the specified portnum
+ */
+ virtual bool wantPortnum(PortNum p) = 0;
+
+ /** Called to handle a particular incoming message
+
+ @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
+ */
+ virtual bool handleReceived(const MeshPacket &mp) { return false; }
+
+ /** For use only by MeshService
+ */
+ static void callPlugins(const MeshPacket &mp);
+};
\ No newline at end of file
diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp
index 2e245d214..aed5a2859 100644
--- a/src/mesh/NodeDB.cpp
+++ b/src/mesh/NodeDB.cpp
@@ -150,13 +150,13 @@ bool NodeDB::resetRadioConfig()
radioConfig.preferences.region = RegionCode_TW;
// Enter super deep sleep soon and stay there not very long
- //radioConfig.preferences.mesh_sds_timeout_secs = 10;
- //radioConfig.preferences.sds_secs = 60;
+ // radioConfig.preferences.mesh_sds_timeout_secs = 10;
+ // radioConfig.preferences.sds_secs = 60;
}
// Update the global myRegion
initRegion();
-
+
return didFactoryReset;
}
@@ -403,6 +403,8 @@ size_t NodeDB::getNumOnlineNodes()
return numseen;
}
+#include "MeshPlugin.h"
+
/// given a subpacket sniffed from the network, update our DB state
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
void NodeDB::updateFrom(const MeshPacket &mp)
@@ -433,25 +435,8 @@ void NodeDB::updateFrom(const MeshPacket &mp)
}
case SubPacket_data_tag: {
- // Keep a copy of the most recent text message.
- if (p.data.typ == Data_Type_CLEAR_TEXT) {
- DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.data.payload.size,
- p.data.payload.bytes);
- if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) {
- // We only store/display messages destined for us.
- devicestate.rx_text_message = mp;
- devicestate.has_rx_text_message = true;
- updateTextMessage = true;
- powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
- notifyObservers(true); // Force an update whether or not our node counts have changed
-
- // This is going into the wifidev feature branch
- // Only update the WebUI if WiFi is enabled
- //#if WiFi_MODE != 0
- // notifyWebUI();
- //#endif
- }
- }
+ if(mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum())
+ MeshPlugin::callPlugins(mp);
break;
}
diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h
index c98e050d8..72dca69fb 100644
--- a/src/mesh/NodeDB.h
+++ b/src/mesh/NodeDB.h
@@ -33,7 +33,6 @@ class NodeDB
public:
bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled
NodeInfo *updateGUIforNode = NULL; // if currently showing this node, we think you should update the GUI
- bool updateTextMessage = false; // if true, the GUI should show a new text message
Observable newStatus;
/// don't do mesh based algoritm for node id assignment (initially)
diff --git a/src/mesh/mesh.pb.c b/src/mesh/mesh.pb.c
index d799c33d2..032d4ed7f 100644
--- a/src/mesh/mesh.pb.c
+++ b/src/mesh/mesh.pb.c
@@ -61,4 +61,3 @@ PB_BIND(ManufacturingData, ManufacturingData, AUTO)
-
diff --git a/src/mesh/mesh.pb.h b/src/mesh/mesh.pb.h
index 851bf88fb..58323a98a 100644
--- a/src/mesh/mesh.pb.h
+++ b/src/mesh/mesh.pb.h
@@ -4,6 +4,7 @@
#ifndef PB_MESH_PB_H_INCLUDED
#define PB_MESH_PB_H_INCLUDED
#include
+#include "portnums.pb.h"
#if PB_PROTO_HEADER_VERSION != 40
#error Regenerate this file with the current version of nanopb generator.
@@ -51,12 +52,6 @@ typedef enum _LocationSharing {
LocationSharing_LocDisabled = 2
} LocationSharing;
-typedef enum _Data_Type {
- Data_Type_OPAQUE = 0,
- Data_Type_CLEAR_TEXT = 1,
- Data_Type_CLEAR_READACK = 2
-} Data_Type;
-
typedef enum _ChannelSettings_ModemConfig {
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
@@ -79,7 +74,7 @@ typedef struct _ChannelSettings {
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
typedef struct _Data {
- Data_Type typ;
+ PortNum portnum;
Data_payload_t payload;
} Data;
@@ -276,10 +271,6 @@ typedef struct _ToRadio {
#define _LocationSharing_MAX LocationSharing_LocDisabled
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
-#define _Data_Type_MIN Data_Type_OPAQUE
-#define _Data_Type_MAX Data_Type_CLEAR_READACK
-#define _Data_Type_ARRAYSIZE ((Data_Type)(Data_Type_CLEAR_READACK+1))
-
#define _ChannelSettings_ModemConfig_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
@@ -287,7 +278,7 @@ typedef struct _ToRadio {
/* Initializer values for message structs */
#define Position_init_default {0, 0, 0, 0, 0}
-#define Data_init_default {_Data_Type_MIN, {0, {0}}}
+#define Data_init_default {_PortNum_MIN, {0, {0}}}
#define User_init_default {"", "", "", {0}}
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
@@ -303,7 +294,7 @@ typedef struct _ToRadio {
#define ToRadio_init_default {0, {MeshPacket_init_default}}
#define ManufacturingData_init_default {0, {{NULL}, NULL}, {{NULL}, NULL}, 0}
#define Position_init_zero {0, 0, 0, 0, 0}
-#define Data_init_zero {_Data_Type_MIN, {0, {0}}}
+#define Data_init_zero {_PortNum_MIN, {0, {0}}}
#define User_init_zero {"", "", "", {0}}
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}}
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
@@ -328,7 +319,7 @@ typedef struct _ToRadio {
#define ChannelSettings_channel_num_tag 9
#define ChannelSettings_psk_tag 4
#define ChannelSettings_name_tag 5
-#define Data_typ_tag 1
+#define Data_portnum_tag 1
#define Data_payload_tag 2
#define DebugString_message_tag 1
#define ManufacturingData_fradioFreq_tag 1
@@ -443,7 +434,7 @@ X(a, STATIC, SINGULAR, FIXED32, time, 9)
#define Position_DEFAULT NULL
#define Data_FIELDLIST(X, a) \
-X(a, STATIC, SINGULAR, UENUM, typ, 1) \
+X(a, STATIC, SINGULAR, UENUM, portnum, 1) \
X(a, STATIC, SINGULAR, BYTES, payload, 2)
#define Data_CALLBACK NULL
#define Data_DEFAULT NULL
@@ -669,20 +660,20 @@ extern const pb_msgdesc_t ManufacturingData_msg;
/* Maximum encoded size of messages (where known) */
#define Position_size 39
-#define Data_size 245
+#define Data_size 246
#define User_size 72
#define RouteDiscovery_size 88
-#define SubPacket_size 274
-#define MeshPacket_size 313
+#define SubPacket_size 275
+#define MeshPacket_size 314
#define ChannelSettings_size 84
#define RadioConfig_size 308
#define RadioConfig_UserPreferences_size 219
#define NodeInfo_size 132
#define MyNodeInfo_size 110
-#define DeviceState_size 5460
+#define DeviceState_size 5462
#define DebugString_size 258
-#define FromRadio_size 322
-#define ToRadio_size 316
+#define FromRadio_size 323
+#define ToRadio_size 317
/* ManufacturingData_size depends on runtime parameters */
#ifdef __cplusplus
diff --git a/src/mesh/portnums.pb.c b/src/mesh/portnums.pb.c
new file mode 100644
index 000000000..0995ab494
--- /dev/null
+++ b/src/mesh/portnums.pb.c
@@ -0,0 +1,10 @@
+/* Automatically generated nanopb constant definitions */
+/* Generated by nanopb-0.4.1 */
+
+#include "portnums.pb.h"
+#if PB_PROTO_HEADER_VERSION != 40
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+
+
diff --git a/src/mesh/portnums.pb.h b/src/mesh/portnums.pb.h
new file mode 100644
index 000000000..c9a2a5f23
--- /dev/null
+++ b/src/mesh/portnums.pb.h
@@ -0,0 +1,37 @@
+/* Automatically generated nanopb header */
+/* Generated by nanopb-0.4.1 */
+
+#ifndef PB_PORTNUMS_PB_H_INCLUDED
+#define PB_PORTNUMS_PB_H_INCLUDED
+#include
+
+#if PB_PROTO_HEADER_VERSION != 40
+#error Regenerate this file with the current version of nanopb generator.
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Enum definitions */
+typedef enum _PortNum {
+ PortNum_UNKNOWN_APP = 0,
+ PortNum_TEXT_MESSAGE_APP = 1,
+ PortNum_GPIO_APP = 2,
+ PortNum_GPS_POSITION_APP = 3,
+ PortNum_MESH_USERINFO_APP = 4,
+ PortNum_IP_TUNNEL_APP = 5,
+ PortNum_PRIVATE_APP = 256
+} PortNum;
+
+/* Helper constants for enums */
+#define _PortNum_MIN PortNum_UNKNOWN_APP
+#define _PortNum_MAX PortNum_PRIVATE_APP
+#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_PRIVATE_APP+1))
+
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif
diff --git a/src/plugins/TextMessagePlugin.cpp b/src/plugins/TextMessagePlugin.cpp
new file mode 100644
index 000000000..31d98feee
--- /dev/null
+++ b/src/plugins/TextMessagePlugin.cpp
@@ -0,0 +1,28 @@
+#include "configuration.h"
+#include "TextMessagePlugin.h"
+#include "NodeDB.h"
+#include "PowerFSM.h"
+
+TextMessagePlugin textMessagePlugin;
+
+bool TextMessagePlugin::handleReceived(const MeshPacket &mp)
+{
+ auto &p = mp.decoded.data;
+ DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes);
+
+ // We only store/display messages destined for us.
+ // Keep a copy of the most recent text message.
+ devicestate.rx_text_message = mp;
+ devicestate.has_rx_text_message = true;
+
+ powerFSM.trigger(EVENT_RECEIVED_TEXT_MSG);
+ notifyObservers(&mp);
+
+ // This is going into the wifidev feature branch
+ // Only update the WebUI if WiFi is enabled
+ //#if WiFi_MODE != 0
+ // notifyWebUI();
+ //#endif
+
+ return false; // Let others look at this message also if they want
+}
diff --git a/src/plugins/TextMessagePlugin.h b/src/plugins/TextMessagePlugin.h
new file mode 100644
index 000000000..1df13a990
--- /dev/null
+++ b/src/plugins/TextMessagePlugin.h
@@ -0,0 +1,28 @@
+#include "MeshPlugin.h"
+#include "Observer.h"
+
+/**
+ * Text message handling for meshtastic - draws on the OLED display the most recent received message
+ */
+class TextMessagePlugin : public MeshPlugin, public Observable
+{
+ public:
+
+ /** Constructor
+ * name is for debugging output
+ */
+ TextMessagePlugin() : MeshPlugin("text") {}
+
+ /**
+ * @return true if you want to receive the specified portnum
+ */
+ virtual bool wantPortnum(PortNum p) { return p == PortNum_TEXT_MESSAGE_APP; }
+
+ /** Called to handle a particular incoming message
+
+ @return true if you've guaranteed you've handled this message and no other handlers should be considered for it
+ */
+ virtual bool handleReceived(const MeshPacket &mp);
+};
+
+extern TextMessagePlugin textMessagePlugin;
\ No newline at end of file