mirror of
https://github.com/meshtastic/firmware.git
synced 2025-04-27 10:21:40 +00:00
Merge pull request #543 from geeksville/udp
big set of changes from my weeks away
This commit is contained in:
commit
b3b4c2c1c3
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -49,7 +49,8 @@
|
|||||||
"string_view": "cpp",
|
"string_view": "cpp",
|
||||||
"cassert": "cpp",
|
"cassert": "cpp",
|
||||||
"iterator": "cpp",
|
"iterator": "cpp",
|
||||||
"shared_mutex": "cpp"
|
"shared_mutex": "cpp",
|
||||||
|
"iostream": "cpp"
|
||||||
},
|
},
|
||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"Blox",
|
"Blox",
|
||||||
|
6
bin/program-release-universal.sh
Executable file
6
bin/program-release-universal.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
source bin/version.sh
|
||||||
|
|
||||||
|
esptool.py --baud 921600 write_flash 0x10000 release/latest/bins/universal/firmware-tbeam-$VERSION.bin
|
@ -1,6 +1,12 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
echo "This script requires https://jpa.kapsi.fi/nanopb/download/ version 0.4.1"
|
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!
|
# the nanopb tool seems to require that the .options file be in the current directory!
|
||||||
cd proto
|
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 *.proto
|
||||||
|
|
||||||
|
echo "Regenerating protobuf documentation - if you see an error message"
|
||||||
|
echo "you can ignore it unless doing a new protobuf release to github."
|
||||||
|
bin/regen-docs.sh
|
@ -2,27 +2,89 @@
|
|||||||
|
|
||||||
You probably don't care about this section - skip to the next one.
|
You probably don't care about this section - skip to the next one.
|
||||||
|
|
||||||
|
For app cleanup:
|
||||||
|
|
||||||
|
* do fixed position bug https://github.com/meshtastic/Meshtastic-device/issues/536
|
||||||
|
* check build guide
|
||||||
|
* generate autodocs
|
||||||
|
* write user guide
|
||||||
|
* DONE update android code: https://developer.android.com/topic/libraries/view-binding/migration
|
||||||
|
* make gpio watch work, use thread and setup
|
||||||
|
* make hello world example service
|
||||||
|
* make python ping command
|
||||||
|
* make python gpio read a bit cleaner
|
||||||
|
* DONE have python tool check max packet size before sending to device
|
||||||
|
* DONE if request was sent reliably, send reply reliably
|
||||||
|
* DONE require a recent python api to talk to these new device loads
|
||||||
|
* DONE require a recent android app to talk to these new device loads
|
||||||
|
* DONE fix handleIncomingPosition
|
||||||
|
* DONE move want_replies handling into plugins
|
||||||
|
* DONE on android for received positions handle either old or new positions / user messages
|
||||||
|
* on android side send old or new positions as needed / user messages
|
||||||
|
* test python side handle new position/user messages
|
||||||
|
* DONE make a gpio example. --gpiowrb 4 1, --gpiord 0x444, --gpiowatch 0x3ff
|
||||||
|
* DONE fix position sending to use new plugin
|
||||||
|
* DONE Add SinglePortNumPlugin - as the new most useful baseclass
|
||||||
|
* DONE move positions into regular data packets (use new app framework)
|
||||||
|
* DONE 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
|
||||||
|
* fix the RTC drift bug
|
||||||
|
* move ping functionality into device, reply with rxsnr info
|
||||||
|
* use channels for gpio security https://github.com/meshtastic/Meshtastic-device/issues/104
|
||||||
|
* implement GPIO watch
|
||||||
|
|
||||||
For high speed/lots of devices/short range tasks:
|
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.
|
- 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.
|
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
|
- 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 with antennas https://meshtastic.discourse.group/t/range-test-ideas-requested/738/2
|
||||||
* update faq on recommended android version and phones
|
* update faq on recommended android version and phones
|
||||||
* add help link inside the app, reference a page on the wiki
|
* add help link inside the app, reference a page on the wiki
|
||||||
* turn on amazon reviews support
|
* turn on amazon reviews support
|
||||||
* add a tablet layout (with map next to messages) in the android app
|
* add a tablet layout (with map next to messages) in the android app
|
||||||
|
|
||||||
|
# Old docs to merge
|
||||||
|
|
||||||
|
MESH RADIO PROTOCOL
|
||||||
|
|
||||||
|
Old TODO notes on the mesh radio protocol, merge into real docs someday...
|
||||||
|
|
||||||
|
for each named group we have a pre-shared key known by all group members and
|
||||||
|
wrapped around the device. you can only be in one group at a time (FIXME?!) To
|
||||||
|
join the group we read a qr code with the preshared key and ParamsCodeEnum. that
|
||||||
|
gets sent via bluetooth to the device. ParamsCodeEnum maps to a set of various
|
||||||
|
radio params (regulatory region, center freq, SF, bandwidth, bitrate, power
|
||||||
|
etc...) so all members of the mesh can have their radios set the same way.
|
||||||
|
|
||||||
|
once in that group, we can talk between 254 node numbers.
|
||||||
|
to get our node number (and announce our presence in the channel) we pick a
|
||||||
|
random node number and broadcast as that node with WANT-NODENUM(my globally
|
||||||
|
unique name). If anyone on the channel has seen someone _else_ using that name
|
||||||
|
within the last 24 hrs(?) they reply with DENY-NODENUM. Note: we might receive
|
||||||
|
multiple denies. Note: this allows others to speak up for some other node that
|
||||||
|
might be saving battery right now. Any time we hear from another node (for any
|
||||||
|
message type), we add that node number to the unpickable list. To dramatically
|
||||||
|
decrease the odds a node number we request is already used by someone. If no one
|
||||||
|
denies within TBD seconds, we assume that we have that node number. As long as
|
||||||
|
we keep talking to folks at least once every 24 hrs, others should remember we
|
||||||
|
have it.
|
||||||
|
|
||||||
|
Once we have a node number we can broadcast POSITION-UPDATE(my globally unique
|
||||||
|
name, lat, lon, alt, amt battery remaining). All receivers will use this to a)
|
||||||
|
update the mapping of who is at what node nums, b) the time of last rx, c)
|
||||||
|
position. If we haven't heard from that node in a while we reply to that node
|
||||||
|
(only) with our current POSITION_UPDATE state - so that node (presumably just
|
||||||
|
rejoined the network) can build a map of all participants.
|
||||||
|
|
||||||
|
We will periodically broadcast POSITION-UPDATE as needed based on distance moved
|
||||||
|
or a periodic minimum heartbeat.
|
||||||
|
|
||||||
|
If user wants to send a text they can SEND_TEXT(dest user, short text message).
|
||||||
|
Dest user is a node number, or 0xff for broadcast.
|
||||||
|
|
||||||
# Medium priority
|
# Medium priority
|
||||||
|
|
||||||
Items to complete before 1.0.
|
Items to complete before 1.0.
|
||||||
|
2
proto
2
proto
@ -1 +1 @@
|
|||||||
Subproject commit a0b8d888961720d70ab7467c94d8fa0687e58020
|
Subproject commit ebd18145cafb0d09528150b7a5eccd52b581902f
|
@ -1,6 +1,7 @@
|
|||||||
#include "SerialConsole.h"
|
#include "SerialConsole.h"
|
||||||
#include "PowerFSM.h"
|
#include "PowerFSM.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
#define Port Serial
|
#define Port Serial
|
||||||
@ -28,7 +29,8 @@ void SerialConsole::init()
|
|||||||
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
void SerialConsole::handleToRadio(const uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
// Turn off debug serial printing once the API is activated, because other threads could print and corrupt packets
|
||||||
setDestination(&noopPrint);
|
if(!radioConfig.preferences.debug_log_enabled)
|
||||||
|
setDestination(&noopPrint);
|
||||||
canWrite = true;
|
canWrite = true;
|
||||||
|
|
||||||
StreamAPI::handleToRadio(buf, len);
|
StreamAPI::handleToRadio(buf, len);
|
||||||
|
@ -32,6 +32,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
#include "meshwifi/meshwifi.h"
|
#include "meshwifi/meshwifi.h"
|
||||||
|
#include "plugins/TextMessagePlugin.h"
|
||||||
#include "target_specific.h"
|
#include "target_specific.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
@ -720,6 +721,7 @@ void Screen::setup()
|
|||||||
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
powerStatusObserver.observe(&powerStatus->onNewStatus);
|
||||||
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
gpsStatusObserver.observe(&gpsStatus->onNewStatus);
|
||||||
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
nodeStatusObserver.observe(&nodeStatus->onNewStatus);
|
||||||
|
textMessageObserver.observe(&textMessagePlugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Screen::forceDisplay()
|
void Screen::forceDisplay()
|
||||||
@ -1183,14 +1185,24 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg)
|
|||||||
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
|
// DEBUG_MSG("Screen got status update %d\n", arg->getStatusType());
|
||||||
switch (arg->getStatusType()) {
|
switch (arg->getStatusType()) {
|
||||||
case STATUS_TYPE_NODE:
|
case STATUS_TYPE_NODE:
|
||||||
if (showingNormalScreen && (nodeDB.updateTextMessage || nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal())) {
|
if (showingNormalScreen &&
|
||||||
|
nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) {
|
||||||
setFrames(); // Regen the list of screens
|
setFrames(); // Regen the list of screens
|
||||||
}
|
}
|
||||||
nodeDB.updateGUI = false;
|
nodeDB.updateGUI = false;
|
||||||
nodeDB.updateTextMessage = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
} // namespace graphics
|
||||||
|
@ -77,6 +77,8 @@ class Screen : public concurrency::OSThread
|
|||||||
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||||
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver =
|
CallbackObserver<Screen, const meshtastic::Status *> nodeStatusObserver =
|
||||||
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
CallbackObserver<Screen, const meshtastic::Status *>(this, &Screen::handleStatusUpdate);
|
||||||
|
CallbackObserver<Screen, const MeshPacket *> textMessageObserver =
|
||||||
|
CallbackObserver<Screen, const MeshPacket *>(this, &Screen::handleTextMessage);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Screen(uint8_t address, int sda = -1, int scl = -1);
|
Screen(uint8_t address, int sda = -1, int scl = -1);
|
||||||
@ -192,6 +194,7 @@ class Screen : public concurrency::OSThread
|
|||||||
DebugInfo *debug_info() { return &debugInfo; }
|
DebugInfo *debug_info() { return &debugInfo; }
|
||||||
|
|
||||||
int handleStatusUpdate(const meshtastic::Status *arg);
|
int handleStatusUpdate(const meshtastic::Status *arg);
|
||||||
|
int handleTextMessage(const MeshPacket *arg);
|
||||||
|
|
||||||
/// Used to force (super slow) eink displays to draw critical frames
|
/// Used to force (super slow) eink displays to draw critical frames
|
||||||
void forceDisplay();
|
void forceDisplay();
|
||||||
|
69
src/mesh/MeshPlugin.cpp
Normal file
69
src/mesh/MeshPlugin.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
#include "MeshPlugin.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
std::vector<MeshPlugin *> *MeshPlugin::plugins;
|
||||||
|
|
||||||
|
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
|
||||||
|
{
|
||||||
|
// Can't trust static initalizer order, so we check each time
|
||||||
|
if(!plugins)
|
||||||
|
plugins = new std::vector<MeshPlugin *>();
|
||||||
|
|
||||||
|
plugins->push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshPlugin::setup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshPlugin::~MeshPlugin()
|
||||||
|
{
|
||||||
|
assert(0); // FIXME - remove from list of plugins once someone needs this feature
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshPlugin::callPlugins(const MeshPacket &mp)
|
||||||
|
{
|
||||||
|
// DEBUG_MSG("In call plugins\n");
|
||||||
|
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
|
||||||
|
auto &pi = **i;
|
||||||
|
if (pi.wantPortnum(mp.decoded.data.portnum)) {
|
||||||
|
bool handled = pi.handleReceived(mp);
|
||||||
|
|
||||||
|
// Possibly send replies (unless we are handling a locally generated message)
|
||||||
|
if (mp.decoded.want_response && mp.from != nodeDB.getNodeNum())
|
||||||
|
pi.sendResponse(mp);
|
||||||
|
|
||||||
|
DEBUG_MSG("Plugin %s handled=%d\n", pi.name, handled);
|
||||||
|
if (handled)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG_MSG("Plugin %s not interested\n", pi.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
|
||||||
|
* is optional
|
||||||
|
*/
|
||||||
|
void MeshPlugin::sendResponse(const MeshPacket &req) {
|
||||||
|
auto r = allocReply();
|
||||||
|
if(r) {
|
||||||
|
DEBUG_MSG("Sending response\n");
|
||||||
|
setReplyTo(r, req);
|
||||||
|
service.sendToMesh(r);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG_MSG("WARNING: Client requested response but this plugin did not provide\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
||||||
|
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
||||||
|
*/
|
||||||
|
void setReplyTo(MeshPacket *p, const MeshPacket &to) {
|
||||||
|
p->to = to.from;
|
||||||
|
p->want_ack = to.want_ack;
|
||||||
|
}
|
67
src/mesh/MeshPlugin.h
Normal file
67
src/mesh/MeshPlugin.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "mesh/MeshTypes.h"
|
||||||
|
#include <vector>
|
||||||
|
/** 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
|
||||||
|
{
|
||||||
|
static std::vector<MeshPlugin *> *plugins;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
MeshPlugin(const char *_name);
|
||||||
|
|
||||||
|
virtual ~MeshPlugin();
|
||||||
|
|
||||||
|
/** For use only by MeshService
|
||||||
|
*/
|
||||||
|
static void callPlugins(const MeshPacket &mp);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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; }
|
||||||
|
|
||||||
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
|
virtual MeshPacket *allocReply() { return NULL; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. This method calls allocReply()
|
||||||
|
* to generate the reply message, and if !NULL that message will be delivered to whoever sent req
|
||||||
|
*/
|
||||||
|
void sendResponse(const MeshPacket &req);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** set the destination and packet parameters of packet p intended as a reply to a particular "to" packet
|
||||||
|
* This ensures that if the request packet was sent reliably, the reply is sent that way as well.
|
||||||
|
*/
|
||||||
|
void setReplyTo(MeshPacket *p, const MeshPacket &to);
|
@ -13,6 +13,8 @@
|
|||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "mesh-pb-constants.h"
|
#include "mesh-pb-constants.h"
|
||||||
|
#include "plugins/PositionPlugin.h"
|
||||||
|
#include "plugins/NodeInfoPlugin.h"
|
||||||
#include "power.h"
|
#include "power.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -51,7 +53,7 @@ MeshService service;
|
|||||||
|
|
||||||
static int32_t sendOwnerCb()
|
static int32_t sendOwnerCb()
|
||||||
{
|
{
|
||||||
service.sendOurOwner();
|
nodeInfoPlugin.sendOurNodeInfo();
|
||||||
|
|
||||||
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
|
return getPref_send_owner_interval() * getPref_position_broadcast_secs() * 1000;
|
||||||
}
|
}
|
||||||
@ -74,113 +76,25 @@ void MeshService::init()
|
|||||||
packetReceivedObserver.observe(&router->notifyPacketReceived);
|
packetReceivedObserver.observe(&router->notifyPacketReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshService::sendOurOwner(NodeNum dest, bool wantReplies)
|
|
||||||
{
|
|
||||||
MeshPacket *p = router->allocForSending();
|
|
||||||
p->to = dest;
|
|
||||||
p->decoded.want_response = wantReplies;
|
|
||||||
p->decoded.which_payload = SubPacket_user_tag;
|
|
||||||
User &u = p->decoded.user;
|
|
||||||
u = owner;
|
|
||||||
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
|
|
||||||
|
|
||||||
sendToMesh(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all
|
|
||||||
const MeshPacket *MeshService::handleFromRadioUser(const MeshPacket *mp)
|
|
||||||
{
|
|
||||||
bool wasBroadcast = mp->to == NODENUM_BROADCAST;
|
|
||||||
|
|
||||||
// Disable this collision testing if we use 32 bit nodenums
|
|
||||||
bool isCollision = (sizeof(NodeNum) == 1) && (mp->from == myNodeInfo.my_node_num);
|
|
||||||
|
|
||||||
if (isCollision) {
|
|
||||||
// we win if we have a lower macaddr
|
|
||||||
bool weWin = memcmp(&owner.macaddr, &mp->decoded.user.macaddr, sizeof(owner.macaddr)) < 0;
|
|
||||||
|
|
||||||
if (weWin) {
|
|
||||||
DEBUG_MSG("NOTE! Received a nodenum collision and we are vetoing\n");
|
|
||||||
|
|
||||||
mp = NULL;
|
|
||||||
|
|
||||||
sendOurOwner(); // send our owner as a _broadcast_ because that other guy is mistakenly using our nodenum
|
|
||||||
} else {
|
|
||||||
// we lost, we need to try for a new nodenum!
|
|
||||||
DEBUG_MSG("NOTE! Received a nodenum collision we lost, so picking a new nodenum\n");
|
|
||||||
nodeDB.updateFrom(
|
|
||||||
*mp); // update the DB early - before trying to repick (so we don't select the same node number again)
|
|
||||||
nodeDB.pickNewNodeNum();
|
|
||||||
sendOurOwner(); // broadcast our new attempt at a node number
|
|
||||||
}
|
|
||||||
} else if (wasBroadcast) {
|
|
||||||
// If we haven't yet abandoned the packet and it was a broadcast, reply (just to them) with our User record so they can
|
|
||||||
// build their DB
|
|
||||||
|
|
||||||
// Someone just sent us a User, reply with our Owner
|
|
||||||
DEBUG_MSG("Received broadcast Owner from 0x%x, replying with our owner\n", mp->from);
|
|
||||||
|
|
||||||
sendOurOwner(mp->from);
|
|
||||||
|
|
||||||
String lcd = String("Joined: ") + mp->decoded.user.long_name + "\n";
|
|
||||||
screen->print(lcd.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
return mp;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MeshService::handleIncomingPosition(const MeshPacket *mp)
|
|
||||||
{
|
|
||||||
if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.which_payload == SubPacket_position_tag) {
|
|
||||||
DEBUG_MSG("handled incoming position time=%u\n", mp->decoded.position.time);
|
|
||||||
|
|
||||||
if (mp->decoded.position.time) {
|
|
||||||
struct timeval tv;
|
|
||||||
uint32_t secs = mp->decoded.position.time;
|
|
||||||
|
|
||||||
tv.tv_sec = secs;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
perhapsSetRTC(RTCQualityFromNet, &tv);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG("Ignoring incoming packet - not a position\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int MeshService::handleFromRadio(const MeshPacket *mp)
|
int MeshService::handleFromRadio(const MeshPacket *mp)
|
||||||
{
|
{
|
||||||
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
|
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
|
||||||
|
|
||||||
// If it is a position packet, perhaps set our clock - this must be before nodeDB.updateFrom
|
printPacket("Forwarding to phone", mp);
|
||||||
handleIncomingPosition(mp);
|
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
||||||
|
|
||||||
if (mp->which_payload == MeshPacket_decoded_tag && mp->decoded.which_payload == SubPacket_user_tag) {
|
fromNum++;
|
||||||
mp = handleFromRadioUser(mp);
|
|
||||||
|
if (toPhoneQueue.numFree() == 0) {
|
||||||
|
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
|
||||||
|
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
|
||||||
|
if (d)
|
||||||
|
releaseToPool(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we veto a received User packet, we don't put it into the DB or forward it to the phone (to prevent confusing it)
|
MeshPacket *copied = packetPool.allocCopy(*mp);
|
||||||
if (mp) {
|
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
|
||||||
printPacket("Forwarding to phone", mp);
|
|
||||||
nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio
|
|
||||||
|
|
||||||
fromNum++;
|
|
||||||
|
|
||||||
if (toPhoneQueue.numFree() == 0) {
|
|
||||||
DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n");
|
|
||||||
MeshPacket *d = toPhoneQueue.dequeuePtr(0);
|
|
||||||
if (d)
|
|
||||||
releaseToPool(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
MeshPacket *copied = packetPool.allocCopy(*mp);
|
|
||||||
assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages
|
|
||||||
|
|
||||||
if (mp->decoded.want_response)
|
|
||||||
sendNetworkPing(mp->from);
|
|
||||||
} else {
|
|
||||||
DEBUG_MSG("Not delivering vetoed User message\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -201,7 +115,7 @@ bool MeshService::reloadConfig()
|
|||||||
|
|
||||||
// This will also update the region as needed
|
// This will also update the region as needed
|
||||||
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
bool didReset = nodeDB.resetRadioConfig(); // Don't let the phone send us fatally bad settings
|
||||||
|
|
||||||
configChanged.notifyObservers(NULL);
|
configChanged.notifyObservers(NULL);
|
||||||
nodeDB.saveToDisk();
|
nodeDB.saveToDisk();
|
||||||
|
|
||||||
@ -211,7 +125,7 @@ bool MeshService::reloadConfig()
|
|||||||
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
/// The owner User record just got updated, update our node DB and broadcast the info into the mesh
|
||||||
void MeshService::reloadOwner()
|
void MeshService::reloadOwner()
|
||||||
{
|
{
|
||||||
sendOurOwner();
|
nodeInfoPlugin.sendOurNodeInfo();
|
||||||
nodeDB.saveToDisk();
|
nodeDB.saveToDisk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,8 +136,6 @@ void MeshService::reloadOwner()
|
|||||||
*/
|
*/
|
||||||
void MeshService::handleToRadio(MeshPacket &p)
|
void MeshService::handleToRadio(MeshPacket &p)
|
||||||
{
|
{
|
||||||
handleIncomingPosition(&p); // If it is a position packet, perhaps set our clock
|
|
||||||
|
|
||||||
if (p.from == 0) // If the phone didn't set a sending node ID, use ours
|
if (p.from == 0) // If the phone didn't set a sending node ID, use ours
|
||||||
p.from = nodeDB.getNodeNum();
|
p.from = nodeDB.getNodeNum();
|
||||||
|
|
||||||
@ -253,7 +165,8 @@ void MeshService::sendToMesh(MeshPacket *p)
|
|||||||
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
// Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other
|
||||||
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
|
// nodes shouldn't trust it anyways) Note: we allow a device with a local GPS to include the time, so that gpsless
|
||||||
// devices can get time.
|
// devices can get time.
|
||||||
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag) {
|
if (p->which_payload == MeshPacket_decoded_tag && p->decoded.which_payload == SubPacket_position_tag &&
|
||||||
|
p->decoded.position.time) {
|
||||||
if (getRTCQuality() < RTCQualityGPS) {
|
if (getRTCQuality() < RTCQualityGPS) {
|
||||||
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
|
DEBUG_MSG("Stripping time %u from position send\n", p->decoded.position.time);
|
||||||
p->decoded.position.time = 0;
|
p->decoded.position.time = 0;
|
||||||
@ -272,36 +185,16 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
|
|||||||
|
|
||||||
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
|
DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies);
|
||||||
if (node->has_position)
|
if (node->has_position)
|
||||||
sendOurPosition(dest, wantReplies);
|
positionPlugin.sendOurPosition(dest, wantReplies);
|
||||||
else
|
else
|
||||||
sendOurOwner(dest, wantReplies);
|
nodeInfoPlugin.sendOurNodeInfo(dest, wantReplies);
|
||||||
}
|
|
||||||
|
|
||||||
void MeshService::sendOurPosition(NodeNum dest, bool wantReplies)
|
|
||||||
{
|
|
||||||
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
|
||||||
assert(node);
|
|
||||||
assert(node->has_position);
|
|
||||||
|
|
||||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
|
||||||
MeshPacket *p = router->allocForSending();
|
|
||||||
p->to = dest;
|
|
||||||
p->decoded.which_payload = SubPacket_position_tag;
|
|
||||||
p->decoded.position = node->position;
|
|
||||||
p->decoded.want_response = wantReplies;
|
|
||||||
p->decoded.position.time =
|
|
||||||
getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
|
||||||
sendToMesh(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Update our local node info with our position (even if we don't decide to update anyone else)
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
MeshPacket *p = router->allocForSending();
|
|
||||||
p->decoded.which_payload = SubPacket_position_tag;
|
|
||||||
|
|
||||||
Position &pos = p->decoded.position;
|
Position pos = Position_init_default;
|
||||||
|
|
||||||
if (gps->hasLock()) {
|
if (gps->hasLock()) {
|
||||||
if (gps->altitude != 0)
|
if (gps->altitude != 0)
|
||||||
@ -309,6 +202,17 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
|||||||
pos.latitude_i = gps->latitude;
|
pos.latitude_i = gps->latitude;
|
||||||
pos.longitude_i = gps->longitude;
|
pos.longitude_i = gps->longitude;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// The GPS has lost lock, if we are fixed position we should just keep using
|
||||||
|
// the old position
|
||||||
|
if(radioConfig.preferences.fixed_position) {
|
||||||
|
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||||
|
assert(node);
|
||||||
|
assert(node->has_position);
|
||||||
|
pos = node->position;
|
||||||
|
DEBUG_MSG("WARNING: Using fixed position\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pos.time = getValidTime(RTCQualityGPS);
|
pos.time = getValidTime(RTCQualityGPS);
|
||||||
|
|
||||||
@ -316,21 +220,18 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
|
|||||||
pos.battery_level = powerStatus->getBatteryChargePercent();
|
pos.battery_level = powerStatus->getBatteryChargePercent();
|
||||||
updateBatteryLevel(pos.battery_level);
|
updateBatteryLevel(pos.battery_level);
|
||||||
|
|
||||||
// DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
|
DEBUG_MSG("got gps notify time=%u, lat=%d, bat=%d\n", pos.latitude_i, pos.time, pos.battery_level);
|
||||||
|
|
||||||
|
// Update our current position in the local DB
|
||||||
|
nodeDB.updatePosition(nodeDB.getNodeNum(), pos);
|
||||||
|
|
||||||
// We limit our GPS broadcasts to a max rate
|
// We limit our GPS broadcasts to a max rate
|
||||||
static uint32_t lastGpsSend;
|
static uint32_t lastGpsSend;
|
||||||
uint32_t now = millis();
|
uint32_t now = millis();
|
||||||
if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
|
if (lastGpsSend == 0 || now - lastGpsSend > getPref_position_broadcast_secs() * 1000) {
|
||||||
lastGpsSend = now;
|
lastGpsSend = now;
|
||||||
DEBUG_MSG("Sending position to mesh\n");
|
DEBUG_MSG("Sending position to mesh (not requesting replies)\n");
|
||||||
|
positionPlugin.sendOurPosition();
|
||||||
sendToMesh(p);
|
|
||||||
} else {
|
|
||||||
// We don't need to send this packet to anyone else, but it still serves as a nice uniform way to update our local state
|
|
||||||
nodeDB.updateFrom(*p);
|
|
||||||
|
|
||||||
releaseToPool(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -75,18 +75,13 @@ class MeshService
|
|||||||
/// sends our owner
|
/// sends our owner
|
||||||
void sendNetworkPing(NodeNum dest, bool wantReplies = false);
|
void sendNetworkPing(NodeNum dest, bool wantReplies = false);
|
||||||
|
|
||||||
/// Send our owner info to a particular node
|
|
||||||
void sendOurOwner(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/// Broadcasts our last known position
|
|
||||||
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
|
||||||
|
|
||||||
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
|
/// Send a packet into the mesh - note p must have been allocated from packetPool. We will return it to that pool after
|
||||||
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
|
/// sending. This is the ONLY function you should use for sending messages into the mesh, because it also updates the nodedb
|
||||||
/// cache
|
/// cache
|
||||||
void sendToMesh(MeshPacket *p);
|
void sendToMesh(MeshPacket *p);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
/// Called when our gps position has changed - updates nodedb and sends Location message out into the mesh
|
||||||
/// returns 0 to allow futher processing
|
/// returns 0 to allow futher processing
|
||||||
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
int onGPSChanged(const meshtastic::GPSStatus *arg);
|
||||||
@ -94,12 +89,6 @@ class MeshService
|
|||||||
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs
|
/// Handle a packet that just arrived from the radio. This method does _not_ free the provided packet. If it needs
|
||||||
/// to keep the packet around it makes a copy
|
/// to keep the packet around it makes a copy
|
||||||
int handleFromRadio(const MeshPacket *p);
|
int handleFromRadio(const MeshPacket *p);
|
||||||
|
|
||||||
/// handle a user packet that just arrived on the radio, return NULL if we should not process this packet at all
|
|
||||||
const MeshPacket *handleFromRadioUser(const MeshPacket *mp);
|
|
||||||
|
|
||||||
/// look at inbound packets and if they contain a position with time, possibly set our clock
|
|
||||||
void handleIncomingPosition(const MeshPacket *mp);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MeshService service;
|
extern MeshService service;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
typedef uint32_t NodeNum;
|
typedef uint32_t NodeNum;
|
||||||
typedef uint32_t PacketId; // A packet sequence number
|
typedef uint32_t PacketId; // A packet sequence number
|
||||||
|
|
||||||
#define NODENUM_BROADCAST (sizeof(NodeNum) == 4 ? UINT32_MAX : UINT8_MAX)
|
#define NODENUM_BROADCAST UINT32_MAX
|
||||||
#define ERRNO_OK 0
|
#define ERRNO_OK 0
|
||||||
#define ERRNO_NO_INTERFACES 33
|
#define ERRNO_NO_INTERFACES 33
|
||||||
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
#define ERRNO_UNKNOWN 32 // pick something that doesn't conflict with RH_ROUTER_ERROR_UNABLE_TO_DELIVER
|
||||||
|
@ -131,13 +131,13 @@ bool NodeDB::resetRadioConfig()
|
|||||||
radioConfig.preferences.region = RegionCode_TW;
|
radioConfig.preferences.region = RegionCode_TW;
|
||||||
|
|
||||||
// Enter super deep sleep soon and stay there not very long
|
// Enter super deep sleep soon and stay there not very long
|
||||||
//radioConfig.preferences.mesh_sds_timeout_secs = 10;
|
// radioConfig.preferences.mesh_sds_timeout_secs = 10;
|
||||||
//radioConfig.preferences.sds_secs = 60;
|
// radioConfig.preferences.sds_secs = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the global myRegion
|
// Update the global myRegion
|
||||||
initRegion();
|
initRegion();
|
||||||
|
|
||||||
return didFactoryReset;
|
return didFactoryReset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,7 +165,7 @@ void NodeDB::installDefaultDeviceState()
|
|||||||
// default to no GPS, until one has been found by probing
|
// default to no GPS, until one has been found by probing
|
||||||
myNodeInfo.has_gps = false;
|
myNodeInfo.has_gps = false;
|
||||||
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
|
myNodeInfo.message_timeout_msec = FLOOD_EXPIRE_TIME;
|
||||||
myNodeInfo.min_app_version = 172;
|
myNodeInfo.min_app_version = 20120; // format is Mmmss (where M is 1+the numeric major number. i.e. 20120 means 1.1.20
|
||||||
generatePacketId(); // FIXME - ugly way to init current_packet_id;
|
generatePacketId(); // FIXME - ugly way to init current_packet_id;
|
||||||
|
|
||||||
// Init our blank owner info to reasonable defaults
|
// Init our blank owner info to reasonable defaults
|
||||||
@ -248,8 +248,7 @@ void NodeDB::pickNewNodeNum()
|
|||||||
|
|
||||||
// If we don't have a nodenum at app - pick an initial nodenum based on the macaddr
|
// If we don't have a nodenum at app - pick an initial nodenum based on the macaddr
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
r = sizeof(NodeNum) == 1 ? ourMacAddr[5]
|
r = (ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5];
|
||||||
: ((ourMacAddr[2] << 24) | (ourMacAddr[3] << 16) | (ourMacAddr[4] << 8) | ourMacAddr[5]);
|
|
||||||
|
|
||||||
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
|
if (r == NODENUM_BROADCAST || r < NUM_RESERVED)
|
||||||
r = NUM_RESERVED; // don't pick a reserved node number
|
r = NUM_RESERVED; // don't pick a reserved node number
|
||||||
@ -379,6 +378,48 @@ size_t NodeDB::getNumOnlineNodes()
|
|||||||
return numseen;
|
return numseen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "MeshPlugin.h"
|
||||||
|
|
||||||
|
/** Update position info for this node based on received position data
|
||||||
|
*/
|
||||||
|
void NodeDB::updatePosition(uint32_t nodeId, const Position &p)
|
||||||
|
{
|
||||||
|
NodeInfo *info = getOrCreateNode(nodeId);
|
||||||
|
|
||||||
|
DEBUG_MSG("DB update position node=0x%x time=%u, latI=%d, lonI=%d\n", nodeId, p.time, p.latitude_i, p.longitude_i);
|
||||||
|
|
||||||
|
info->position = p;
|
||||||
|
info->has_position = true;
|
||||||
|
updateGUIforNode = info;
|
||||||
|
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Update user info for this node based on received user data
|
||||||
|
*/
|
||||||
|
void NodeDB::updateUser(uint32_t nodeId, const User &p)
|
||||||
|
{
|
||||||
|
NodeInfo *info = getOrCreateNode(nodeId);
|
||||||
|
|
||||||
|
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
||||||
|
|
||||||
|
bool changed = memcmp(&info->user, &p,
|
||||||
|
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
|
||||||
|
|
||||||
|
info->user = p;
|
||||||
|
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
||||||
|
info->has_user = true;
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
updateGUIforNode = info;
|
||||||
|
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
||||||
|
notifyObservers(true); // Force an update whether or not our node counts have changed
|
||||||
|
|
||||||
|
// Not really needed - we will save anyways when we go to sleep
|
||||||
|
// We just changed something important about the user, store our DB
|
||||||
|
// saveToDisk();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// given a subpacket sniffed from the network, update our DB state
|
/// 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
|
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||||
void NodeDB::updateFrom(const MeshPacket &mp)
|
void NodeDB::updateFrom(const MeshPacket &mp)
|
||||||
@ -398,58 +439,21 @@ void NodeDB::updateFrom(const MeshPacket &mp)
|
|||||||
|
|
||||||
switch (p.which_payload) {
|
switch (p.which_payload) {
|
||||||
case SubPacket_position_tag: {
|
case SubPacket_position_tag: {
|
||||||
// we always trust our local timestamps more
|
// handle a legacy position packet
|
||||||
info->position = p.position;
|
DEBUG_MSG("WARNING: Processing a (deprecated) position packet from %d\n", mp.from);
|
||||||
if (mp.rx_time)
|
updatePosition(mp.from, p.position);
|
||||||
info->position.time = mp.rx_time;
|
|
||||||
info->has_position = true;
|
|
||||||
updateGUIforNode = info;
|
|
||||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SubPacket_data_tag: {
|
case SubPacket_data_tag: {
|
||||||
// Keep a copy of the most recent text message.
|
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum())
|
||||||
if (p.data.typ == Data_Type_CLEAR_TEXT) {
|
MeshPlugin::callPlugins(mp);
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SubPacket_user_tag: {
|
case SubPacket_user_tag: {
|
||||||
DEBUG_MSG("old user %s/%s/%s\n", info->user.id, info->user.long_name, info->user.short_name);
|
DEBUG_MSG("WARNING: Processing a (deprecated) user packet from %d\n", mp.from);
|
||||||
|
updateUser(mp.from, p.user);
|
||||||
bool changed = memcmp(&info->user, &p.user,
|
|
||||||
sizeof(info->user)); // Both of these blocks start as filled with zero so I think this is okay
|
|
||||||
|
|
||||||
info->user = p.user;
|
|
||||||
DEBUG_MSG("updating changed=%d user %s/%s/%s\n", changed, info->user.id, info->user.long_name, info->user.short_name);
|
|
||||||
info->has_user = true;
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
updateGUIforNode = info;
|
|
||||||
powerFSM.trigger(EVENT_NODEDB_UPDATED);
|
|
||||||
notifyObservers(true); // Force an update whether or not our node counts have changed
|
|
||||||
|
|
||||||
// Not really needed - we will save anyways when we go to sleep
|
|
||||||
// We just changed something important about the user, store our DB
|
|
||||||
// saveToDisk();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ class NodeDB
|
|||||||
public:
|
public:
|
||||||
bool updateGUI = false; // we think the gui should definitely be redrawn, screen will clear this once handled
|
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
|
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<const meshtastic::NodeStatus *> newStatus;
|
Observable<const meshtastic::NodeStatus *> newStatus;
|
||||||
|
|
||||||
/// don't do mesh based algoritm for node id assignment (initially)
|
/// don't do mesh based algoritm for node id assignment (initially)
|
||||||
@ -58,6 +57,14 @@ class NodeDB
|
|||||||
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
/// we updateGUI and updateGUIforNode if we think our this change is big enough for a redraw
|
||||||
void updateFrom(const MeshPacket &p);
|
void updateFrom(const MeshPacket &p);
|
||||||
|
|
||||||
|
/** Update position info for this node based on received position data
|
||||||
|
*/
|
||||||
|
void updatePosition(uint32_t nodeId, const Position &p);
|
||||||
|
|
||||||
|
/** Update user info for this node based on received user data
|
||||||
|
*/
|
||||||
|
void updateUser(uint32_t nodeId, const User &p);
|
||||||
|
|
||||||
/// @return our node number
|
/// @return our node number
|
||||||
NodeNum getNodeNum() { return myNodeInfo.my_node_num; }
|
NodeNum getNodeNum() { return myNodeInfo.my_node_num; }
|
||||||
|
|
||||||
|
3
src/mesh/ProtobufPlugin.cpp
Normal file
3
src/mesh/ProtobufPlugin.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#include "ProtobufPlugin.h"
|
||||||
|
|
||||||
|
|
66
src/mesh/ProtobufPlugin.h
Normal file
66
src/mesh/ProtobufPlugin.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "SinglePortPlugin.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A base class for mesh plugins that assume that they are sending/receiving one particular protobuf based
|
||||||
|
* payload. Using one particular app ID.
|
||||||
|
*
|
||||||
|
* If you are using protobufs to encode your packets (recommended) you can use this as a baseclass for your plugin
|
||||||
|
* and avoid a bunch of boilerplate code.
|
||||||
|
*/
|
||||||
|
template <class T> class ProtobufPlugin : private SinglePortPlugin
|
||||||
|
{
|
||||||
|
const pb_msgdesc_t *fields;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
ProtobufPlugin(const char *_name, PortNum _ourPortNum, const pb_msgdesc_t *_fields)
|
||||||
|
: SinglePortPlugin(_name, _ourPortNum), fields(_fields)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle a received message, the data field in the message is already decoded and is provided
|
||||||
|
*/
|
||||||
|
virtual bool handleReceivedProtobuf(const MeshPacket &mp, const T &decoded) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mesh packet which has been preinited with a particular protobuf data payload and port number.
|
||||||
|
* You can then send this packet (after customizing any of the payload fields you might need) with
|
||||||
|
* service.sendToMesh()
|
||||||
|
*/
|
||||||
|
MeshPacket *allocDataProtobuf(const T &payload)
|
||||||
|
{
|
||||||
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
|
MeshPacket *p = allocDataPacket();
|
||||||
|
|
||||||
|
p->decoded.data.payload.size =
|
||||||
|
pb_encode_to_bytes(p->decoded.data.payload.bytes, sizeof(p->decoded.data.payload.bytes), fields, &payload);
|
||||||
|
// DEBUG_MSG("did encode\n");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** 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)
|
||||||
|
{
|
||||||
|
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
|
||||||
|
// it would be better to update even if the message was destined to others.
|
||||||
|
|
||||||
|
auto &p = mp.decoded.data;
|
||||||
|
DEBUG_MSG("Received %s from=0x%0x, id=%d, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
|
||||||
|
|
||||||
|
T scratch;
|
||||||
|
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
|
||||||
|
handleReceivedProtobuf(mp, scratch);
|
||||||
|
|
||||||
|
return false; // Let others look at this message also if they want
|
||||||
|
}
|
||||||
|
};
|
@ -58,7 +58,7 @@ class RadioInterface
|
|||||||
uint8_t sf = 9;
|
uint8_t sf = 9;
|
||||||
uint8_t cr = 7;
|
uint8_t cr = 7;
|
||||||
|
|
||||||
uint16_t preambleLength = 32; // 8 is default, but FIXME use longer to increase the amount of sleep time when receiving
|
uint16_t preambleLength = 32; // 8 is default, but we use longer to increase the amount of sleep time when receiving
|
||||||
|
|
||||||
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
MeshPacket *sendingPacket = NULL; // The packet we are currently sending
|
||||||
uint32_t lastTxStart = 0L;
|
uint32_t lastTxStart = 0L;
|
||||||
|
40
src/mesh/SinglePortPlugin.h
Normal file
40
src/mesh/SinglePortPlugin.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "MeshPlugin.h"
|
||||||
|
#include "Router.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Most plugins are only interested in sending/receving one particular portnum. This baseclass simplifies that common
|
||||||
|
* case.
|
||||||
|
*/
|
||||||
|
class SinglePortPlugin : public MeshPlugin
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
PortNum ourPortNum;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
SinglePortPlugin(const char *_name, PortNum _ourPortNum) : MeshPlugin(_name), ourPortNum(_ourPortNum) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* @return true if you want to receive the specified portnum
|
||||||
|
*/
|
||||||
|
virtual bool wantPortnum(PortNum p) { return p == ourPortNum; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a mesh packet which has been preinited as a data packet with a particular port number.
|
||||||
|
* You can then send this packet (after customizing any of the payload fields you might need) with
|
||||||
|
* service.sendToMesh()
|
||||||
|
*/
|
||||||
|
MeshPacket *allocDataPacket()
|
||||||
|
{
|
||||||
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
|
MeshPacket *p = router->allocForSending();
|
||||||
|
p->decoded.which_payload = SubPacket_data_tag;
|
||||||
|
p->decoded.data.portnum = ourPortNum;
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
};
|
@ -51,10 +51,6 @@ PB_BIND(FromRadio, FromRadio, 2)
|
|||||||
PB_BIND(ToRadio, ToRadio, 2)
|
PB_BIND(ToRadio, ToRadio, 2)
|
||||||
|
|
||||||
|
|
||||||
PB_BIND(ManufacturingData, ManufacturingData, AUTO)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifndef PB_MESH_PB_H_INCLUDED
|
#ifndef PB_MESH_PB_H_INCLUDED
|
||||||
#define PB_MESH_PB_H_INCLUDED
|
#define PB_MESH_PB_H_INCLUDED
|
||||||
#include <pb.h>
|
#include <pb.h>
|
||||||
|
#include "portnums.pb.h"
|
||||||
|
|
||||||
#if PB_PROTO_HEADER_VERSION != 40
|
#if PB_PROTO_HEADER_VERSION != 40
|
||||||
#error Regenerate this file with the current version of nanopb generator.
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
@ -22,7 +23,8 @@ typedef enum _RouteError {
|
|||||||
} RouteError;
|
} RouteError;
|
||||||
|
|
||||||
typedef enum _Constants {
|
typedef enum _Constants {
|
||||||
Constants_Unused = 0
|
Constants_Unused = 0,
|
||||||
|
Constants_DATA_PAYLOAD_LEN = 240
|
||||||
} Constants;
|
} Constants;
|
||||||
|
|
||||||
typedef enum _RegionCode {
|
typedef enum _RegionCode {
|
||||||
@ -50,12 +52,6 @@ typedef enum _LocationSharing {
|
|||||||
LocationSharing_LocDisabled = 2
|
LocationSharing_LocDisabled = 2
|
||||||
} LocationSharing;
|
} 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 {
|
typedef enum _ChannelSettings_ModemConfig {
|
||||||
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
|
ChannelSettings_ModemConfig_Bw125Cr45Sf128 = 0,
|
||||||
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
|
ChannelSettings_ModemConfig_Bw500Cr45Sf128 = 1,
|
||||||
@ -78,7 +74,7 @@ typedef struct _ChannelSettings {
|
|||||||
|
|
||||||
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
|
typedef PB_BYTES_ARRAY_T(240) Data_payload_t;
|
||||||
typedef struct _Data {
|
typedef struct _Data {
|
||||||
Data_Type typ;
|
PortNum portnum;
|
||||||
Data_payload_t payload;
|
Data_payload_t payload;
|
||||||
} Data;
|
} Data;
|
||||||
|
|
||||||
@ -86,13 +82,6 @@ typedef struct _DebugString {
|
|||||||
char message[256];
|
char message[256];
|
||||||
} DebugString;
|
} DebugString;
|
||||||
|
|
||||||
typedef struct _ManufacturingData {
|
|
||||||
uint32_t fradioFreq;
|
|
||||||
pb_callback_t hw_model;
|
|
||||||
pb_callback_t hw_version;
|
|
||||||
int32_t selftest_result;
|
|
||||||
} ManufacturingData;
|
|
||||||
|
|
||||||
typedef struct _MyNodeInfo {
|
typedef struct _MyNodeInfo {
|
||||||
uint32_t my_node_num;
|
uint32_t my_node_num;
|
||||||
bool has_gps;
|
bool has_gps;
|
||||||
@ -140,7 +129,9 @@ typedef struct _RadioConfig_UserPreferences {
|
|||||||
uint32_t gps_attempt_time;
|
uint32_t gps_attempt_time;
|
||||||
bool is_router;
|
bool is_router;
|
||||||
bool is_low_power;
|
bool is_low_power;
|
||||||
|
bool fixed_position;
|
||||||
bool factory_reset;
|
bool factory_reset;
|
||||||
|
bool debug_log_enabled;
|
||||||
pb_size_t ignore_incoming_count;
|
pb_size_t ignore_incoming_count;
|
||||||
uint32_t ignore_incoming[3];
|
uint32_t ignore_incoming[3];
|
||||||
} RadioConfig_UserPreferences;
|
} RadioConfig_UserPreferences;
|
||||||
@ -260,8 +251,8 @@ typedef struct _ToRadio {
|
|||||||
#define _RouteError_ARRAYSIZE ((RouteError)(RouteError_TIMEOUT+1))
|
#define _RouteError_ARRAYSIZE ((RouteError)(RouteError_TIMEOUT+1))
|
||||||
|
|
||||||
#define _Constants_MIN Constants_Unused
|
#define _Constants_MIN Constants_Unused
|
||||||
#define _Constants_MAX Constants_Unused
|
#define _Constants_MAX Constants_DATA_PAYLOAD_LEN
|
||||||
#define _Constants_ARRAYSIZE ((Constants)(Constants_Unused+1))
|
#define _Constants_ARRAYSIZE ((Constants)(Constants_DATA_PAYLOAD_LEN+1))
|
||||||
|
|
||||||
#define _RegionCode_MIN RegionCode_Unset
|
#define _RegionCode_MIN RegionCode_Unset
|
||||||
#define _RegionCode_MAX RegionCode_TW
|
#define _RegionCode_MAX RegionCode_TW
|
||||||
@ -275,10 +266,6 @@ typedef struct _ToRadio {
|
|||||||
#define _LocationSharing_MAX LocationSharing_LocDisabled
|
#define _LocationSharing_MAX LocationSharing_LocDisabled
|
||||||
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
|
#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_MIN ChannelSettings_ModemConfig_Bw125Cr45Sf128
|
||||||
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
|
#define _ChannelSettings_ModemConfig_MAX ChannelSettings_ModemConfig_Bw125Cr48Sf4096
|
||||||
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
|
#define _ChannelSettings_ModemConfig_ARRAYSIZE ((ChannelSettings_ModemConfig)(ChannelSettings_ModemConfig_Bw125Cr48Sf4096+1))
|
||||||
@ -286,37 +273,35 @@ typedef struct _ToRadio {
|
|||||||
|
|
||||||
/* Initializer values for message structs */
|
/* Initializer values for message structs */
|
||||||
#define Position_init_default {0, 0, 0, 0, 0}
|
#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 User_init_default {"", "", "", {0}}
|
||||||
#define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 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}
|
#define SubPacket_init_default {0, {Position_init_default}, 0, 0, 0, 0, {0}, 0}
|
||||||
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0}
|
#define MeshPacket_init_default {0, 0, 0, {SubPacket_init_default}, 0, 0, 0, 0, 0}
|
||||||
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
|
#define ChannelSettings_init_default {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
|
||||||
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default, false, ChannelSettings_init_default}
|
||||||
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||||
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
#define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0}
|
||||||
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_default {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
|
#define DeviceState_init_default {false, RadioConfig_init_default, false, MyNodeInfo_init_default, false, User_init_default, 0, {NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default, NodeInfo_init_default}, 0, {MeshPacket_init_default}, false, MeshPacket_init_default, 0, 0, 0}
|
||||||
#define DebugString_init_default {""}
|
#define DebugString_init_default {""}
|
||||||
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
|
#define FromRadio_init_default {0, 0, {MeshPacket_init_default}}
|
||||||
#define ToRadio_init_default {0, {MeshPacket_init_default}}
|
#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 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 User_init_zero {"", "", "", {0}}
|
||||||
#define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 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}
|
#define SubPacket_init_zero {0, {Position_init_zero}, 0, 0, 0, 0, {0}, 0}
|
||||||
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0}
|
#define MeshPacket_init_zero {0, 0, 0, {SubPacket_init_zero}, 0, 0, 0, 0, 0}
|
||||||
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
|
#define ChannelSettings_init_zero {0, _ChannelSettings_ModemConfig_MIN, {0, {0}}, "", 0, 0, 0, 0}
|
||||||
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero, false, ChannelSettings_init_zero}
|
||||||
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||||
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
#define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0}
|
||||||
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
|
#define DeviceState_init_zero {false, RadioConfig_init_zero, false, MyNodeInfo_init_zero, false, User_init_zero, 0, {NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero, NodeInfo_init_zero}, 0, {MeshPacket_init_zero}, false, MeshPacket_init_zero, 0, 0, 0}
|
||||||
#define DebugString_init_zero {""}
|
#define DebugString_init_zero {""}
|
||||||
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
|
#define FromRadio_init_zero {0, 0, {MeshPacket_init_zero}}
|
||||||
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
#define ToRadio_init_zero {0, {MeshPacket_init_zero}}
|
||||||
#define ManufacturingData_init_zero {0, {{NULL}, NULL}, {{NULL}, NULL}, 0}
|
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define ChannelSettings_tx_power_tag 1
|
#define ChannelSettings_tx_power_tag 1
|
||||||
@ -327,13 +312,9 @@ typedef struct _ToRadio {
|
|||||||
#define ChannelSettings_channel_num_tag 9
|
#define ChannelSettings_channel_num_tag 9
|
||||||
#define ChannelSettings_psk_tag 4
|
#define ChannelSettings_psk_tag 4
|
||||||
#define ChannelSettings_name_tag 5
|
#define ChannelSettings_name_tag 5
|
||||||
#define Data_typ_tag 1
|
#define Data_portnum_tag 1
|
||||||
#define Data_payload_tag 2
|
#define Data_payload_tag 2
|
||||||
#define DebugString_message_tag 1
|
#define DebugString_message_tag 1
|
||||||
#define ManufacturingData_fradioFreq_tag 1
|
|
||||||
#define ManufacturingData_hw_model_tag 2
|
|
||||||
#define ManufacturingData_hw_version_tag 3
|
|
||||||
#define ManufacturingData_selftest_result_tag 4
|
|
||||||
#define MyNodeInfo_my_node_num_tag 1
|
#define MyNodeInfo_my_node_num_tag 1
|
||||||
#define MyNodeInfo_has_gps_tag 2
|
#define MyNodeInfo_has_gps_tag 2
|
||||||
#define MyNodeInfo_num_channels_tag 3
|
#define MyNodeInfo_num_channels_tag 3
|
||||||
@ -370,7 +351,9 @@ typedef struct _ToRadio {
|
|||||||
#define RadioConfig_UserPreferences_region_tag 15
|
#define RadioConfig_UserPreferences_region_tag 15
|
||||||
#define RadioConfig_UserPreferences_is_router_tag 37
|
#define RadioConfig_UserPreferences_is_router_tag 37
|
||||||
#define RadioConfig_UserPreferences_is_low_power_tag 38
|
#define RadioConfig_UserPreferences_is_low_power_tag 38
|
||||||
|
#define RadioConfig_UserPreferences_fixed_position_tag 39
|
||||||
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
#define RadioConfig_UserPreferences_factory_reset_tag 100
|
||||||
|
#define RadioConfig_UserPreferences_debug_log_enabled_tag 101
|
||||||
#define RadioConfig_UserPreferences_location_share_tag 32
|
#define RadioConfig_UserPreferences_location_share_tag 32
|
||||||
#define RadioConfig_UserPreferences_gps_operation_tag 33
|
#define RadioConfig_UserPreferences_gps_operation_tag 33
|
||||||
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
|
#define RadioConfig_UserPreferences_gps_update_interval_tag 34
|
||||||
@ -442,7 +425,7 @@ X(a, STATIC, SINGULAR, FIXED32, time, 9)
|
|||||||
#define Position_DEFAULT NULL
|
#define Position_DEFAULT NULL
|
||||||
|
|
||||||
#define Data_FIELDLIST(X, a) \
|
#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)
|
X(a, STATIC, SINGULAR, BYTES, payload, 2)
|
||||||
#define Data_CALLBACK NULL
|
#define Data_CALLBACK NULL
|
||||||
#define Data_DEFAULT NULL
|
#define Data_DEFAULT NULL
|
||||||
@ -537,7 +520,9 @@ X(a, STATIC, SINGULAR, UINT32, gps_update_interval, 34) \
|
|||||||
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
|
X(a, STATIC, SINGULAR, UINT32, gps_attempt_time, 36) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
|
X(a, STATIC, SINGULAR, BOOL, is_router, 37) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
|
X(a, STATIC, SINGULAR, BOOL, is_low_power, 38) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, fixed_position, 39) \
|
||||||
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
X(a, STATIC, SINGULAR, BOOL, factory_reset, 100) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, debug_log_enabled, 101) \
|
||||||
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
|
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
|
||||||
#define RadioConfig_UserPreferences_CALLBACK NULL
|
#define RadioConfig_UserPreferences_CALLBACK NULL
|
||||||
#define RadioConfig_UserPreferences_DEFAULT NULL
|
#define RadioConfig_UserPreferences_DEFAULT NULL
|
||||||
@ -623,14 +608,6 @@ X(a, STATIC, ONEOF, MESSAGE, (variant,set_owner,variant.set_owner), 102)
|
|||||||
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig
|
#define ToRadio_variant_set_radio_MSGTYPE RadioConfig
|
||||||
#define ToRadio_variant_set_owner_MSGTYPE User
|
#define ToRadio_variant_set_owner_MSGTYPE User
|
||||||
|
|
||||||
#define ManufacturingData_FIELDLIST(X, a) \
|
|
||||||
X(a, STATIC, SINGULAR, UINT32, fradioFreq, 1) \
|
|
||||||
X(a, CALLBACK, SINGULAR, STRING, hw_model, 2) \
|
|
||||||
X(a, CALLBACK, SINGULAR, STRING, hw_version, 3) \
|
|
||||||
X(a, STATIC, SINGULAR, SINT32, selftest_result, 4)
|
|
||||||
#define ManufacturingData_CALLBACK pb_default_field_callback
|
|
||||||
#define ManufacturingData_DEFAULT NULL
|
|
||||||
|
|
||||||
extern const pb_msgdesc_t Position_msg;
|
extern const pb_msgdesc_t Position_msg;
|
||||||
extern const pb_msgdesc_t Data_msg;
|
extern const pb_msgdesc_t Data_msg;
|
||||||
extern const pb_msgdesc_t User_msg;
|
extern const pb_msgdesc_t User_msg;
|
||||||
@ -646,7 +623,6 @@ extern const pb_msgdesc_t DeviceState_msg;
|
|||||||
extern const pb_msgdesc_t DebugString_msg;
|
extern const pb_msgdesc_t DebugString_msg;
|
||||||
extern const pb_msgdesc_t FromRadio_msg;
|
extern const pb_msgdesc_t FromRadio_msg;
|
||||||
extern const pb_msgdesc_t ToRadio_msg;
|
extern const pb_msgdesc_t ToRadio_msg;
|
||||||
extern const pb_msgdesc_t ManufacturingData_msg;
|
|
||||||
|
|
||||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
#define Position_fields &Position_msg
|
#define Position_fields &Position_msg
|
||||||
@ -664,25 +640,23 @@ extern const pb_msgdesc_t ManufacturingData_msg;
|
|||||||
#define DebugString_fields &DebugString_msg
|
#define DebugString_fields &DebugString_msg
|
||||||
#define FromRadio_fields &FromRadio_msg
|
#define FromRadio_fields &FromRadio_msg
|
||||||
#define ToRadio_fields &ToRadio_msg
|
#define ToRadio_fields &ToRadio_msg
|
||||||
#define ManufacturingData_fields &ManufacturingData_msg
|
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define Position_size 39
|
#define Position_size 39
|
||||||
#define Data_size 245
|
#define Data_size 246
|
||||||
#define User_size 72
|
#define User_size 72
|
||||||
#define RouteDiscovery_size 88
|
#define RouteDiscovery_size 88
|
||||||
#define SubPacket_size 274
|
#define SubPacket_size 275
|
||||||
#define MeshPacket_size 313
|
#define MeshPacket_size 314
|
||||||
#define ChannelSettings_size 84
|
#define ChannelSettings_size 84
|
||||||
#define RadioConfig_size 308
|
#define RadioConfig_size 314
|
||||||
#define RadioConfig_UserPreferences_size 219
|
#define RadioConfig_UserPreferences_size 225
|
||||||
#define NodeInfo_size 132
|
#define NodeInfo_size 132
|
||||||
#define MyNodeInfo_size 110
|
#define MyNodeInfo_size 110
|
||||||
#define DeviceState_size 5460
|
#define DeviceState_size 5468
|
||||||
#define DebugString_size 258
|
#define DebugString_size 258
|
||||||
#define FromRadio_size 322
|
#define FromRadio_size 323
|
||||||
#define ToRadio_size 316
|
#define ToRadio_size 318
|
||||||
/* ManufacturingData_size depends on runtime parameters */
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
10
src/mesh/portnums.pb.c
Normal file
10
src/mesh/portnums.pb.c
Normal file
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
37
src/mesh/portnums.pb.h
Normal file
37
src/mesh/portnums.pb.h
Normal file
@ -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 <pb.h>
|
||||||
|
|
||||||
|
#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_REMOTE_HARDWARE_APP = 2,
|
||||||
|
PortNum_POSITION_APP = 3,
|
||||||
|
PortNum_NODEINFO_APP = 4,
|
||||||
|
PortNum_PRIVATE_APP = 256,
|
||||||
|
PortNum_IP_TUNNEL_APP = 1024
|
||||||
|
} PortNum;
|
||||||
|
|
||||||
|
/* Helper constants for enums */
|
||||||
|
#define _PortNum_MIN PortNum_UNKNOWN_APP
|
||||||
|
#define _PortNum_MAX PortNum_IP_TUNNEL_APP
|
||||||
|
#define _PortNum_ARRAYSIZE ((PortNum)(PortNum_IP_TUNNEL_APP+1))
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
13
src/mesh/remote_hardware.pb.c
Normal file
13
src/mesh/remote_hardware.pb.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* Automatically generated nanopb constant definitions */
|
||||||
|
/* Generated by nanopb-0.4.1 */
|
||||||
|
|
||||||
|
#include "remote_hardware.pb.h"
|
||||||
|
#if PB_PROTO_HEADER_VERSION != 40
|
||||||
|
#error Regenerate this file with the current version of nanopb generator.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PB_BIND(HardwareMessage, HardwareMessage, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
69
src/mesh/remote_hardware.pb.h
Normal file
69
src/mesh/remote_hardware.pb.h
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/* Automatically generated nanopb header */
|
||||||
|
/* Generated by nanopb-0.4.1 */
|
||||||
|
|
||||||
|
#ifndef PB_REMOTE_HARDWARE_PB_H_INCLUDED
|
||||||
|
#define PB_REMOTE_HARDWARE_PB_H_INCLUDED
|
||||||
|
#include <pb.h>
|
||||||
|
|
||||||
|
#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 _HardwareMessage_Type {
|
||||||
|
HardwareMessage_Type_UNSET = 0,
|
||||||
|
HardwareMessage_Type_WRITE_GPIOS = 1,
|
||||||
|
HardwareMessage_Type_WATCH_GPIOS = 2,
|
||||||
|
HardwareMessage_Type_GPIOS_CHANGED = 3,
|
||||||
|
HardwareMessage_Type_READ_GPIOS = 4,
|
||||||
|
HardwareMessage_Type_READ_GPIOS_REPLY = 5
|
||||||
|
} HardwareMessage_Type;
|
||||||
|
|
||||||
|
/* Struct definitions */
|
||||||
|
typedef struct _HardwareMessage {
|
||||||
|
HardwareMessage_Type typ;
|
||||||
|
uint64_t gpio_mask;
|
||||||
|
uint64_t gpio_value;
|
||||||
|
} HardwareMessage;
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper constants for enums */
|
||||||
|
#define _HardwareMessage_Type_MIN HardwareMessage_Type_UNSET
|
||||||
|
#define _HardwareMessage_Type_MAX HardwareMessage_Type_READ_GPIOS_REPLY
|
||||||
|
#define _HardwareMessage_Type_ARRAYSIZE ((HardwareMessage_Type)(HardwareMessage_Type_READ_GPIOS_REPLY+1))
|
||||||
|
|
||||||
|
|
||||||
|
/* Initializer values for message structs */
|
||||||
|
#define HardwareMessage_init_default {_HardwareMessage_Type_MIN, 0, 0}
|
||||||
|
#define HardwareMessage_init_zero {_HardwareMessage_Type_MIN, 0, 0}
|
||||||
|
|
||||||
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
|
#define HardwareMessage_typ_tag 1
|
||||||
|
#define HardwareMessage_gpio_mask_tag 2
|
||||||
|
#define HardwareMessage_gpio_value_tag 3
|
||||||
|
|
||||||
|
/* Struct field encoding specification for nanopb */
|
||||||
|
#define HardwareMessage_FIELDLIST(X, a) \
|
||||||
|
X(a, STATIC, SINGULAR, UENUM, typ, 1) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT64, gpio_mask, 2) \
|
||||||
|
X(a, STATIC, SINGULAR, UINT64, gpio_value, 3)
|
||||||
|
#define HardwareMessage_CALLBACK NULL
|
||||||
|
#define HardwareMessage_DEFAULT NULL
|
||||||
|
|
||||||
|
extern const pb_msgdesc_t HardwareMessage_msg;
|
||||||
|
|
||||||
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
|
#define HardwareMessage_fields &HardwareMessage_msg
|
||||||
|
|
||||||
|
/* Maximum encoded size of messages (where known) */
|
||||||
|
#define HardwareMessage_size 24
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
44
src/plugins/NodeInfoPlugin.cpp
Normal file
44
src/plugins/NodeInfoPlugin.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "NodeInfoPlugin.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include "Router.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
NodeInfoPlugin nodeInfoPlugin;
|
||||||
|
|
||||||
|
bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User &p)
|
||||||
|
{
|
||||||
|
// FIXME - we currently update NodeInfo data in the DB only if the message was a broadcast or destined to us
|
||||||
|
// it would be better to update even if the message was destined to others.
|
||||||
|
|
||||||
|
nodeDB.updateUser(mp.from, p);
|
||||||
|
|
||||||
|
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
|
||||||
|
|
||||||
|
// Show new nodes on LCD screen
|
||||||
|
if (wasBroadcast) {
|
||||||
|
String lcd = String("Joined: ") + p.long_name + "\n";
|
||||||
|
screen->print(lcd.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false; // Let others look at this message also if they want
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeInfoPlugin::sendOurNodeInfo(NodeNum dest, bool wantReplies)
|
||||||
|
{
|
||||||
|
MeshPacket *p = allocReply();
|
||||||
|
p->to = dest;
|
||||||
|
p->decoded.want_response = wantReplies;
|
||||||
|
|
||||||
|
service.sendToMesh(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshPacket *NodeInfoPlugin::allocReply()
|
||||||
|
{
|
||||||
|
User &u = owner;
|
||||||
|
|
||||||
|
DEBUG_MSG("sending owner %s/%s/%s\n", u.id, u.long_name, u.short_name);
|
||||||
|
return allocDataProtobuf(u);
|
||||||
|
}
|
32
src/plugins/NodeInfoPlugin.h
Normal file
32
src/plugins/NodeInfoPlugin.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ProtobufPlugin.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NodeInfo plugin for sending/receiving NodeInfos into the mesh
|
||||||
|
*/
|
||||||
|
class NodeInfoPlugin : public ProtobufPlugin<User>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
NodeInfoPlugin() : ProtobufPlugin("nodeinfo", PortNum_NODEINFO_APP, User_fields) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send our NodeInfo into the mesh
|
||||||
|
*/
|
||||||
|
void sendOurNodeInfo(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** 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 handleReceivedProtobuf(const MeshPacket &mp, const User &p);
|
||||||
|
|
||||||
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
|
virtual MeshPacket *allocReply();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern NodeInfoPlugin nodeInfoPlugin;
|
51
src/plugins/PositionPlugin.cpp
Normal file
51
src/plugins/PositionPlugin.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "PositionPlugin.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include "Router.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
|
||||||
|
PositionPlugin positionPlugin;
|
||||||
|
|
||||||
|
bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position &p)
|
||||||
|
{
|
||||||
|
// FIXME - we currently update position data in the DB only if the message was a broadcast or destined to us
|
||||||
|
// it would be better to update even if the message was destined to others.
|
||||||
|
|
||||||
|
if (p.time) {
|
||||||
|
struct timeval tv;
|
||||||
|
uint32_t secs = p.time;
|
||||||
|
|
||||||
|
tv.tv_sec = secs;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
|
||||||
|
perhapsSetRTC(RTCQualityFromNet, &tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeDB.updatePosition(mp.from, p);
|
||||||
|
|
||||||
|
return false; // Let others look at this message also if they want
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshPacket *PositionPlugin::allocReply()
|
||||||
|
{
|
||||||
|
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
|
||||||
|
assert(node);
|
||||||
|
assert(node->has_position);
|
||||||
|
|
||||||
|
// Update our local node info with our position (even if we don't decide to update anyone else)
|
||||||
|
auto position = node->position;
|
||||||
|
position.time = getValidTime(RTCQualityGPS); // This nodedb timestamp might be stale, so update it if our clock is valid.
|
||||||
|
|
||||||
|
return allocDataProtobuf(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PositionPlugin::sendOurPosition(NodeNum dest, bool wantReplies)
|
||||||
|
{
|
||||||
|
MeshPacket *p = allocReply();
|
||||||
|
p->to = dest;
|
||||||
|
p->decoded.want_response = wantReplies;
|
||||||
|
|
||||||
|
service.sendToMesh(p);
|
||||||
|
}
|
||||||
|
|
33
src/plugins/PositionPlugin.h
Normal file
33
src/plugins/PositionPlugin.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ProtobufPlugin.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position plugin for sending/receiving positions into the mesh
|
||||||
|
*/
|
||||||
|
class PositionPlugin : public ProtobufPlugin<Position>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
PositionPlugin() : ProtobufPlugin("position", PortNum_POSITION_APP, Position_fields) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send our position into the mesh
|
||||||
|
*/
|
||||||
|
void sendOurPosition(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** 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 handleReceivedProtobuf(const MeshPacket &mp, const Position &p);
|
||||||
|
|
||||||
|
/** Messages can be received that have the want_response bit set. If set, this callback will be invoked
|
||||||
|
* so that subclasses can (optionally) send a response back to the original sender. */
|
||||||
|
virtual MeshPacket *allocReply();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern PositionPlugin positionPlugin;
|
63
src/plugins/RemoteHardwarePlugin.cpp
Normal file
63
src/plugins/RemoteHardwarePlugin.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include "RemoteHardwarePlugin.h"
|
||||||
|
#include "MeshService.h"
|
||||||
|
#include "NodeDB.h"
|
||||||
|
#include "RTC.h"
|
||||||
|
#include "Router.h"
|
||||||
|
#include "configuration.h"
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
RemoteHardwarePlugin remoteHardwarePlugin;
|
||||||
|
|
||||||
|
#define NUM_GPIOS 64
|
||||||
|
|
||||||
|
|
||||||
|
bool RemoteHardwarePlugin::handleReceivedProtobuf(const MeshPacket &req, const HardwareMessage &p)
|
||||||
|
{
|
||||||
|
switch (p.typ) {
|
||||||
|
case HardwareMessage_Type_WRITE_GPIOS:
|
||||||
|
// Print notification to LCD screen
|
||||||
|
screen->print("Write GPIOs\n");
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < NUM_GPIOS; i++) {
|
||||||
|
uint64_t mask = 1 << i;
|
||||||
|
if (p.gpio_mask & mask) {
|
||||||
|
digitalWrite(i, (p.gpio_value & mask) ? 1 : 0);
|
||||||
|
pinMode(i, OUTPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HardwareMessage_Type_READ_GPIOS: {
|
||||||
|
// Print notification to LCD screen
|
||||||
|
screen->print("Read GPIOs\n");
|
||||||
|
|
||||||
|
uint64_t res = 0;
|
||||||
|
for (uint8_t i = 0; i < NUM_GPIOS; i++) {
|
||||||
|
uint64_t mask = 1 << i;
|
||||||
|
if (p.gpio_mask & mask) {
|
||||||
|
pinMode(i, INPUT_PULLUP);
|
||||||
|
if (digitalRead(i))
|
||||||
|
res |= (1 << i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the reply
|
||||||
|
HardwareMessage reply = HardwareMessage_init_default;
|
||||||
|
reply.typ = HardwareMessage_Type_READ_GPIOS_REPLY;
|
||||||
|
reply.gpio_value = res;
|
||||||
|
MeshPacket *p = allocDataProtobuf(reply);
|
||||||
|
setReplyTo(p, req);
|
||||||
|
service.sendToMesh(p);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case HardwareMessage_Type_READ_GPIOS_REPLY:
|
||||||
|
case HardwareMessage_Type_GPIOS_CHANGED:
|
||||||
|
break; // Ignore - we might see our own replies
|
||||||
|
|
||||||
|
default:
|
||||||
|
DEBUG_MSG("Hardware operation %d not yet implemented! FIXME\n", p.typ);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true; // handled
|
||||||
|
}
|
24
src/plugins/RemoteHardwarePlugin.h
Normal file
24
src/plugins/RemoteHardwarePlugin.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ProtobufPlugin.h"
|
||||||
|
#include "remote_hardware.pb.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A plugin that provides easy low-level remote access to device hardware.
|
||||||
|
*/
|
||||||
|
class RemoteHardwarePlugin : public ProtobufPlugin<HardwareMessage>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
RemoteHardwarePlugin() : ProtobufPlugin("remotehardware", PortNum_REMOTE_HARDWARE_APP, HardwareMessage_fields) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** 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 handleReceivedProtobuf(const MeshPacket &mp, const HardwareMessage &p);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern RemoteHardwarePlugin remoteHardwarePlugin;
|
28
src/plugins/TextMessagePlugin.cpp
Normal file
28
src/plugins/TextMessagePlugin.cpp
Normal file
@ -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
|
||||||
|
}
|
25
src/plugins/TextMessagePlugin.h
Normal file
25
src/plugins/TextMessagePlugin.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "SinglePortPlugin.h"
|
||||||
|
#include "Observer.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text message handling for meshtastic - draws on the OLED display the most recent received message
|
||||||
|
*/
|
||||||
|
class TextMessagePlugin : public SinglePortPlugin, public Observable<const MeshPacket *>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
* name is for debugging output
|
||||||
|
*/
|
||||||
|
TextMessagePlugin() : SinglePortPlugin("text", PortNum_TEXT_MESSAGE_APP) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** 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;
|
Loading…
Reference in New Issue
Block a user