From 076251e6a8309e62e24b25a2a34a13d3efac19eb Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Wed, 3 Mar 2021 11:49:09 +0800 Subject: [PATCH 01/26] todo cleanup --- docs/software/TODO.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b47fdb95b..5942aa438 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -2,7 +2,7 @@ You probably don't care about this section - skip to the next one. -1.2 cleanup & multichannel support: +## 1.2 cleanup & multichannel support: * DONE call RouterPlugin for *all* packets - not just Router packets * DONE generate channel hash from the name of the channel+the psk (not just one or the other) @@ -44,8 +44,8 @@ You probably don't care about this section - skip to the next one. * 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) -* warn in python api if we are too new to talk to the device code -* 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 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" * DONE scrub protobufs to make sure they are absoloute minimum wiresize (in particular Data, ChannelSets and positions) * DONE change syncword (now ox2b) From 2af9e1431e6adeba112d30b60a37e809fd56d219 Mon Sep 17 00:00:00 2001 From: Charles Crossan Date: Sat, 27 Feb 2021 23:23:50 -0500 Subject: [PATCH 02/26] 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 --- proto | 2 +- src/mesh/generated/admin.pb.h | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/portnums.pb.h | 2 +- src/mesh/generated/radioconfig.pb.c | 1 + src/mesh/generated/radioconfig.pb.h | 27 ++++-- .../esp32/EnvironmentalMeasurementPlugin.cpp | 90 ++++++++++++++----- .../esp32/EnvironmentalMeasurementPlugin.h | 11 +-- 8 files changed, 99 insertions(+), 38 deletions(-) diff --git a/proto b/proto index 94bd0aae4..270cbdb68 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 94bd0aae44e2c16c7776289225c804100c856cd4 +Subproject commit 270cbdb6801761f054cb79f64b68b8a75cfb50f6 diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index f9be1cada..7c0ac9145 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -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" */ diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index a1e6de3af..dd3451849 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -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" */ diff --git a/src/mesh/generated/portnums.pb.h b/src/mesh/generated/portnums.pb.h index 758db47a6..5904a548c 100644 --- a/src/mesh/generated/portnums.pb.h +++ b/src/mesh/generated/portnums.pb.h @@ -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 diff --git a/src/mesh/generated/radioconfig.pb.c b/src/mesh/generated/radioconfig.pb.c index 85aa7aa18..716b804e8 100644 --- a/src/mesh/generated/radioconfig.pb.c +++ b/src/mesh/generated/radioconfig.pb.c @@ -17,3 +17,4 @@ PB_BIND(RadioConfig_UserPreferences, RadioConfig_UserPreferences, 2) + diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h index b8a6bfd7a..85bfa1a2d 100644 --- a/src/mesh/generated/radioconfig.pb.h +++ b/src/mesh/generated/radioconfig.pb.h @@ -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" */ diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index b332efd6e..40be3f9d3 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -53,7 +53,8 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { 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;*/ 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 @@ -96,6 +97,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( @@ -127,16 +129,6 @@ bool EnvironmentalMeasurementPluginRadio::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; @@ -149,7 +141,64 @@ 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 CelsiusToFarenheit(float c) { + return (c*9)/5 + 32; +} + + +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"); + 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"); + return; + } + + EnvironmentalMeasurement lastMeasurement; + + + uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket); + String lastSender = GetSenderName(*lastMeasurementPacket); + + auto &p = lastMeasurementPacket->decoded.data; + 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 EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) { const EnvironmentalMeasurement &p = *pptr; @@ -174,8 +223,8 @@ bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacke DEBUG_MSG("EnvironmentalMeasurement->relative_humidity: %f\n", p.relative_humidity); DEBUG_MSG("EnvironmentalMeasurement->temperature: %f\n", p.temperature); - lastMeasurement = p; - lastSender = sender; + lastMeasurementPacket = packetPool.allocCopy(mp); + return false; // Let others look at this message also if they want } @@ -184,20 +233,19 @@ bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNu 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 (!dht.read(true)){ sensor_read_error_count++; DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n"); return false; } + m.relative_humidity = dht.readHumidity(); + m.temperature = 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; diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index e29ea983e..4e43e46ce 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -27,11 +27,8 @@ class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin Date: Tue, 2 Mar 2021 21:12:22 -0500 Subject: [PATCH 03/26] 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 --- .../esp32/EnvironmentalMeasurementPlugin.cpp | 83 +++++++++---------- .../esp32/EnvironmentalMeasurementPlugin.h | 56 ++++--------- 2 files changed, 54 insertions(+), 85 deletions(-) diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 40be3f9d3..4ade032be 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -10,20 +10,10 @@ #include #include -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,12 +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 = 60; - radioConfig.preferences.environmental_measurement_plugin_display_farenheit = true;*/ + 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 @@ -63,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); @@ -112,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); @@ -125,7 +130,7 @@ int32_t EnvironmentalMeasurementPlugin::runOnce() { #endif } -bool EnvironmentalMeasurementPluginRadio::wantUIFrame() { +bool EnvironmentalMeasurementPlugin::wantUIFrame() { return radioConfig.preferences.environmental_measurement_plugin_screen_enabled; } @@ -154,12 +159,12 @@ uint32_t GetTimeSinceMeshPacket(const MeshPacket *mp) { } -float CelsiusToFarenheit(float c) { +float EnvironmentalMeasurementPlugin::CelsiusToFarenheit(float c) { return (c*9)/5 + 32; } -void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) +void EnvironmentalMeasurementPlugin::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) { display->setTextAlignment(TEXT_ALIGN_LEFT); display->setFont(FONT_MEDIUM); @@ -167,7 +172,7 @@ void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDi 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"); + //DEBUG_MSG("EnvironmentalMeasurement: No previous measurement; not drawing frame\n"); return; } @@ -177,7 +182,7 @@ void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDi uint32_t agoSecs = GetTimeSinceMeshPacket(lastMeasurementPacket); String lastSender = GetSenderName(*lastMeasurementPacket); - auto &p = lastMeasurementPacket->decoded.data; + auto &p = lastMeasurementPacket->decoded; if (!pb_decode_from_bytes(p.payload.bytes, p.payload.size, EnvironmentalMeasurement_fields, @@ -198,37 +203,25 @@ void EnvironmentalMeasurementPluginRadio::drawFrame(OLEDDisplay *display, OLEDDi } -bool EnvironmentalMeasurementPluginRadio::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement &p) +bool EnvironmentalMeasurementPlugin::handleReceivedProtobuf(const MeshPacket &mp, const EnvironmentalMeasurement *p) { - const EnvironmentalMeasurement &p = *pptr; - 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); 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; @@ -236,13 +229,13 @@ bool EnvironmentalMeasurementPluginRadio::sendOurEnvironmentalMeasurement(NodeNu DEBUG_MSG("-----------------------------------------\n"); DEBUG_MSG("EnvironmentalMeasurement: Read data\n"); - if (!dht.read(true)){ + if (!this->dht->read(true)){ sensor_read_error_count++; DEBUG_MSG("EnvironmentalMeasurement: FAILED TO READ DATA\n"); return false; } - m.relative_humidity = dht.readHumidity(); - m.temperature = dht.readTemperature(); + 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); diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h index 4e43e46ce..3123cc0f0 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.h +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.h @@ -3,56 +3,32 @@ #include "../mesh/generated/environmental_measurement.pb.h" #include #include +#include - -class EnvironmentalMeasurementPlugin : private concurrency::OSThread -{ - bool firstTime = 1; - - public: - EnvironmentalMeasurementPlugin(); - - protected: - virtual int32_t runOnce(); -}; - -extern EnvironmentalMeasurementPlugin *environmentalMeasurementPlugin; - -/** - * EnvironmentalMeasurementPluginRadio plugin for sending/receiving environmental measurements to/from the mesh - */ -class EnvironmentalMeasurementPluginRadio : public ProtobufPlugin +class EnvironmentalMeasurementPlugin : private concurrency::OSThread, public ProtobufPlugin { public: - /** Constructor - * name is for debugging output - */ - EnvironmentalMeasurementPluginRadio() : ProtobufPlugin("EnvironmentalMeasurement", PortNum_ENVIRONMENTAL_MEASUREMENT_APP, &EnvironmentalMeasurement_msg) { + 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(); /** * 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: - + float CelsiusToFarenheit(float c); + bool firstTime = 1; + DHT* dht; const MeshPacket *lastMeasurementPacket; - -}; - -extern EnvironmentalMeasurementPluginRadio *environmentalMeasurementPluginRadio; \ No newline at end of file + uint32_t sensor_read_error_count = 0; +}; \ No newline at end of file From 955d03acb1859ad9108f407cfabdb01841b45223 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Mar 2021 11:28:50 +0800 Subject: [PATCH 04/26] fix symbol conflict with new nrf52 libs --- src/mesh/NodeDB.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 29c35369f..b424adcba 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -154,7 +154,7 @@ extern NodeDB nodeDB; */ // Our delay functions check for this for times that should never expire -#define DELAY_FOREVER 0xffffffff +#define NODE_DELAY_FOREVER 0xffffffff #define IF_ROUTER(routerVal, normalVal) (radioConfig.preferences.is_router ? (routerVal) : (normalVal)) @@ -168,8 +168,8 @@ PREF_GET(position_broadcast_secs, IF_ROUTER(12 * 60 * 60, 15 * 60)) PREF_GET(wait_bluetooth_secs, IF_ROUTER(1, 60)) PREF_GET(screen_on_secs, 60) -PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60)) -PREF_GET(phone_sds_timeout_sec, IF_ROUTER(DELAY_FOREVER, 2 * 60 * 60)) +PREF_GET(mesh_sds_timeout_secs, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60)) +PREF_GET(phone_sds_timeout_sec, IF_ROUTER(NODE_DELAY_FOREVER, 2 * 60 * 60)) PREF_GET(sds_secs, 365 * 24 * 60 * 60) // We default to sleeping (with bluetooth off for 5 minutes at a time). This seems to be a good tradeoff between From 56fe211466cc2cd569512bc6a940cd7e5115a3a4 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Mar 2021 11:29:55 +0800 Subject: [PATCH 05/26] 1.2.1 --- docs/software/TODO.md | 7 +++++-- version.properties | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 5942aa438..5547110dd 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -29,10 +29,11 @@ You probably don't care about this section - skip to the next one. * DONE release protobufs * DONE release to developers * fix 1.1.50 android debug panel display -* add gui in android app for setting region +* warn in android app about unset regions +* 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 -* use set-channel from android * 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?) @@ -40,6 +41,8 @@ You probably don't care about this section - skip to the next one. * 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 +* 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) diff --git a/version.properties b/version.properties index c77424e6a..9d155e715 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 0 +build = 1 From 2f6034b06772f3292a951d1c2b18ecd9593d8241 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Thu, 4 Mar 2021 22:09:02 +0800 Subject: [PATCH 06/26] update todos --- docs/software/TODO.md | 31 +++++++++++++++++-------------- proto | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 5547110dd..b96deb3a0 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -21,32 +21,35 @@ 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 -* fix 1.1.50 android debug panel display -* warn in android app about unset regions -* 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 +* DONE fix setch-fast in python tool * 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 +* fix 1.1.50 android debug panel display +* 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 * 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" diff --git a/proto b/proto index 270cbdb68..ac4f53ed8 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 270cbdb6801761f054cb79f64b68b8a75cfb50f6 +Subproject commit ac4f53ed8c903a5bdf3d19727e96791d6be71022 From 950b32232f493d196b275fce40ea0a423d2d18b3 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 10:19:27 +0800 Subject: [PATCH 07/26] don't send messages the phone sent us back towards the phone --- docs/software/TODO.md | 6 +- src/graphics/Screen.cpp | 2 +- src/mesh/DSRRouter.cpp | 2 +- src/mesh/MeshPacketQueue.cpp | 2 +- src/mesh/MeshPlugin.cpp | 4 +- src/mesh/MeshService.cpp | 59 +++++++++++-------- src/mesh/MeshTypes.h | 8 ++- src/mesh/NodeDB.cpp | 10 +++- src/mesh/NodeDB.h | 1 + src/mesh/PacketHistory.cpp | 4 +- src/mesh/ReliableRouter.cpp | 10 ++-- src/mesh/ReliableRouter.h | 2 +- src/mesh/Router.cpp | 8 ++- src/plugins/ExternalNotificationPlugin.cpp | 2 +- src/plugins/NodeInfoPlugin.cpp | 2 +- src/plugins/PositionPlugin.cpp | 2 +- src/plugins/SerialPlugin.cpp | 2 +- .../esp32/EnvironmentalMeasurementPlugin.cpp | 5 +- src/plugins/esp32/RangeTestPlugin.cpp | 8 +-- src/plugins/esp32/StoreForwardPlugin.cpp | 6 +- 20 files changed, 87 insertions(+), 58 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index b96deb3a0..dfef04277 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -29,13 +29,14 @@ You probably don't care about this section - skip to the next one. * 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 * 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?) +* 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 * 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 * make python tests more exhaustive * pick default random admin key * exclude admin channels from URL? @@ -61,6 +62,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 diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index d04b9960b..6e52abdde 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -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); diff --git a/src/mesh/DSRRouter.cpp b/src/mesh/DSRRouter.cpp index 5fa6b1609..f7d8588e4 100644 --- a/src/mesh/DSRRouter.cpp +++ b/src/mesh/DSRRouter.cpp @@ -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) diff --git a/src/mesh/MeshPacketQueue.cpp b/src/mesh/MeshPacketQueue.cpp index 56db3feb3..6c964e509 100644 --- a/src/mesh/MeshPacketQueue.cpp +++ b/src/mesh/MeshPacketQueue.cpp @@ -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 */ diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 6fd3c72b8..34aaa2360 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -52,7 +52,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp) // 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)) { + if (mp.decoded.want_response && toUs && (getFrom(&mp) != ourNodeNum || mp.to == ourNodeNum)) { pi.sendResponse(mp); DEBUG_MSG("Plugin %s sent a response\n", pi.name); } @@ -94,7 +94,7 @@ void MeshPlugin::sendResponse(const MeshPacket &req) { */ 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->to = getFrom(&to); p->want_ack = to.want_ack; p->decoded.request_id = to.id; } diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 753d942df..f21742eaa 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -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,25 +65,29 @@ void MeshService::init() gpsObserver.observe(&gps->newStatus); } - int MeshService::handleFromRadio(const MeshPacket *mp) { powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping - printPacket("Forwarding to phone", mp); - nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio + if (mp->from != 0) { + printPacket("Forwarding to phone", mp); + nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio - fromNum++; + fromNum++; - if (toPhoneQueue.numFree() == 0) { - DEBUG_MSG("NOTE: tophone queue is full, discarding oldest\n"); - MeshPacket *d = toPhoneQueue.dequeuePtr(0); - if (d) - releaseToPool(d); + 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 + } + else { + DEBUG_MSG("Packet originally from phone, no need to send back that way...\n"); } - - MeshPacket *copied = packetPool.allocCopy(*mp); - assert(toPhoneQueue.enqueue(copied, 0)); // FIXME, instead of failing for full queue, delete the oldest mssages return 0; } @@ -128,8 +130,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 +157,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 +183,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 +217,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 diff --git a/src/mesh/MeshTypes.h b/src/mesh/MeshTypes.h index 06f2bf480..e7e6265a4 100644 --- a/src/mesh/MeshTypes.h +++ b/src/mesh/MeshTypes.h @@ -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 &packetPool; \ No newline at end of file +extern Allocator &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); \ No newline at end of file diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 22c1ccb6f..166e159f2 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -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 diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index b424adcba..e5f1b6564 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -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; + diff --git a/src/mesh/PacketHistory.cpp b/src/mesh/PacketHistory.cpp index 3d1884ace..19ce41bc8 100644 --- a/src/mesh/PacketHistory.cpp +++ b/src/mesh/PacketHistory.cpp @@ -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); diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index da743c389..80ee97701 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -26,15 +26,15 @@ ErrorCode ReliableRouter::send(MeshPacket *p) bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) { - if (p->to == NODENUM_BROADCAST && p->from == getNodeNum()) { + if (p->to == NODENUM_BROADCAST && getFrom(p) == 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); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -60,7 +60,7 @@ 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); + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } // If the payload is valid, look for ack/nak @@ -131,7 +131,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]; diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index e6a71f423..fefc85cb3 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -15,7 +15,7 @@ struct GlobalPacketId { GlobalPacketId(const MeshPacket *p) { - node = p->from; + node = getFrom(p); id = p->id; } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index a6afe952e..b4bb149dd 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -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 || @@ -273,7 +277,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); diff --git a/src/plugins/ExternalNotificationPlugin.cpp b/src/plugins/ExternalNotificationPlugin.cpp index 754259828..42865f3cc 100644 --- a/src/plugins/ExternalNotificationPlugin.cpp +++ b/src/plugins/ExternalNotificationPlugin.cpp @@ -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. diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 2524ffa58..82c16cbdc 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -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; diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index 251605865..b6f76ad72 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -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 } diff --git a/src/plugins/SerialPlugin.cpp b/src/plugins/SerialPlugin.cpp index 060f05ba1..c93bf8521 100644 --- a/src/plugins/SerialPlugin.cpp +++ b/src/plugins/SerialPlugin.cpp @@ -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 diff --git a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp index 4ade032be..69482dbc7 100644 --- a/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp +++ b/src/plugins/esp32/EnvironmentalMeasurementPlugin.cpp @@ -137,8 +137,9 @@ bool EnvironmentalMeasurementPlugin::wantUIFrame() { 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"; diff --git a/src/plugins/esp32/RangeTestPlugin.cpp b/src/plugins/esp32/RangeTestPlugin.cpp index 227deba4d..2332b687a 100644 --- a/src/plugins/esp32/RangeTestPlugin.cpp +++ b/src/plugins/esp32/RangeTestPlugin.cpp @@ -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 diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index d55e076bb..5340c48ae 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -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)); } } From 0c0c0babba9d415f481cb2b46a274158e9c447f0 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 11:44:45 +0800 Subject: [PATCH 08/26] combine acks works --- docs/software/TODO.md | 2 +- src/mesh/FloodingRouter.cpp | 2 +- src/mesh/MeshPlugin.cpp | 64 +++++++++++++++++++++-------------- src/mesh/MeshPlugin.h | 7 ++++ src/mesh/MeshService.cpp | 27 ++++++--------- src/mesh/PhoneAPI.cpp | 1 + src/mesh/ProtobufPlugin.h | 3 +- src/mesh/ReliableRouter.cpp | 38 ++++++++++++--------- src/mesh/Router.cpp | 1 + src/plugins/Plugins.cpp | 4 ++- src/plugins/RoutingPlugin.cpp | 5 +-- 11 files changed, 91 insertions(+), 63 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index dfef04277..622a95af3 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -31,7 +31,7 @@ You probably don't care about this section - skip to the next one. * 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 -* combine acks and responses in a single message if possible (do routing plugin LAST and drop ACK if someone else has already replied) +* 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 * DONE warn in android app about unset regions diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 049d038c7..491501e91 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -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 diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 34aaa2360..562f31c73 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -1,23 +1,28 @@ #include "MeshPlugin.h" -#include "NodeDB.h" #include "MeshService.h" +#include "NodeDB.h" #include std::vector *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(); 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 && (getFrom(&mp) != 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,39 @@ 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 = getFrom(&to); p->want_ack = to.want_ack; p->decoded.request_id = to.id; } -std::vector MeshPlugin::GetMeshPluginsWithUIFrames() { +std::vector MeshPlugin::GetMeshPluginsWithUIFrames() +{ - std::vector pluginsWithUIFrames; + std::vector 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; - } diff --git a/src/mesh/MeshPlugin.h b/src/mesh/MeshPlugin.h index 7220a198b..7234b6b0a 100644 --- a/src/mesh/MeshPlugin.h +++ b/src/mesh/MeshPlugin.h @@ -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 diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index f21742eaa..4dcc17859 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -69,26 +69,21 @@ int MeshService::handleFromRadio(const MeshPacket *mp) { powerFSM.trigger(EVENT_RECEIVED_PACKET); // Possibly keep the node from sleeping - if (mp->from != 0) { - printPacket("Forwarding to phone", mp); - nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio + printPacket("Forwarding to phone", mp); + nodeDB.updateFrom(*mp); // update our DB state based off sniffing every RX packet from the radio - fromNum++; + 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 - } - else { - DEBUG_MSG("Packet originally from phone, no need to send back that way...\n"); + 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 + return 0; } diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index a7797c255..5a7666b2d 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -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: { diff --git a/src/mesh/ProtobufPlugin.h b/src/mesh/ProtobufPlugin.h index c68885df2..30874b24b 100644 --- a/src/mesh/ProtobufPlugin.h +++ b/src/mesh/ProtobufPlugin.h @@ -58,11 +58,12 @@ template 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 diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index 80ee97701..eb22117fd 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -2,6 +2,7 @@ #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" +#include "MeshPlugin.h" // ReliableRouter::ReliableRouter() {} @@ -26,7 +27,8 @@ ErrorCode ReliableRouter::send(MeshPacket *p) bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) { - if (p->to == NODENUM_BROADCAST && getFrom(p) == getNodeNum()) { + // 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. @@ -34,7 +36,8 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // the original sending process. if (stopRetransmission(getFrom(p), p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - sendAckNak(Routing_Error_NONE, getFrom(p), 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, getFrom(p), 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); } } } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index b4bb149dd..17f6c50f2 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -231,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 { diff --git a/src/plugins/Plugins.cpp b/src/plugins/Plugins.cpp index 65f1f5f03..ca4cb52f4 100644 --- a/src/plugins/Plugins.cpp +++ b/src/plugins/Plugins.cpp @@ -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(); } \ No newline at end of file diff --git a/src/plugins/RoutingPlugin.cpp b/src/plugins/RoutingPlugin.cpp index 18427bdca..f6c2ea03a 100644 --- a/src/plugins/RoutingPlugin.cpp +++ b/src/plugins/RoutingPlugin.cpp @@ -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); } From 8739469db30139cbfffcebf5de6502ea337579e6 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 11:49:37 +0800 Subject: [PATCH 09/26] oops typo --- src/mesh/Router.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 17f6c50f2..87e8e4295 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -231,7 +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)); + 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 { From c9c44a934daad581541fc2dfbbedd340d8212013 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 12:37:26 +0800 Subject: [PATCH 10/26] don't generate acks for locally sourced msgs --- docs/software/TODO.md | 2 ++ src/mesh/MeshPlugin.cpp | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index 622a95af3..d256cd15d 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -34,6 +34,8 @@ You probably don't care about this section - skip to the next one. * 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 +* 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 diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index 562f31c73..e17cc5475 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -109,7 +109,11 @@ void setReplyTo(MeshPacket *p, const MeshPacket &to) { assert(p->which_payloadVariant == MeshPacket_decoded_tag); // Should already be set by now p->to = getFrom(&to); - p->want_ack = to.want_ack; + + // 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; } From 845dd1f9e36f7c01c2b2b8d6cde0c47dd1589b30 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Fri, 5 Mar 2021 12:39:39 +0800 Subject: [PATCH 11/26] 1.2.4 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 9d155e715..a374a8b7d 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 1 +build = 4 From badfaa8545f3108c9eb08733a85919de27637aaf Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 10:27:31 +0800 Subject: [PATCH 12/26] make error message clearer for packets that are too big --- src/mesh/mesh-pb-constants.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/mesh-pb-constants.cpp b/src/mesh/mesh-pb-constants.cpp index 337e585de..fac31872c 100644 --- a/src/mesh/mesh-pb-constants.cpp +++ b/src/mesh/mesh-pb-constants.cpp @@ -18,8 +18,8 @@ size_t pb_encode_to_bytes(uint8_t *destbuf, size_t destbufsize, const pb_msgdesc pb_ostream_t stream = pb_ostream_from_buffer(destbuf, destbufsize); if (!pb_encode(&stream, fields, src_struct)) { - DEBUG_MSG("Error: can't encode protobuf %s\n", PB_GET_ERROR(&stream)); - assert(0); // FIXME - panic + DEBUG_MSG("Panic: can't encode protobuf %s, did you make a field too large?\n", PB_GET_ERROR(&stream)); + assert(0); // If this asser fails it probably means you made a field too large for the max limits specified in mesh.options } else { return stream.bytes_written; } From d2d6b8e12ff4b9c71e27ec9e0761ab2fc9f4556e Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 10:27:48 +0800 Subject: [PATCH 13/26] fix log formatting --- src/mesh/PhoneAPI.cpp | 2 +- src/mesh/ReliableRouter.cpp | 4 ++-- src/plugins/TextMessagePlugin.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 5a7666b2d..c9ee13b9d 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -179,7 +179,7 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Do we have a message from the mesh? if (fromRadioScratch.which_payloadVariant != 0) { // Encapsulate as a FromRadio packet - DEBUG_MSG("encoding toPhone packet to phone variant=%d", fromRadioScratch.which_payloadVariant); + DEBUG_MSG("encoding toPhone packet to phone variant=%d\n", fromRadioScratch.which_payloadVariant); size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch); DEBUG_MSG(", %d bytes\n", numbytes); return numbytes; diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index eb22117fd..e3bd983d6 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -160,14 +160,14 @@ int32_t ReliableRouter::doRetransmissions() // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { - DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=%d\n", p.packet->from, p.packet->to, + DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, p.packet->id); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); } else { - DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=%d, tries left=%d\n", p.packet->from, p.packet->to, + DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, p.packet->id, p.numRetransmissions); // Note: we call the superclass version because we don't want to have our version of send() add a new diff --git a/src/plugins/TextMessagePlugin.cpp b/src/plugins/TextMessagePlugin.cpp index 8da2a10f9..b285363aa 100644 --- a/src/plugins/TextMessagePlugin.cpp +++ b/src/plugins/TextMessagePlugin.cpp @@ -8,7 +8,7 @@ TextMessagePlugin *textMessagePlugin; bool TextMessagePlugin::handleReceived(const MeshPacket &mp) { auto &p = mp.decoded; - DEBUG_MSG("Received text msg from=0x%0x, id=%d, msg=%.*s\n", mp.from, mp.id, p.payload.size, p.payload.bytes); + DEBUG_MSG("Received text msg from=0x%0x, id=0x%x, 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. From 2c29e8b179e3fff3ae6c8f3443ad63976363186d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 10:36:30 +0800 Subject: [PATCH 14/26] make nodeinfo & position plugins optional --- src/mesh/MeshService.cpp | 21 ++++++++++++++------- src/plugins/NodeInfoPlugin.cpp | 3 +-- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 4dcc17859..5590fa9cf 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -114,7 +114,8 @@ bool MeshService::reloadConfig() void MeshService::reloadOwner() { assert(nodeInfoPlugin); - nodeInfoPlugin->sendOurNodeInfo(); + if(nodeInfoPlugin) + nodeInfoPlugin->sendOurNodeInfo(); nodeDB.saveToDisk(); } @@ -170,12 +171,18 @@ void MeshService::sendNetworkPing(NodeNum dest, bool wantReplies) NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); assert(node); - DEBUG_MSG("Sending network ping to 0x%x, with position=%d, wantReplies=%d\n", dest, node->has_position, wantReplies); - assert(positionPlugin && nodeInfoPlugin); - if (node->has_position) - positionPlugin->sendOurPosition(dest, wantReplies); - else - nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies); + if (node->has_position) { + if(positionPlugin) { + DEBUG_MSG("Sending position ping to 0x%x, wantReplies=%d\n", dest, wantReplies); + positionPlugin->sendOurPosition(dest, wantReplies); + } + } + else { + if(nodeInfoPlugin) { + DEBUG_MSG("Sending nodeinfo ping to 0x%x, wantReplies=%d\n", dest, wantReplies); + nodeInfoPlugin->sendOurNodeInfo(dest, wantReplies); + } + } } NodeInfo *MeshService::refreshMyNodeInfo() diff --git a/src/plugins/NodeInfoPlugin.cpp b/src/plugins/NodeInfoPlugin.cpp index 82c16cbdc..f5f3ae194 100644 --- a/src/plugins/NodeInfoPlugin.cpp +++ b/src/plugins/NodeInfoPlugin.cpp @@ -65,8 +65,7 @@ int32_t NodeInfoPlugin::runOnce() currentGeneration = radioGeneration; DEBUG_MSG("Sending our nodeinfo to mesh (wantReplies=%d)\n", requestReplies); - assert(nodeInfoPlugin); - nodeInfoPlugin->sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) + sendOurNodeInfo(NODENUM_BROADCAST, requestReplies); // Send our info (don't request replies) return getPref_position_broadcast_secs() * 1000; } From c88b9732eb2b6245c1a1055bfc341f619ff62f4d Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 11:13:33 +0800 Subject: [PATCH 15/26] REALLY IMPORTANT: fix bug with retransmissions not happening --- src/mesh/RadioInterface.cpp | 14 +++++++++----- src/mesh/ReliableRouter.cpp | 32 ++++++++++++++++++++++++-------- src/mesh/ReliableRouter.h | 4 +--- src/mesh/Router.cpp | 5 +++++ src/mesh/Router.h | 5 +++++ 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 7b8aec605..966b900cc 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -1,16 +1,16 @@ +#include "configuration.h" #include "RadioInterface.h" #include "Channels.h" #include "MeshRadio.h" #include "MeshService.h" #include "NodeDB.h" #include "assert.h" -#include "configuration.h" +#include "Router.h" #include "sleep.h" #include #include #include -#include "Channels.h" #define RDEF(name, freq, spacing, num_ch, power_limit) \ { \ @@ -119,11 +119,11 @@ uint32_t RadioInterface::getTxDelayMsec() void printPacket(const char *prefix, const MeshPacket *p) { - DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, p->want_ack, - p->hop_limit, p->channel); + DEBUG_MSG("%s (id=0x%08x Fr0x%02x To0x%02x, WantAck%d, HopLim%d Ch0x%x", prefix, p->id, p->from & 0xff, p->to & 0xff, + p->want_ack, p->hop_limit, p->channel); if (p->which_payloadVariant == MeshPacket_decoded_tag) { auto &s = p->decoded; - + DEBUG_MSG(" Portnum=%d", s.portnum); if (s.want_response) @@ -332,6 +332,10 @@ void RadioInterface::deliverToReceiver(MeshPacket *p) { assert(rxDest); assert(rxDest->enqueue(p, 0)); // NOWAIT - fixme, if queue is full, delete older messages + + // Nasty hack because our threading is primitive. interfaces shouldn't need to know about routers FIXME + if (router) + router->setReceivedMessage(); } /*** diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index e3bd983d6..fd67bf3e5 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -1,8 +1,8 @@ #include "ReliableRouter.h" +#include "MeshPlugin.h" #include "MeshTypes.h" #include "configuration.h" #include "mesh-pb-constants.h" -#include "MeshPlugin.h" // ReliableRouter::ReliableRouter() {} @@ -36,7 +36,7 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // the original sending process. if (stopRetransmission(getFrom(p), p->id)) { DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - if(p->want_ack) + if (p->want_ack) sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -63,7 +63,7 @@ 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) { - if(MeshPlugin::currentReply) + 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); @@ -136,8 +136,9 @@ PendingPacket *ReliableRouter::startRetransmission(MeshPacket *p) auto id = GlobalPacketId(p); auto rec = PendingPacket(p); - setNextTx(&rec); stopRetransmission(getFrom(p), p->id); + + setNextTx(&rec); pending[id] = rec; return &pending[id]; @@ -157,6 +158,8 @@ int32_t ReliableRouter::doRetransmissions() ++nextIt; // we use this odd pattern because we might be deleting it... auto &p = it->second; + bool stillValid = true; // assume we'll keep this record around + // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { @@ -166,9 +169,10 @@ int32_t ReliableRouter::doRetransmissions() // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); + stillValid = false; // just deleted it } else { - DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, p.packet->to, - p.packet->id, p.numRetransmissions); + DEBUG_MSG("Sending reliable retransmission fr=0x%x,to=0x%x,id=0x%x, tries left=%d\n", p.packet->from, + p.packet->to, p.packet->id, p.numRetransmissions); // Note: we call the superclass version because we don't want to have our version of send() add a new // retransmission record @@ -178,8 +182,10 @@ int32_t ReliableRouter::doRetransmissions() --p.numRetransmissions; setNextTx(&p); } - } else { - // Not yet time + } + + if(stillValid) { + // Update our desired sleep delay int32_t t = p.nextTxMsec - now; d = min(t, d); @@ -187,4 +193,14 @@ int32_t ReliableRouter::doRetransmissions() } return d; +} + +void ReliableRouter::setNextTx(PendingPacket *pending) +{ + assert(iface); + auto d = iface->getRetransmissionMsec(pending->packet); + pending->nextTxMsec = millis() + d; + DEBUG_MSG("Setting next retransmission in %u msecs: ", d); + printPacket("", pending->packet); + setReceivedMessage(); // Run ASAP, so we can figure out our correct sleep time } \ No newline at end of file diff --git a/src/mesh/ReliableRouter.h b/src/mesh/ReliableRouter.h index fefc85cb3..db161b984 100644 --- a/src/mesh/ReliableRouter.h +++ b/src/mesh/ReliableRouter.h @@ -125,7 +125,5 @@ class ReliableRouter : public FloodingRouter */ int32_t doRetransmissions(); - void setNextTx(PendingPacket *pending) { - assert(iface); - pending->nextTxMsec = millis() + iface->getRetransmissionMsec(pending->packet); } + void setNextTx(PendingPacket *pending); }; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 87e8e4295..d08124b4a 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -115,12 +115,17 @@ void Router::abortSendAndNak(Routing_Error err, MeshPacket *p) packetPool.release(p); } +void Router::setReceivedMessage() { + setInterval(0); // Run ASAP, so we can figure out our correct sleep time +} + ErrorCode Router::sendLocal(MeshPacket *p) { // No need to deliver externally if the destination is the local node if (p->to == nodeDB.getNodeNum()) { printPacket("Enqueuing local", p); fromRadioQueue.enqueue(p); + setReceivedMessage(); return ERRNO_OK; } else if (!iface) { // We must be sending to remote nodes also, fail if no interface found diff --git a/src/mesh/Router.h b/src/mesh/Router.h index 6e6bf2c2a..6e217017b 100644 --- a/src/mesh/Router.h +++ b/src/mesh/Router.h @@ -63,6 +63,11 @@ class Router : protected concurrency::OSThread * @return our local nodenum */ NodeNum getNodeNum(); + /** Wake up the router thread ASAP, because we just queued a message for it. + * FIXME, this is kinda a hack because we don't have a nice way yet to say 'wake us because we are 'blocked on this queue' + */ + void setReceivedMessage(); + protected: friend class RoutingPlugin; From aa6b29a4b587fd0ebc8235cb7e3228240f494542 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 11:19:52 +0800 Subject: [PATCH 16/26] fix from address on naks --- src/mesh/ReliableRouter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index fd67bf3e5..cde08b5bb 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -163,9 +163,9 @@ int32_t ReliableRouter::doRetransmissions() // FIXME, handle 51 day rolloever here!!! if (p.nextTxMsec <= now) { if (p.numRetransmissions == 0) { - DEBUG_MSG("Reliable send failed, returning a nak fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, + DEBUG_MSG("Reliable send failed, returning a nak for fr=0x%x,to=0x%x,id=0x%x\n", p.packet->from, p.packet->to, p.packet->id); - sendAckNak(Routing_Error_MAX_RETRANSMIT, p.packet->from, p.packet->id); + sendAckNak(Routing_Error_MAX_RETRANSMIT, getFrom(p.packet), p.packet->id); // Note: we don't stop retransmission here, instead the Nak packet gets processed in sniffReceived - which // allows the DSR version to still be able to look at the PendingPacket stopRetransmission(it->first); From 49b1f4c5aff5d511272b0fa20da103fee51ff504 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 14:21:20 +0800 Subject: [PATCH 17/26] oops - fix failed text message rx --- docs/software/TODO.md | 4 ++-- src/esp32/ESP32CryptoEngine.cpp | 2 +- src/mesh/Channels.cpp | 3 ++- src/mesh/CryptoEngine.cpp | 4 ++++ src/mesh/Router.cpp | 42 +++++++++++++++++++++++---------- 5 files changed, 38 insertions(+), 17 deletions(-) diff --git a/docs/software/TODO.md b/docs/software/TODO.md index d256cd15d..26fb08851 100644 --- a/docs/software/TODO.md +++ b/docs/software/TODO.md @@ -34,8 +34,8 @@ You probably don't care about this section - skip to the next one. * 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 -* test android channel setting -* release to users +* DONE test android channel setting +* DONE 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 diff --git a/src/esp32/ESP32CryptoEngine.cpp b/src/esp32/ESP32CryptoEngine.cpp index 9d86ffeb0..f04614c72 100644 --- a/src/esp32/ESP32CryptoEngine.cpp +++ b/src/esp32/ESP32CryptoEngine.cpp @@ -54,7 +54,7 @@ class ESP32CryptoEngine : public CryptoEngine static uint8_t scratch[MAX_BLOCKSIZE]; size_t nc_off = 0; - // DEBUG_MSG("ESP32 encrypt!\n"); + // DEBUG_MSG("ESP32 crypt fr=%x, num=%x, numBytes=%d!\n", fromNode, (uint32_t) packetNum, numBytes); initNonce(fromNode, packetNum); assert(numBytes <= MAX_BLOCKSIZE); memcpy(scratch, bytes, numBytes); diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index 76ea3fb92..414930182 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -275,10 +275,11 @@ const char *Channels::getPrimaryName() bool Channels::decryptForHash(ChannelIndex chIndex, ChannelHash channelHash) { if(chIndex > getNumChannels() || getHash(chIndex) != channelHash) { - DEBUG_MSG("Skipping channel %d due to invalid hash/index\n", chIndex); + // DEBUG_MSG("Skipping channel %d (hash %x) due to invalid hash/index, want=%x\n", chIndex, getHash(chIndex), channelHash); return false; } else { + DEBUG_MSG("Using channel %d (hash 0x%x)\n", chIndex, channelHash); setCrypto(chIndex); return true; } diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index 74f4b7836..59cb7ad8f 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -4,6 +4,10 @@ void CryptoEngine::setKey(const CryptoKey &k) { DEBUG_MSG("Installing AES%d key!\n", k.length * 8); + /* for(uint8_t i = 0; i < k.length; i++) + DEBUG_MSG("%02x ", k.bytes[i]); + DEBUG_MSG("\n"); */ + key = k; } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index d08124b4a..8f566dffe 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -143,6 +143,13 @@ ErrorCode Router::sendLocal(MeshPacket *p) } } +void printBytes(const char *label, const uint8_t *p, size_t numbytes) { + DEBUG_MSG("%s: ", label); + for(size_t i = 0; i < numbytes; i++) + DEBUG_MSG("%02x ", p[i]); + DEBUG_MSG("\n"); +} + /** * Send a packet on a suitable interface. This routine will * later free() the packet to pool. This routine is not allowed to stall. @@ -173,6 +180,8 @@ ErrorCode Router::send(MeshPacket *p) if (p->which_payloadVariant == MeshPacket_decoded_tag) { static uint8_t bytes[MAX_RHPACKETLEN]; // we have to use a scratch buffer because a union + // printPacket("pre encrypt", p); // portnum valid here + size_t numbytes = pb_encode_to_bytes(bytes, sizeof(bytes), Data_fields, &p->decoded); if (numbytes > MAX_RHPACKETLEN) { @@ -180,6 +189,8 @@ ErrorCode Router::send(MeshPacket *p) return ERRNO_TOO_LARGE; } + //printBytes("plaintext", bytes, numbytes); + auto hash = channels.setActiveByIndex(p->channel); if (hash < 0) { // No suitable channel could be found for sending @@ -189,7 +200,7 @@ ErrorCode Router::send(MeshPacket *p) // Now that we are encrypting the packet channel should be the hash (no longer the index) p->channel = hash; - crypto->encrypt(p->from, p->id, numbytes, bytes); + crypto->encrypt(getFrom(p), p->id, numbytes, bytes); // Copy back into the packet and set the variant type memcpy(p->encrypted.bytes, bytes, numbytes); @@ -230,20 +241,26 @@ bool Router::perhapsDecode(MeshPacket *p) if (channels.decryptForHash(chIndex, p->channel)) { // Try to decrypt the packet if we can static uint8_t bytes[MAX_RHPACKETLEN]; + size_t rawSize = p->encrypted.size; + assert(rawSize <= sizeof(bytes)); memcpy(bytes, p->encrypted.bytes, - p->encrypted - .size); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf - crypto->decrypt(p->from, p->id, p->encrypted.size, bytes); + rawSize); // we have to copy into a scratch buffer, because these bytes are a union with the decoded protobuf + crypto->decrypt(p->from, p->id, rawSize, bytes); + + //printBytes("plaintext", bytes, p->encrypted.size); // 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 { + memset(&p->decoded, 0, sizeof(p->decoded)); + if (!pb_decode_from_bytes(bytes, rawSize, Data_fields, &p->decoded)) { + DEBUG_MSG("Invalid protobufs in received mesh packet (bad psk?)!\n"); + } else if(p->decoded.portnum == PortNum_UNKNOWN_APP) { + DEBUG_MSG("Invalid portnum (bad psk?)!\n"); + } + else { // parsing was successful + p->which_payloadVariant = MeshPacket_decoded_tag; // change type to decoded p->channel = chIndex; // change to store the index instead of the hash - // printPacket("decoded message", p); - p->which_payloadVariant = MeshPacket_decoded_tag; + printPacket("decoded message", p); return true; } } @@ -268,11 +285,10 @@ void Router::handleReceived(MeshPacket *p) p->rx_time = getValidTime(RTCQualityFromNet); // store the arrival timestamp for the phone // Take those raw bytes and convert them back into a well structured protobuf we can understand - bool decoded = perhapsDecode(p); - printPacket("handleReceived", p); - DEBUG_MSG("decoded=%d\n", decoded); + bool decoded = perhapsDecode(p); if (decoded) { // parsing was successful, queue for our recipient + printPacket("handleReceived", p); // call any promiscious plugins here, make a (non promisiocous) plugin for forwarding messages to phone api // sniffReceived(p); From 7a764efc10e5856663d92634f579f5da20128efe Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 14:30:53 +0800 Subject: [PATCH 18/26] 1.2.5 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a374a8b7d..d16382f27 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 4 +build = 5 From 96cfad4e579768c4fd3106c0d8a9cd3bb72704ea Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 14:52:26 +0800 Subject: [PATCH 19/26] less logspam --- src/mesh/PhoneAPI.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index c9ee13b9d..6e2ac479b 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -179,9 +179,8 @@ size_t PhoneAPI::getFromRadio(uint8_t *buf) // Do we have a message from the mesh? if (fromRadioScratch.which_payloadVariant != 0) { // Encapsulate as a FromRadio packet - DEBUG_MSG("encoding toPhone packet to phone variant=%d\n", fromRadioScratch.which_payloadVariant); size_t numbytes = pb_encode_to_bytes(buf, FromRadio_size, FromRadio_fields, &fromRadioScratch); - DEBUG_MSG(", %d bytes\n", numbytes); + // DEBUG_MSG("encoding toPhone packet to phone variant=%d, %d bytes\n", fromRadioScratch.which_payloadVariant, numbytes); return numbytes; } From 6f13966d1906927c14ff6100164fabc92d3c5e99 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 17:40:20 +0800 Subject: [PATCH 20/26] fix missing acks for broadcasts --- src/mesh/ReliableRouter.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mesh/ReliableRouter.cpp b/src/mesh/ReliableRouter.cpp index cde08b5bb..962aabeb7 100644 --- a/src/mesh/ReliableRouter.cpp +++ b/src/mesh/ReliableRouter.cpp @@ -35,9 +35,10 @@ bool ReliableRouter::shouldFilterReceived(const MeshPacket *p) // If this is the first time we saw this, cancel any retransmissions we have queued up and generate an internal ack for // the original sending process. if (stopRetransmission(getFrom(p), p->id)) { - DEBUG_MSG("Someone is retransmitting for us, generate implicit ack\n"); - if (p->want_ack) - sendAckNak(Routing_Error_NONE, getFrom(p), p->id); + DEBUG_MSG("generating implicit ack\n"); + // NOTE: we do NOT check p->wantAck here because p is the INCOMING rebroadcast and that packet is not expected to be + // marked as wantAck + sendAckNak(Routing_Error_NONE, getFrom(p), p->id); } } @@ -182,9 +183,9 @@ int32_t ReliableRouter::doRetransmissions() --p.numRetransmissions; setNextTx(&p); } - } + } - if(stillValid) { + if (stillValid) { // Update our desired sleep delay int32_t t = p.nextTxMsec - now; From ba9a94d026791ca4d75eddd0b87b38692a5b4319 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 18:00:20 +0800 Subject: [PATCH 21/26] fix is_low_power detection --- src/PowerFSM.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 85e08f536..9c145499d 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -181,7 +181,7 @@ void PowerFSM_setup() 1) If we're powered up and there's no battery, we must be getting power externally. 2) If we detect USB power from the power management chip, we must be getting power externally. */ - bool hasPower = (powerStatus && !powerStatus->getHasBattery()) || (!isLowPower && powerStatus && powerStatus->getHasUSB()); + bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB()); DEBUG_MSG("PowerFSM init, USB power=%d\n", hasPower); powerFSM.add_timed_transition(&stateBOOT, hasPower ? &statePOWER : &stateON, 3 * 1000, NULL, "boot timeout"); From 1f335069620b0155b537b98702bd52adde7c4582 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sat, 6 Mar 2021 21:10:36 +0800 Subject: [PATCH 22/26] Add RU region --- src/mesh/RadioInterface.cpp | 18 ++++++++++++++++++ src/mesh/generated/radioconfig.pb.h | 7 ++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 966b900cc..49dc69927 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -25,9 +25,27 @@ const RegionInfo regions[] = { RDEF(KR, 921.9f, 0.2f, 8, 0), // KR channel settings (KR920-923) Start from TTN download channel // freq. (921.9f is for download, others are for uplink) RDEF(TW, 923.0f, 0.2f, 10, 0), // TW channel settings (AS2 bandplan 923-925MHz) + RDEF(RU, 868.9f, 0.2f, 2, 20), // See notes below RDEF(Unset, 903.08f, 2.16f, 13, 0) // Assume US freqs if unset, Must be last }; +/* Notes about the RU bandplan (from @denis-d in https://meshtastic.discourse.group/t/russian-band-plan-proposal/2786/2): + +According to Annex 12 to GKRCh (National Radio Frequency Commission) decision № 18-46-03-1 (September 11th 2018) https://digital.gov.ru/uploaded/files/prilozhenie-12-k-reshenyu-gkrch-18-46-03-1.pdf 1 +We have 3 options for 868 MHz: + +864,0 - 865,0 MHz ERP 25mW, Duty Cycle 0.1% (3.6 sec in hour) or LBT (Listen Before Talk), prohibited in airports. +866,0 - 868,0 MHz ERP 25mW, Duty Cycle 1% or LBT, PSD (Power Spectrum Density) 1000mW/MHz, prohibited in airports +868,7 - 869,2 MHz ERP 100mW, Duty Cycle 10% or LBT, no resctrictions +and according to RP2-1.0.2 LoRaWAN® Regional Parameters RP2-1.0.2 LoRaWAN® Regional Parameters - LoRa Alliance® +I propose to use following meshtastic bandplan: +1 channel - central frequency 868.9MHz 125kHz band +Protective band - 75kHz +2 channel - central frequency 869.1MHz 125kHz band + +RDEF(RU, 868.9f, 0.2f, 2, 20) +*/ + const RegionInfo *myRegion; void initRegion() diff --git a/src/mesh/generated/radioconfig.pb.h b/src/mesh/generated/radioconfig.pb.h index 85bfa1a2d..9ea021f13 100644 --- a/src/mesh/generated/radioconfig.pb.h +++ b/src/mesh/generated/radioconfig.pb.h @@ -19,7 +19,8 @@ typedef enum _RegionCode { RegionCode_JP = 5, RegionCode_ANZ = 6, RegionCode_KR = 7, - RegionCode_TW = 8 + RegionCode_TW = 8, + RegionCode_RU = 9 } RegionCode; typedef enum _ChargeCurrent { @@ -123,8 +124,8 @@ typedef struct _RadioConfig { /* Helper constants for enums */ #define _RegionCode_MIN RegionCode_Unset -#define _RegionCode_MAX RegionCode_TW -#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_TW+1)) +#define _RegionCode_MAX RegionCode_RU +#define _RegionCode_ARRAYSIZE ((RegionCode)(RegionCode_RU+1)) #define _ChargeCurrent_MIN ChargeCurrent_MAUnset #define _ChargeCurrent_MAX ChargeCurrent_MA1320 From 64bc791e482b1d1dafc26c4fbf4f171294d7afca Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:34:29 +0800 Subject: [PATCH 23/26] fix docs --- src/PowerFSM.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 9c145499d..09fc35e6c 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -178,8 +178,9 @@ void PowerFSM_setup() bool isLowPower = radioConfig.preferences.is_low_power || isRouter; /* To determine if we're externally powered, assumptions - 1) If we're powered up and there's no battery, we must be getting power externally. - 2) If we detect USB power from the power management chip, we must be getting power externally. + 1) If we're powered up and there's no battery, we must be getting power externally. (because we'd be dead otherwise) + + 2) If we detect USB power from the power management chip, we must be getting power externally. */ bool hasPower = !isLowPower && powerStatus && (!powerStatus->getHasBattery() || powerStatus->getHasUSB()); From 12a7934ca108c2cfd4b886ee4c59cdf993b4c073 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:34:35 +0800 Subject: [PATCH 24/26] add RU --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index ac4f53ed8..7c025b9a4 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit ac4f53ed8c903a5bdf3d19727e96791d6be71022 +Subproject commit 7c025b9a4d54bb410ec17ee653122861b413f177 From d014ae0bffc9283c0b4de9196984c28eedd8e585 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:51:17 +0800 Subject: [PATCH 25/26] fix ls_sleeps communication to device clients --- src/plugins/AdminPlugin.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/AdminPlugin.cpp b/src/plugins/AdminPlugin.cpp index bba1b39a9..7e0a67074 100644 --- a/src/plugins/AdminPlugin.cpp +++ b/src/plugins/AdminPlugin.cpp @@ -24,6 +24,12 @@ void AdminPlugin::handleGetRadio(const MeshPacket &req) // We create the reply here AdminMessage r = AdminMessage_init_default; r.get_radio_response = devicestate.radio; + + // NOTE: The phone app needs to know the ls_secs value so it can properly expect sleep behavior. + // So even if we internally use 0 to represent 'use default' we still need to send the value we are + // using to the app (so that even old phone apps work with new device loads). + r.get_radio_response.preferences.ls_secs = getPref_ls_secs(); + r.which_variant = AdminMessage_get_radio_response_tag; reply = allocDataProtobuf(r); } From f320ecbde8503e86a069c2184ac90689d3696789 Mon Sep 17 00:00:00 2001 From: Kevin Hester Date: Sun, 7 Mar 2021 09:51:51 +0800 Subject: [PATCH 26/26] 1.2.6 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index d16382f27..d0634458c 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 5 +build = 6