Compare commits

..

13 Commits
1.2.1 ... 1.2.4

Author SHA1 Message Date
Kevin Hester
c5b67d821d Merge pull request #730 from geeksville/dev1.2
1.2.4
2021-03-05 13:46:18 +08:00
Kevin Hester
63bf7a29f3 Merge branch 'master' into dev1.2 2021-03-05 13:46:10 +08:00
Kevin Hester
845dd1f9e3 1.2.4 2021-03-05 12:39:39 +08:00
Kevin Hester
c9c44a934d don't generate acks for locally sourced msgs 2021-03-05 12:39:31 +08:00
Kevin Hester
2f6981a27f Merge pull request #729 from geeksville/dev1.2
important fixes for 1.2
2021-03-05 12:07:27 +08:00
Kevin Hester
8739469db3 oops typo 2021-03-05 11:49:37 +08:00
Kevin Hester
0c0c0babba combine acks works 2021-03-05 11:44:45 +08:00
Kevin Hester
950b32232f don't send messages the phone sent us back towards the phone 2021-03-05 10:19:27 +08:00
Kevin Hester
2f6034b067 update todos 2021-03-04 22:10:09 +08:00
Kevin Hester
159f7622e4 Merge pull request #724 from crossan007/improvements_to_env_plugin
Improvements to Environmental Measurement Plugin
2021-03-04 22:00:25 +08:00
Kevin Hester
2cc2fa906a Merge branch 'master' into improvements_to_env_plugin 2021-03-04 20:06:27 +08:00
Charles Crossan
1b71a0f436 refactor ENV to single multi-inheritance class with cleaner user preferences
Fix merge issues

don't log when drawing blank frames

remove useless logging

re-comment stuff

fix comment

unused var
2021-03-03 20:30:20 -05:00
Charles Crossan
2af9e1431e Improvements to EnvironmentalMeasurementPlugin
Instead of holding onto only the last measurement, hold onto a copy of the last MeshPacket containing a measurement

This will make it easier to display the last time received

make DHT sensor reads more reliable

user preference for Farenheit vs Celsius
2021-03-03 08:23:03 -05:00
34 changed files with 309 additions and 213 deletions

View File

@@ -21,32 +21,38 @@ You probably don't care about this section - skip to the next one.
* DONE implement 'get channels' Admin plugin operation
* DONE use get-channels from python
* DONE use get channels & get settings from android
* use set-channel from python
* DONE use set-channel from python
* DONE make settings changes from python work
* DONE pthon should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
* DONE add check for old devices with new API library
* DONE release python api
* DONE release protobufs
* DONE release to developers
* DONE fix setch-fast in python tool
* age out pendingrequests in the python API
* DONE stress test channel download from python, sometimes it seems like we don't get all replies, bug was due to simultaneous android connection
* DONE combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
* DONE don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
* fix 1.1.50 android debug panel display
* warn in android app about unset regions
* use set-channel from android
* test android channel setting
* release to users
* DONE warn in android app about unset regions
* DONE use set-channel from android
* DONE add gui in android app for setting region
* stress test channel download from python, sometimes it seems like we don't get all replies
* investigate @mc-hamster report of heap corruption
* DONE use set-user from android
* combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied)
* don't send packets we received from the phone BACK TOWARDS THE PHONE (possibly use fromnode 0 for packets the phone sends?)
* use portuino TCP connection to debug with python API
* make python tests more exhaustive
* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered)
* stress test multi channel
* pick default random admin key
* exclude admin channels from URL?
* make a way to share just secondary channels via URL
* use single byte 'well known' channel names for the four default channel names (longslow etc), and for admin, gpio, etc...
* use presence of gpio channel to enable gpio ops, same for serial etc...
* pick default random admin key
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
* add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
* restrict gpio & serial & settings operations to the admin channel (unless local to the current node)
* add channel restrictions for plugins (and restrict routing plugin to the "control" channel)
* stress test multi channel
* investigate @mc-hamster report of heap corruption
* DONE use set-user from android
* use portuino TCP connection to debug with python API
* document the relationship between want_response (indicating remote node received it) and want_ack (indicating that this message should be sent reliably - and also get acks from the first rx node and naks if it is never delivered)
* DONE android should stop fetching channels once we've reached our first empty channel definition (hasSettings == true)
* DONE warn in python api if we are too new to talk to the device code
* DONE make a post warning about 1.2, telling how to stay on old android & python clients. link to this from the android dialog message and python version warning.
* DONE "FIXME - move the radioconfig/user/channel READ operations into SettingsMessage as well"
@@ -58,6 +64,7 @@ You probably don't care about this section - skip to the next one.
* confirm we are still calling the plugins for messages inbound from the phone (or generated locally)
* confirm we are still multi hop routing flood broadcasts
* confirm we are still doing resends on unicast reliable packets
* add history to routed packets: https://meshtastic.discourse.group/t/packet-source-tracking/2764/2
* add support for full DSR unicast delivery
* DONE move acks into routing
* DONE make all subpackets different versions of data

2
proto

Submodule proto updated: 94bd0aae44...ac4f53ed8c

View File

@@ -229,7 +229,7 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state
displayedNodeNum = 0; // Not currently showing a node pane
MeshPacket &mp = devicestate.rx_text_message;
NodeInfo *node = nodeDB.getNode(mp.from);
NodeInfo *node = nodeDB.getNode(getFrom(&mp));
// DEBUG_MSG("drawing text message from 0x%x: %s\n", mp.from,
// mp.decoded.variant.data.decoded.bytes);

View File

@@ -69,7 +69,7 @@ void DSRRouter::sniffReceived(const MeshPacket *p, const Routing *c)
// ignore rebroadcasts.
// this will also add records for any ACKs we receive for our messages
if (p->to != NODENUM_BROADCAST || p->hop_limit != HOP_RELIABLE) {
addRoute(p->from, p->from, 0); // We are adjacent with zero hops
addRoute(getFrom(p), getFrom(p), 0); // We are adjacent with zero hops
}
if (c)

View File

@@ -31,7 +31,7 @@ void FloodingRouter::sniffReceived(const MeshPacket *p, const Routing *c)
{
// If a broadcast, possibly _also_ send copies out into the mesh.
// (FIXME, do something smarter than naive flooding here)
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && p->from != getNodeNum()) {
if (p->to == NODENUM_BROADCAST && p->hop_limit > 0 && getFrom(p) != getNodeNum()) {
if (p->id != 0) {
MeshPacket *tosend = packetPool.allocCopy(*p); // keep a copy because we will be sending it

View File

@@ -71,7 +71,7 @@ static PacketId findId;
static bool isMyPacket(MeshPacket *p)
{
return p->id == findId && p->from == findFrom;
return p->id == findId && getFrom(p) == findFrom;
}
/** Attempt to find and remove a packet from this queue. Returns true the packet which was removed from the queue */

View File

@@ -1,23 +1,28 @@
#include "MeshPlugin.h"
#include "NodeDB.h"
#include "MeshService.h"
#include "NodeDB.h"
#include <assert.h>
std::vector<MeshPlugin *> *MeshPlugin::plugins;
const MeshPacket *MeshPlugin::currentRequest;
/**
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks
*/
MeshPacket *MeshPlugin::currentReply;
MeshPlugin::MeshPlugin(const char *_name) : name(_name)
{
// Can't trust static initalizer order, so we check each time
if(!plugins)
if (!plugins)
plugins = new std::vector<MeshPlugin *>();
plugins->push_back(this);
}
void MeshPlugin::setup() {
}
void MeshPlugin::setup() {}
MeshPlugin::~MeshPlugin()
{
@@ -31,6 +36,8 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
assert(mp.which_payloadVariant == MeshPacket_decoded_tag); // I think we are guarnteed the packet is decoded by this point?
currentReply = NULL; // No reply yet
// Was this message directed to us specifically? Will be false if we are sniffing someone elses packets
auto ourNodeNum = nodeDB.getNodeNum();
bool toUs = mp.to == NODENUM_BROADCAST || mp.to == ourNodeNum;
@@ -48,15 +55,16 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
bool handled = pi.handleReceived(mp);
// Possibly send replies (but only if the message was directed to us specifically, i.e. not for promiscious sniffing)
// also: we only let the one plugin send a reply, once that happens, remaining plugins are not considered
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because currently when the phone
// sends things, it sends things using the local node ID as the from address. A better solution (FIXME) would be to let phones
// have their own distinct addresses and we 'route' to them like any other node.
if (mp.decoded.want_response && toUs && (mp.from != ourNodeNum || mp.to == ourNodeNum)) {
// NOTE: we send a reply *even if the (non broadcast) request was from us* which is unfortunate but necessary because
// currently when the phone sends things, it sends things using the local node ID as the from address. A better
// solution (FIXME) would be to let phones have their own distinct addresses and we 'route' to them like any other
// node.
if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum) && !currentReply) {
pi.sendResponse(mp);
DEBUG_MSG("Plugin %s sent a response\n", pi.name);
}
else {
} else {
DEBUG_MSG("Plugin %s considered\n", pi.name);
}
if (handled) {
@@ -64,11 +72,17 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
break;
}
}
pi.currentRequest = NULL;
}
if(!pluginFound)
if(currentReply) {
DEBUG_MSG("Sending response\n");
service.sendToMesh(currentReply);
currentReply = NULL;
}
if (!pluginFound)
DEBUG_MSG("No plugins interested in portnum=%d\n", mp.decoded.portnum);
}
@@ -76,39 +90,43 @@ void MeshPlugin::callPlugins(const MeshPacket &mp)
* so that subclasses can (optionally) send a response back to the original sender. Implementing this method
* is optional
*/
void MeshPlugin::sendResponse(const MeshPacket &req) {
void MeshPlugin::sendResponse(const MeshPacket &req)
{
auto r = allocReply();
if(r) {
DEBUG_MSG("Sending response\n");
if (r) {
setReplyTo(r, req);
service.sendToMesh(r);
}
else {
currentReply = r;
} else {
// Ignore - this is now expected behavior for routing plugin (because it ignores some replies)
// 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
/** 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) {
*/
void setReplyTo(MeshPacket *p, const MeshPacket &to)
{
assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now
p->to = to.from;
p->want_ack = to.want_ack;
p->to = getFrom(&to);
// No need for an ack if we are just delivering locally (it just generates an ignored ack)
p->want_ack = (to.from != 0) ? to.want_ack : false;
if(p->priority == MeshPacket_Priority_UNSET)
p->priority = MeshPacket_Priority_RELIABLE;
p->decoded.request_id = to.id;
}
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames() {
std::vector<MeshPlugin *> MeshPlugin::GetMeshPluginsWithUIFrames()
{
std::vector<MeshPlugin *> pluginsWithUIFrames;
std::vector<MeshPlugin *> pluginsWithUIFrames;
for (auto i = plugins->begin(); i != plugins->end(); ++i) {
auto &pi = **i;
if ( pi.wantUIFrame()) {
if (pi.wantUIFrame()) {
DEBUG_MSG("Plugin wants a UI Frame\n");
pluginsWithUIFrames.push_back(&pi);
}
}
return pluginsWithUIFrames;
}

View File

@@ -82,6 +82,13 @@ class MeshPlugin
private:
/**
* If any of the current chain of plugins has already sent a reply, it will be here. This is useful to allow
* the RoutingPlugin to avoid sending redundant acks
*/
static MeshPacket *currentReply;
friend class ReliableRouter;
/** 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

View File

@@ -13,8 +13,8 @@
#include "RTC.h"
#include "main.h"
#include "mesh-pb-constants.h"
#include "plugins/PositionPlugin.h"
#include "plugins/NodeInfoPlugin.h"
#include "plugins/PositionPlugin.h"
#include "power.h"
/*
@@ -51,8 +51,6 @@ MeshService service;
#include "Router.h"
MeshService::MeshService() : toPhoneQueue(MAX_RX_TOPHONE)
{
// assert(MAX_RX_TOPHONE == 32); // FIXME, delete this, just checking my clever macro
@@ -67,7 +65,6 @@ void MeshService::init()
gpsObserver.observe(&gps->newStatus);
}
int MeshService::handleFromRadio(const MeshPacket *mp)
{
powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping
@@ -128,8 +125,12 @@ void MeshService::reloadOwner()
*/
void MeshService::handleToRadio(MeshPacket &p)
{
if (p.from == 0) // If the phone didn't set a sending node ID, use ours
p.from = nodeDB.getNodeNum();
if (p.from != 0) { // We don't let phones assign nodenums to their sent messages
DEBUG_MSG("Warning: phone tried to pick a nodenum, we don't allow that.\n");
p.from = 0;
} else {
// p.from = nodeDB.getNodeNum();
}
if (p.id == 0)
p.id = generatePacketId(); // If the phone didn't supply one, then pick one
@@ -151,7 +152,8 @@ void MeshService::handleToRadio(MeshPacket &p)
}
/** Attempt to cancel a previously sent packet from this _local_ node. Returns true if a packet was found we could cancel */
bool MeshService::cancelSending(PacketId id) {
bool MeshService::cancelSending(PacketId id)
{
return router->cancelSending(nodeDB.getNodeNum(), id);
}
@@ -176,21 +178,22 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies)
nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies);
}
NodeInfo *MeshService::refreshMyNodeInfo() {
NodeInfo *MeshService::refreshMyNodeInfo()
{
NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum());
assert(node);
// We might not have a position yet for our local node, in that case, at least try to send the time
if(!node->has_position) {
if (!node->has_position) {
memset(&node->position, 0, sizeof(node->position));
node->has_position = true;
}
Position &position = node->position;
// Update our local node info with our position (even if we don't decide to update anyone else)
position.time = getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
position.time =
getValidTime(RTCQualityFromNet); // This nodedb timestamp might be stale, so update it if our clock is kinda valid
position.battery_level = powerStatus->getBatteryChargePercent();
updateBatteryLevel(position.battery_level);
@@ -209,11 +212,10 @@ int MeshService::onGPSChanged(const meshtastic::GPSStatus *unused)
pos.altitude = gps->altitude;
pos.latitude_i = gps->latitude;
pos.longitude_i = gps->longitude;
}
else {
} else {
// The GPS has lost lock, if we are fixed position we should just keep using
// the old position
if(radioConfig.preferences.fixed_position) {
if (radioConfig.preferences.fixed_position) {
DEBUG_MSG("WARNING: Using fixed position\n");
} else {
// throw away old position

View File

@@ -32,4 +32,10 @@ typedef uint32_t PacketId; // A packet sequence number
typedef int ErrorCode;
/// Alloc and free packets to our global, ISR safe pool
extern Allocator<MeshPacket> &packetPool;
extern Allocator<MeshPacket> &packetPool;
/**
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node.
* If from is zero this function returns our node number instead
*/
NodeNum getFrom(const MeshPacket *p);

View File

@@ -66,6 +66,14 @@ NodeNum displayedNodeNum;
NodeDB::NodeDB() : nodes(devicestate.node_db), numNodes(&devicestate.node_db_count) {}
/**
* Most (but not always) of the time we want to treat packets 'from' the local phone (where from == 0), as if they originated on the local node.
* If from is zero this function returns our node number instead
*/
NodeNum getFrom(const MeshPacket *p) {
return (p->from == 0) ? nodeDB.getNodeNum() : p->from;
}
bool NodeDB::resetRadioConfig()
{
bool didFactoryReset = false;
@@ -406,7 +414,7 @@ void NodeDB::updateFrom(const MeshPacket &mp)
if (mp.which_payloadVariant == MeshPacket_decoded_tag) {
DEBUG_MSG("Update DB node 0x%x, rx_time=%u\n", mp.from, mp.rx_time);
NodeInfo *info = getOrCreateNode(mp.from);
NodeInfo *info = getOrCreateNode(getFrom(&mp));
if (mp.rx_time) { // if the packet has a valid timestamp use it to update our last_seen
info->has_position = true; // at least the time is valid

View File

@@ -183,3 +183,4 @@ PREF_GET(min_wake_secs, 10)
* might have changed is incremented. Allows others to detect they might now be on a new channel.
*/
extern uint32_t radioGeneration;

View File

@@ -26,7 +26,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
// DEBUG_MSG("Deleting old broadcast record %d\n", i);
recentPackets.erase(recentPackets.begin() + i); // delete old record
} else {
if (r.id == p->id && r.sender == p->from) {
if (r.id == p->id && r.sender == getFrom(p)) {
DEBUG_MSG("Found existing packet record for fr=0x%x,to=0x%x,id=%d\n", p->from, p->to, p->id);
// Update the time on this record to now
@@ -43,7 +43,7 @@ bool PacketHistory::wasSeenRecently(const MeshPacket *p, bool withUpdate)
if (withUpdate) {
PacketRecord r;
r.id = p->id;
r.sender = p->from;
r.sender = getFrom(p);
r.rxTimeMsec = now;
recentPackets.push_back(r);
printPacket("Adding packet record", p);

View File

@@ -59,6 +59,7 @@ void PhoneAPI::handleToRadio(const uint8_t *buf, size_t bufLength)
}
// return (lastContactMsec != 0) &&
memset(&toRadioScratch, 0, sizeof(toRadioScratch));
if (pb_decode_from_bytes(buf, bufLength, ToRadio_fields, &toRadioScratch)) {
switch (toRadioScratch.which_payloadVariant) {
case ToRadio_packet_tag: {

View File

@@ -58,11 +58,12 @@ template <class T> class ProtobufPlugin : protected SinglePortPlugin
// it would be better to update even if the message was destined to others.
auto &p = mp.decoded;
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, payloadlen=%d\n", name, mp.from, mp.id, p.payload.size);
DEBUG_MSG("Received %s from=0x%0x, id=0x%x, portnum=%d, payloadlen=%d\n", name, mp.from, mp.id, p.portnum, p.payload.size);
T scratch;
T *decoded = NULL;
if(mp.decoded.portnum == ourPortNum) {
memset(&scratch, 0, sizeof(scratch));
if (pb_decode_from_bytes(p.payload.bytes, p.payload.size, fields, &scratch))
decoded = &scratch;
else

View File

@@ -2,6 +2,7 @@
#include "MeshTypes.h"
#include "configuration.h"
#include "mesh-pb-constants.h"
#include "MeshPlugin.h"
// ReliableRouter::ReliableRouter() {}
@@ -26,15 +27,17 @@ ErrorCode ReliableRouter::send(MeshPacket *p)
bool ReliableRouter::shouldFilterReceived(const MeshPacket *p)
{
// Note: do not use getFrom() here, because we want to ignore messages sent from phone
if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) {
printPacket("Rx someone rebroadcasting for us", p);
// We are seeing someone rebroadcast one of our broadcast attempts.
// If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for
// the original sending process.
if (stopRetransmission(p->from, p->id)) {
if (stopRetransmission(getFrom(p), p->id)) {
DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n");
sendAckNak(Routing_Error_NONE, p->from, p->id);
if(p->want_ack)
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
}
}
@@ -60,23 +63,26 @@ void ReliableRouter::sniffReceived(const MeshPacket *p, const Routing *c)
if (p->to == ourNode) { // ignore ack/nak/want_ack packets that are not address to us (we only handle 0 hop reliability
// - not DSR routing)
if (p->want_ack) {
sendAckNak(Routing_Error_NONE, p->from, p->id);
if(MeshPlugin::currentReply)
DEBUG_MSG("Someone else has replied to this message, no need for a 2nd ack");
else
sendAckNak(Routing_Error_NONE, getFrom(p), p->id);
}
// If the payload is valid, look for ack/nak
if (c) {
PacketId ackId = c->error_reason == Routing_Error_NONE ? p->decoded.request_id : 0;
PacketId nakId = c->error_reason != Routing_Error_NONE ? p->decoded.request_id : 0;
// We consider an ack to be either a !routing packet with a request ID or a routing packet with !error
PacketId ackId = ((c && c->error_reason == Routing_Error_NONE) || !c) ? p->decoded.request_id : 0;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId) {
if (ackId) {
DEBUG_MSG("Received a ack=%d, stopping retransmissions\n", ackId);
stopRetransmission(p->to, ackId);
} else {
DEBUG_MSG("Received a nak=%d, stopping retransmissions\n", nakId);
stopRetransmission(p->to, nakId);
}
// A nak is a routing packt that has an error code
PacketId nakId = (c && c->error_reason != Routing_Error_NONE) ? p->decoded.request_id : 0;
// We intentionally don't check wasSeenRecently, because it is harmless to delete non existent retransmission records
if (ackId || nakId) {
if (ackId) {
DEBUG_MSG("Received a ack for 0x%x, stopping retransmissions\n", ackId);
stopRetransmission(p->to, ackId);
} else {
DEBUG_MSG("Received a nak for 0x%x, stopping retransmissions\n", nakId);
stopRetransmission(p->to, nakId);
}
}
}
@@ -131,7 +137,7 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p)
auto rec = PendingPacket(p);
setNextTx(&rec);
stopRetransmission(p->from, p->id);
stopRetransmission(getFrom(p), p->id);
pending[id] = rec;
return &pending[id];

View File

@@ -15,7 +15,7 @@ struct GlobalPacketId {
GlobalPacketId(const MeshPacket *p)
{
node = p->from;
node = getFrom(p);
id = p->id;
}

View File

@@ -111,7 +111,7 @@ void Router::sendAckNak(Routing_Error err, NodeNum to, PacketId idFrom)
void Router::abortSendAndNak(Routing_Error err, MeshPacket *p)
{
DEBUG_MSG("Error=%d, returning NAK and dropping packet.\n", err);
sendAckNak(Routing_Error_NO_INTERFACE, p->from, p->id);
sendAckNak(Routing_Error_NO_INTERFACE, getFrom(p), p->id);
packetPool.release(p);
}
@@ -155,6 +155,10 @@ ErrorCode Router::send(MeshPacket *p)
if (p->to == NODENUM_BROADCAST)
p->want_ack = false;
// Up until this point we might have been using 0 for the from address (if it started with the phone), but when we send over
// the lora we need to make sure we have replaced it with our local address
p->from = getFrom(p);
// If the packet hasn't yet been encrypted, do so now (it might already be encrypted if we are just forwarding it)
assert(p->which_payloadVariant == MeshPacket_encrypted_tag ||
@@ -227,6 +231,7 @@ bool Router::perhapsDecode(MeshPacket *p)
crypto->decrypt(p->from, p->id, p->encrypted.size, bytes);
// Take those raw bytes and convert them back into a well structured protobuf we can understand
memset(&p->decoded, 0, sizeof(p->decoded));
if (!pb_decode_from_bytes(bytes, p->encrypted.size, Data_fields, &p->decoded)) {
DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?!\n");
} else {
@@ -273,7 +278,7 @@ void Router::handleReceived(MeshPacket *p)
void Router::perhapsHandleReceived(MeshPacket *p)
{
assert(radioConfig.has_preferences);
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, p->from);
bool ignore = is_in_repeated(radioConfig.preferences.ignore_incoming, getFrom(p));
if (ignore)
DEBUG_MSG("Ignoring incoming message, 0x%x is in our ignore list\n", p->from);

View File

@@ -67,7 +67,7 @@ extern const pb_msgdesc_t AdminMessage_msg;
#define AdminMessage_fields &AdminMessage_msg
/* Maximum encoded size of messages (where known) */
#define AdminMessage_size 338
#define AdminMessage_size 351
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -82,7 +82,7 @@ extern const pb_msgdesc_t DeviceState_msg;
#define DeviceState_fields &DeviceState_msg
/* Maximum encoded size of messages (where known) */
#define DeviceState_size 6156
#define DeviceState_size 6169
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -20,10 +20,10 @@ typedef enum _PortNum {
PortNum_ADMIN_APP = 6,
PortNum_REPLY_APP = 32,
PortNum_IP_TUNNEL_APP = 33,
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 34,
PortNum_SERIAL_APP = 64,
PortNum_STORE_FORWARD_APP = 65,
PortNum_RANGE_TEST_APP = 66,
PortNum_ENVIRONMENTAL_MEASUREMENT_APP = 67,
PortNum_PRIVATE_APP = 256,
PortNum_ATAK_FORWARDER = 257,
PortNum_MAX = 511

View File

@@ -17,3 +17,4 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2)

View File

@@ -56,6 +56,10 @@ typedef enum _LocationSharing {
LocationSharing_LocDisabled = 2
} LocationSharing;
typedef enum _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType {
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11 = 0
} RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType;
/* Struct definitions */
typedef struct _RadioConfig_UserPreferences {
uint32_t position_broadcast_secs;
@@ -106,6 +110,9 @@ typedef struct _RadioConfig_UserPreferences {
uint32_t environmental_measurement_plugin_read_error_count_threshold;
uint32_t environmental_measurement_plugin_update_interval;
uint32_t environmental_measurement_plugin_recovery_interval;
bool environmental_measurement_plugin_display_farenheit;
RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType environmental_measurement_plugin_sensor_type;
uint32_t environmental_measurement_plugin_sensor_pin;
} RadioConfig_UserPreferences;
typedef struct _RadioConfig {
@@ -131,6 +138,10 @@ typedef struct _RadioConfig {
#define _LocationSharing_MAX LocationSharing_LocDisabled
#define _LocationSharing_ARRAYSIZE ((LocationSharing)(LocationSharing_LocDisabled+1))
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MAX RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11
#define _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_ARRAYSIZE ((RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType)(RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11+1))
#ifdef __cplusplus
extern "C" {
@@ -138,9 +149,9 @@ extern "C" {
/* Initializer values for message structs */
#define RadioConfig_init_default {false, RadioConfig_UserPreferences_init_default}
#define RadioConfig_UserPreferences_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0}
#define RadioConfig_init_zero {false, RadioConfig_UserPreferences_init_zero}
#define RadioConfig_UserPreferences_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "", "", 0, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, _RegionCode_MIN, _ChargeCurrent_MIN, _LocationSharing_MIN, _GpsOperation_MIN, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_MIN, 0}
/* Field tags (for use in manual encoding/decoding) */
#define RadioConfig_UserPreferences_position_broadcast_secs_tag 1
@@ -190,6 +201,9 @@ extern "C" {
#define RadioConfig_UserPreferences_environmental_measurement_plugin_read_error_count_threshold_tag 142
#define RadioConfig_UserPreferences_environmental_measurement_plugin_update_interval_tag 143
#define RadioConfig_UserPreferences_environmental_measurement_plugin_recovery_interval_tag 144
#define RadioConfig_UserPreferences_environmental_measurement_plugin_display_farenheit_tag 145
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_type_tag 146
#define RadioConfig_UserPreferences_environmental_measurement_plugin_sensor_pin_tag 147
#define RadioConfig_preferences_tag 1
/* Struct field encoding specification for nanopb */
@@ -246,7 +260,10 @@ X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_measurement_
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_screen_enabled, 141) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_read_error_count_threshold, 142) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_update_interval, 143) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144)
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_recovery_interval, 144) \
X(a, STATIC, SINGULAR, BOOL, environmental_measurement_plugin_display_farenheit, 145) \
X(a, STATIC, SINGULAR, UENUM, environmental_measurement_plugin_sensor_type, 146) \
X(a, STATIC, SINGULAR, UINT32, environmental_measurement_plugin_sensor_pin, 147)
#define RadioConfig_UserPreferences_CALLBACK NULL
#define RadioConfig_UserPreferences_DEFAULT NULL
@@ -258,8 +275,8 @@ extern const pb_msgdesc_t RadioConfig_UserPreferences_msg;
#define RadioConfig_UserPreferences_fields &RadioConfig_UserPreferences_msg
/* Maximum encoded size of messages (where known) */
#define RadioConfig_size 335
#define RadioConfig_UserPreferences_size 332
#define RadioConfig_size 348
#define RadioConfig_UserPreferences_size 345
#ifdef __cplusplus
} /* extern "C" */

View File

@@ -147,7 +147,7 @@ bool ExternalNotificationPluginRadio::handleReceived(const MeshPacket &mp)
auto &p = mp.decoded;
if (mp.from != nodeDB.getNodeNum()) {
if (getFrom(&mp) != nodeDB.getNodeNum()) {
// TODO: This may be a problem if messages are sent in unicide, but I'm not sure if it will.
// Need to know if and how this could be a problem.

View File

@@ -12,7 +12,7 @@ bool NodeInfoPlugin::handleReceivedProtobuf(const MeshPacket &mp, const User *pp
{
auto p = *pptr;
nodeDB.updateUser(mp.from, p);
nodeDB.updateUser(getFrom(&mp), p);
bool wasBroadcast = mp.to == NODENUM_BROADCAST;

View File

@@ -20,7 +20,6 @@
*/
void setupPlugins()
{
routingPlugin = new RoutingPlugin();
adminPlugin = new AdminPlugin();
nodeInfoPlugin = new NodeInfoPlugin();
positionPlugin = new PositionPlugin();
@@ -48,4 +47,7 @@ void setupPlugins()
// new StoreForwardPlugin();
new EnvironmentalMeasurementPlugin();
#endif
// NOTE! This plugin must be added LAST because it likes to check for replies from other plugins and avoid sending extra acks
routingPlugin = new RoutingPlugin();
}

View File

@@ -30,7 +30,7 @@ bool PositionPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Position
perhapsSetRTC(RTCQualityFromNet, &tv);
}
nodeDB.updatePosition(mp.from, p);
nodeDB.updatePosition(getFrom(&mp), p);
return false; // Let others look at this message also if they want
}

View File

@@ -9,11 +9,12 @@ RoutingPlugin *routingPlugin;
bool RoutingPlugin::handleReceivedProtobuf(const MeshPacket &mp, const Routing *r)
{
DEBUG_MSG("Routing sniffing", &mp);
printPacket("Routing sniffing", &mp);
router->sniffReceived(&mp, r);
// FIXME - move this to a non promsicious PhoneAPI plugin?
if (mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) {
// Note: we are careful not to send back packets that started with the phone back to the phone
if ((mp.to == NODENUM_BROADCAST || mp.to == nodeDB.getNodeNum()) && (mp.from != 0)) {
printPacket("Delivering rx packet", &mp);
service.handleFromRadio(&mp);
}

View File

@@ -160,7 +160,7 @@ bool SerialPluginRadio::handleReceived(const MeshPacket &mp)
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
if (mp.from == nodeDB.getNodeNum()) {
if (getFrom(&mp) == nodeDB.getNodeNum()) {
/*
* If radioConfig.preferences.serialplugin_echo is true, then echo the packets that are sent out back to the TX

View File

@@ -10,20 +10,10 @@
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
EnvironmentalMeasurementPlugin::EnvironmentalMeasurementPlugin() : concurrency::OSThread("EnvironmentalMeasurementPlugin") {}
uint32_t sensor_read_error_count = 0;
#define DHT_11_GPIO_PIN 13
#define DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS 1000 // Some sensors (the DHT11) have a minimum required duration between read attempts
#define FAILED_STATE_SENSOR_READ_MULTIPLIER 10
#define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true
DHT dht(DHT_11_GPIO_PIN,DHT11);
#ifdef HAS_EINK
// The screen is bigger so use bigger fonts
@@ -49,11 +39,15 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
Uncomment the preferences below if you want to use the plugin
without having to configure it from the PythonAPI or WebUI.
*/
/*radioConfig.preferences.environmental_measurement_plugin_measurement_enabled = 1;
radioConfig.preferences.environmental_measurement_plugin_screen_enabled = 1;
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold = 5;
radioConfig.preferences.environmental_measurement_plugin_update_interval = 30;
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 600;*/
radioConfig.preferences.environmental_measurement_plugin_recovery_interval = 60;
radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true;
radioConfig.preferences.environmental_measurement_plugin_sensor_pin = 13;
radioConfig.preferences.environmental_measurement_plugin_sensor_type = RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType::RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11;*/
if (! (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
// If this plugin is not enabled, and the user doesn't want the display screen don't waste any OSThread time on it
@@ -62,20 +56,32 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
if (firstTime) {
// This is the first time the OSThread library has called this function, so do some setup
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
environmentalMeasurementPluginRadio = new EnvironmentalMeasurementPluginRadio();
firstTime = 0;
// begin reading measurements from the sensor
// DHT have a max read-rate of 1HZ, so we should wait at least 1 second
// after initializing the sensor before we try to read from it.
// returning the interval here means that the next time OSThread
// calls our plugin, we'll run the other branch of this if statement
// and actually do a "sendOurEnvironmentalMeasurement()"
if (radioConfig.preferences.environmental_measurement_plugin_measurement_enabled)
{
DEBUG_MSG("EnvironmentalMeasurement: Initializing\n");
// it's possible to have this plugin enabled, only for displaying values on the screen.
// therefore, we should only enable the sensor loop if measurement is also enabled
dht.begin();
switch(radioConfig.preferences.environmental_measurement_plugin_sensor_type) {
case RadioConfig_UserPreferences_EnvironmentalMeasurementSensorType_DHT11:
dht = new DHT(radioConfig.preferences.environmental_measurement_plugin_sensor_pin,DHT11);
this->dht->begin();
this->dht->read();
DEBUG_MSG("EnvironmentalMeasurement: Opened DHT11 on pin: %d\n",radioConfig.preferences.environmental_measurement_plugin_sensor_pin);
break;
default:
DEBUG_MSG("EnvironmentalMeasurement: Invalid sensor type selected; Disabling plugin");
return (INT32_MAX);
break;
}
// begin reading measurements from the sensor
// DHT have a max read-rate of 1HZ, so we should wait at least 1 second
// after initializing the sensor before we try to read from it.
// returning the interval here means that the next time OSThread
// calls our plugin, we'll run the other branch of this if statement
// and actually do a "sendOurEnvironmentalMeasurement()"
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
}
return (INT32_MAX);
@@ -96,6 +102,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
"EnvironmentalMeasurement: TEMPORARILY DISABLED; The environmental_measurement_plugin_read_error_count_threshold has been exceed: %d. Will retry reads in %d seconds\n",
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold,
radioConfig.preferences.environmental_measurement_plugin_recovery_interval);
sensor_read_error_count = 0;
return(radioConfig.preferences.environmental_measurement_plugin_recovery_interval*1000);
}
DEBUG_MSG(
@@ -110,7 +117,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
sensor_read_error_count,
radioConfig.preferences.environmental_measurement_plugin_read_error_count_threshold-sensor_read_error_count);
}
if (! environmentalMeasurementPluginRadio->sendOurEnvironmentalMeasurement() ){
if (!sendOurEnvironmentalMeasurement() ){
// if we failed to read the sensor, then try again
// as soon as we can according to the maximum polling frequency
return(DHT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS);
@@ -123,25 +130,16 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() {
#endif
}
bool EnvironmentalMeasurementPluginRadio::wantUIFrame() {
bool EnvironmentalMeasurementPlugin::wantUIFrame() {
return radioConfig.preferences.environmental_measurement_plugin_screen_enabled;
}
void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
display->drawString(x, y, "Environment");
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": T:"+ String(lastMeasurement.temperature,2) + " H:" + String(lastMeasurement.relative_humidity,2));
}
String GetSenderName(const MeshPacket &mp) {
String sender;
if (nodeDB.getNode(mp.from)){
sender = nodeDB.getNode(mp.from)->user.short_name;
auto node = nodeDB.getNode(getFrom(&mp));
if (node){
sender = node->user.short_name;
}
else {
sender = "UNK";
@@ -149,55 +147,99 @@ String GetSenderName(const MeshPacket &mp) {
return sender;
}
bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *pptr)
uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) {
uint32_t now = getTime();
uint32_t last_seen = mp->rx_time;
int delta = (int)(now - last_seen);
if (delta < 0) // our clock must be slightly off still - not set from GPS yet
delta = 0;
return delta;
}
float EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c) {
return (c*9)/5 + 32;
}
void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
const EnvironmentalMeasurement &p = *pptr;
display->setTextAlignment(TEXT_ALIGN_LEFT);
display->setFont(FONT_MEDIUM);
display->drawString(x, y, "Environment");
if (lastMeasurementPacket == nullptr) {
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), "No measurement");
//DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame\n");
return;
}
EnvironmentalMeasurement lastMeasurement;
uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket);
String lastSender = GetSenderName(*lastMeasurementPacket);
auto &p = lastMeasurementPacket->decoded;
if (!pb_decode_from_bytes(p.payload.bytes,
p.payload.size,
EnvironmentalMeasurement_fields,
&lastMeasurement)) {
display->setFont(FONT_SMALL);
display->drawString(x, y += fontHeight(FONT_MEDIUM), "Measurement Error");
DEBUG_MSG("EnvironmentalMeasurement: unable to decode last packet");
return;
}
display->setFont(FONT_SMALL);
String last_temp = String(lastMeasurement.temperature,0) +"°C";
if (radioConfig.preferences.environmental_measurement_plugin_display_farenheit){
last_temp = String(CelsiusToFarenheit(lastMeasurement.temperature),0) +"°F";;
}
display->drawString(x, y += fontHeight(FONT_MEDIUM), lastSender+": "+last_temp +"/"+ String(lastMeasurement.relative_humidity,0) + "%("+String(agoSecs)+"s)");
}
bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p)
{
if (!(radioConfig.preferences.environmental_measurement_plugin_measurement_enabled || radioConfig.preferences.environmental_measurement_plugin_screen_enabled)){
// If this plugin is not enabled in any capacity, don't handle the packet, and allow other plugins to consume
return false;
}
bool wasBroadcast = mp.to == NODENUM_BROADCAST;
String sender = GetSenderName(mp);
// Show new nodes on LCD screen
if (DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN && wasBroadcast) {
String lcd = String("Env Measured: ") +sender + "\n" +
"T: " + p.temperature + "\n" +
"H: " + p.relative_humidity + "\n";
screen->print(lcd.c_str());
}
DEBUG_MSG("-----------------------------------------\n");
DEBUG_MSG("EnvironmentalMeasurement: Received data from %s\n", sender);
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity);
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature);
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p->relative_humidity);
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p->temperature);
lastMeasurementPacket = packetPool.allocCopy(mp);
lastMeasurement = p;
lastSender = sender;
return false; // Let others look at this message also if they want
}
bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies)
bool EnvironmentalMeasurementPlugin::sendOurEnvironmentalMeasurement(NodeNum dest, bool wantReplies)
{
EnvironmentalMeasurement m;
m.barometric_pressure = 0; // TODO: Add support for barometric sensors
m.relative_humidity = dht.readHumidity();
m.temperature = dht.readTemperature();;
DEBUG_MSG("-----------------------------------------\n");
DEBUG_MSG("EnvironmentalMeasurement: Read data\n");
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
if (isnan(m.relative_humidity) || isnan(m.temperature) ){
if (!this->dht->read(true)){
sensor_read_error_count++;
DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n");
return false;
}
m.relative_humidity = this->dht->readHumidity();
m.temperature = this->dht->readTemperature();
DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", m.relative_humidity);
DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", m.temperature);
sensor_read_error_count = 0;

View File

@@ -3,61 +3,32 @@
#include "../mesh/generated/environmental_measurement.pb.h"
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
#include <DHT.h>
class EnvironmentalMeasurementPlugin : private concurrency::OSThread
class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public ProtobufPlugin<EnvironmentalMeasurement>
{
bool firstTime = 1;
public:
EnvironmentalMeasurementPlugin();
EnvironmentalMeasurementPlugin(): concurrency::OSThread("EnvironmentalMeasurementPlugin"), ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {
lastMeasurementPacket = nullptr;
}
virtual bool wantUIFrame();
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
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 EnvironmentalMeasurement *p);
virtual int32_t runOnce();
};
extern EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin;
/**
* EnvironmentalMeasurementPluginRadio plugin for sending/receiving environmental measurements to/from the mesh
*/
class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin<EnvironmentalMeasurement>
{
public:
/** Constructor
* name is for debugging output
*/
EnvironmentalMeasurementPluginRadio() : ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) {
lastMeasurement.barometric_pressure = nanf("");
lastMeasurement.relative_humidity = nanf("");
lastMeasurement.temperature = nanf("");
lastSender = "N/A";
}
/**
* Send our EnvironmentalMeasurement into the mesh
*/
bool sendOurEnvironmentalMeasurement(NodeNum dest = NODENUM_BROADCAST, bool wantReplies = false);
virtual void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y);
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 EnvironmentalMeasurement *p);
virtual bool wantUIFrame();
private:
EnvironmentalMeasurement lastMeasurement;
String lastSender;
};
extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio;
float CelsiusToFarenheit(float c);
bool firstTime = 1;
DHT* dht;
const MeshPacket *lastMeasurementPacket;
uint32_t sensor_read_error_count = 0;
};

View File

@@ -133,7 +133,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
// DEBUG_MSG("Received text msg self=0x%0x, from=0x%0x, to=0x%0x, id=%d, msg=%.*s\n",
// nodeDB.getNodeNum(), mp.from, mp.to, mp.id, p.payload.size, p.payload.bytes);
if (mp.from != nodeDB.getNodeNum()) {
if (getFrom(&mp) != nodeDB.getNodeNum()) {
// DEBUG_MSG("* * Message came from the mesh\n");
// Serial2.println("* * Message came from the mesh");
@@ -144,7 +144,7 @@ bool RangeTestPluginRadio::handleReceived(const MeshPacket &mp)
*/
NodeInfo *n = nodeDB.getNode(mp.from);
NodeInfo *n = nodeDB.getNode(getFrom(&mp));
if (radioConfig.preferences.range_test_plugin_save) {
appendFile(mp);
@@ -209,7 +209,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
{
auto &p = mp.decoded;
NodeInfo *n = nodeDB.getNode(mp.from);
NodeInfo *n = nodeDB.getNode(getFrom(&mp));
/*
DEBUG_MSG("-----------------------------------------\n");
DEBUG_MSG("p.payload.bytes \"%s\"\n", p.payload.bytes);
@@ -290,7 +290,7 @@ bool RangeTestPluginRadio::appendFile(const MeshPacket &mp)
fileToAppend.printf("??:??:??,"); // Time
}
fileToAppend.printf("%d,", mp.from); // From
fileToAppend.printf("%d,", getFrom(&mp)); // From
fileToAppend.printf("%s,", n->user.long_name); // Long Name
fileToAppend.printf("%f,", n->position.latitude_i * 1e-7); // Sender Lat
fileToAppend.printf("%f,", n->position.longitude_i * 1e-7); // Sender Long

View File

@@ -240,12 +240,12 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
#ifndef NO_ESP32
if (radioConfig.preferences.store_forward_plugin_enabled) {
if (mp.from != nodeDB.getNodeNum()) {
if (getFrom(&mp) != nodeDB.getNodeNum()) {
// DEBUG_MSG("Store & Forward Plugin -- Print Start ---------- ---------- ---------- ---------- ----------\n\n\n");
// DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d", prefix, p->id, p->from & 0xff, p->to & 0xff,
// p->want_ack, p->hop_limit);
printPacket("----- PACKET FROM RADIO -----", &mp);
uint32_t sawTime = storeForwardPlugin->sawNode(mp.from & 0xffffffff);
uint32_t sawTime = storeForwardPlugin->sawNode(getFrom(&mp) & 0xffffffff);
DEBUG_MSG("We last saw this node (%u), %u sec ago\n", mp.from & 0xffffffff, (millis() - sawTime) / 1000);
if (mp.decoded.portnum == PortNum_UNKNOWN_APP) {
@@ -283,7 +283,7 @@ bool StoreForwardPluginRadio::handleReceived(const MeshPacket &mp)
if ((millis() - sawTime) > STOREFORWARD_SEND_HISTORY_SHORT) {
// Node has been away for a while.
storeForwardPlugin->historySend(sawTime, mp.from);
storeForwardPlugin->historySend(sawTime, getFrom(&mp));
}
}

View File

@@ -1,4 +1,4 @@
[VERSION]
major = 1
minor = 2
build = 1
build = 4