From a2883789d1489343e720eb17d104501aa982d691 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 28 Dec 2021 23:29:30 -0800 Subject: [PATCH 01/34] updating proto submodule to latest --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index c52c8ef99..638783bad 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit c52c8ef99ead88a5edb73891b33247c54d37cb28 +Subproject commit 638783bad47d683a5bd67f8f53091c8905e4402d From f1c029d6dad9183584adc9791df8ed0650a361b7 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 28 Dec 2021 23:33:12 -0800 Subject: [PATCH 02/34] updating proto submodule to latest --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index 638783bad..ec35525ae 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 638783bad47d683a5bd67f8f53091c8905e4402d +Subproject commit ec35525ae6042999b2b3de368aff0ebc3fdcf308 From 10dc8233ea3150c0bac4364e09ca306addb10e10 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 28 Dec 2021 23:34:49 -0800 Subject: [PATCH 03/34] Initial checkin for Airtime Utilization https://github.com/meshtastic/Meshtastic-device/issues/1034 --- src/airtime.cpp | 73 +++++++++++++++++++++----------- src/airtime.h | 26 ++++++++---- src/graphics/Screen.cpp | 10 ++--- src/mesh/http/ContentHandler.cpp | 18 ++++---- 4 files changed, 79 insertions(+), 48 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 683b8f2c0..657f72689 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -1,17 +1,11 @@ -#include "configuration.h" #include "airtime.h" #include "NodeDB.h" +#include "configuration.h" #define periodsToLog 24 AirTime *airTime; -uint32_t secondsPerPeriod = 3600; -uint32_t lastMillis = 0; -uint32_t secSinceBoot = 0; - -// AirTime at; - // Don't read out of this directly. Use the helper functions. struct airtimeStruct { uint32_t periodTX[periodsToLog]; // AirTime transmitted @@ -36,14 +30,17 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms) } else { DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n"); } + + uint8_t channelUtilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS; + this->channelUtilization[channelUtilPeriod] = channelUtilization[channelUtilPeriod] + airtime_ms; } -uint8_t currentPeriodIndex() +uint8_t AirTime::currentPeriodIndex() { - return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog); + return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % periodsToLog); } -void airtimeRotatePeriod() +void AirTime::airtimeRotatePeriod() { if (airtimes.lastPeriodIndex != currentPeriodIndex()) { @@ -64,7 +61,6 @@ void airtimeRotatePeriod() myNodeInfo.air_period_tx[0] = 0; myNodeInfo.air_period_rx[0] = 0; - airtimes.lastPeriodIndex = currentPeriodIndex(); } } @@ -82,36 +78,63 @@ uint32_t *airtimeReport(reportTypes reportType) return 0; } -uint8_t getPeriodsToLog() +uint8_t AirTime::getPeriodsToLog() { return periodsToLog; } -uint32_t getSecondsPerPeriod() +uint32_t AirTime::getSecondsPerPeriod() { - return secondsPerPeriod; + return SECONDS_PER_PERIOD; } -uint32_t getSecondsSinceBoot() +uint32_t AirTime::getSecondsSinceBoot() { - return secSinceBoot; + return this->secSinceBoot; +} + +float AirTime::channelUtilizationPercent() +{ + uint32_t sum = 0; + for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) { + sum += this->channelUtilization[i]; + // DEBUG_MSG("ChanUtilArray %u %u\n", i, this->channelUtilization[i]); + } + + return (float(sum) / float(CHANNEL_UTILIZATION_PERIODS * 10 * 1000)) * 100; } AirTime::AirTime() : concurrency::OSThread("AirTime") {} int32_t AirTime::runOnce() { - //DEBUG_MSG("AirTime::runOnce()\n"); - - airtimeRotatePeriod(); secSinceBoot++; - /* - This actually doesn't need to be run once per second but we currently use it for the - secSinceBoot counter. + uint8_t utilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS; + + if (firstTime) { + // DEBUG_MSG("AirTime::runOnce()\n"); + + airtimeRotatePeriod(); + + for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) { + this->channelUtilization[i] = 0; + } + + firstTime = false; + lastUtilPeriod = utilPeriod; + + } else { + + // Reset the channelUtilization window when we roll over + if (lastUtilPeriod != utilPeriod) { + lastUtilPeriod = utilPeriod; + + this->channelUtilization[utilPeriod] = 0; + } + + DEBUG_MSG("Channel Utilization percent %3.1f\n", airTime->channelUtilizationPercent()); + } - If we have a better counter of how long the device has been online (and not millis()) - then we can change this to something less frequent. Maybe once ever 5 seconds? - */ return (1000 * 1); } \ No newline at end of file diff --git a/src/airtime.h b/src/airtime.h index 134bad47d..9c67759c3 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -23,21 +23,16 @@ RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel. */ + +#define CHANNEL_UTILIZATION_PERIODS 6 +#define SECONDS_PER_PERIOD 3600 + enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG }; void logAirtime(reportTypes reportType, uint32_t airtime_ms); -void airtimeRotatePeriod(); - -uint8_t currentPeriodIndex(); -uint8_t getPeriodsToLog(); - -uint32_t getSecondsSinceBoot(); - uint32_t *airtimeReport(reportTypes reportType); -uint32_t getSecondsPerPeriod(); - class AirTime : private concurrency::OSThread { @@ -45,6 +40,19 @@ class AirTime : private concurrency::OSThread AirTime(); void logAirtime(reportTypes reportType, uint32_t airtime_ms); + float channelUtilizationPercent(); + uint32_t channelUtilization[CHANNEL_UTILIZATION_PERIODS]; + + uint8_t currentPeriodIndex(); + void airtimeRotatePeriod(); + uint8_t getPeriodsToLog(); + uint32_t getSecondsPerPeriod(); + uint32_t getSecondsSinceBoot(); + + private: + bool firstTime = true; + uint8_t lastUtilPeriod = 0; + uint32_t secSinceBoot = 0; protected: virtual int32_t runOnce() override; diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 502c60b02..cdf5ab1a5 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1398,11 +1398,11 @@ void DebugInfo::drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *stat display->drawString(x, y + FONT_HEIGHT_SMALL * 1, uptime); -#ifndef NO_ESP32 - // Show CPU Frequency. - display->drawString(x + SCREEN_WIDTH - display->getStringWidth("CPU " + String(getCpuFrequencyMhz()) + "MHz"), - y + FONT_HEIGHT_SMALL * 1, "CPU " + String(getCpuFrequencyMhz()) + "MHz"); -#endif + // Display Channel Utilization + char chUtil[13]; + sprintf(chUtil, "ChUtil %2.0f%%", airTime->channelUtilizationPercent()); + display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), + y + FONT_HEIGHT_SMALL * 1, chUtil); // Line 3 if (radioConfig.preferences.gps_format != GpsCoordinateFormat_GpsFormatDMS) // if DMS then don't draw altitude diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 4174c0a23..b5ac29500 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -503,11 +503,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->print("\"tx_log\": ["); logArray = airtimeReport(TX_LOG); - for (int i = 0; i < getPeriodsToLog(); i++) { + for (int i = 0; i < airTime->getPeriodsToLog(); i++) { uint32_t tmp; tmp = *(logArray + i); res->printf("%d", tmp); - if (i != getPeriodsToLog() - 1) { + if (i != airTime->getPeriodsToLog() - 1) { res->print(", "); } } @@ -516,11 +516,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->print("\"rx_log\": ["); logArray = airtimeReport(RX_LOG); - for (int i = 0; i < getPeriodsToLog(); i++) { + for (int i = 0; i < airTime->getPeriodsToLog(); i++) { uint32_t tmp; tmp = *(logArray + i); res->printf("%d", tmp); - if (i != getPeriodsToLog() - 1) { + if (i != airTime->getPeriodsToLog() - 1) { res->print(", "); } } @@ -529,19 +529,19 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->print("\"rx_all_log\": ["); logArray = airtimeReport(RX_ALL_LOG); - for (int i = 0; i < getPeriodsToLog(); i++) { + for (int i = 0; i < airTime->getPeriodsToLog(); i++) { uint32_t tmp; tmp = *(logArray + i); res->printf("%d", tmp); - if (i != getPeriodsToLog() - 1) { + if (i != airTime->getPeriodsToLog() - 1) { res->print(", "); } } res->println("],"); - res->printf("\"seconds_since_boot\": %u,\n", getSecondsSinceBoot()); - res->printf("\"seconds_per_period\": %u,\n", getSecondsPerPeriod()); - res->printf("\"periods_to_log\": %u\n", getPeriodsToLog()); + res->printf("\"seconds_since_boot\": %u,\n", airTime->getSecondsSinceBoot()); + res->printf("\"seconds_per_period\": %u,\n", airTime->getSecondsPerPeriod()); + res->printf("\"periods_to_log\": %u\n", airTime->getPeriodsToLog()); res->println("},"); From 79e75a47f6e1c445061cdfa7209152498d6de32a Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Tue, 28 Dec 2021 23:37:23 -0800 Subject: [PATCH 04/34] Add channel utilization to myNodeInfo --- src/airtime.cpp | 5 ++++- src/mesh/generated/admin.pb.h | 2 +- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 13 ++++++++----- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 657f72689..62033d847 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -133,7 +133,10 @@ int32_t AirTime::runOnce() this->channelUtilization[utilPeriod] = 0; } - DEBUG_MSG("Channel Utilization percent %3.1f\n", airTime->channelUtilizationPercent()); + // Update channel_utilization every second. + myNodeInfo.channel_utilization = airTime->channelUtilizationPercent(); + + //DEBUG_MSG("Channel Utilization percent %3.1f\n", airTime->channelUtilizationPercent()); } return (1000 * 1); diff --git a/src/mesh/generated/admin.pb.h b/src/mesh/generated/admin.pb.h index 08c647aea..ebc6fc9a0 100644 --- a/src/mesh/generated/admin.pb.h +++ b/src/mesh/generated/admin.pb.h @@ -86,7 +86,7 @@ extern const pb_msgdesc_t AdminMessage_msg; #define AdminMessage_fields &AdminMessage_msg /* Maximum encoded size of messages (where known) */ -#define AdminMessage_size 461 +#define AdminMessage_size 529 #ifdef __cplusplus } /* extern "C" */ diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 2d4e53f0c..284aa68f7 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -125,7 +125,7 @@ extern const pb_msgdesc_t ChannelFile_msg; /* Maximum encoded size of messages (where known) */ #define LegacyRadioConfig_size 4 #define LegacyRadioConfig_LegacyPreferences_size 2 -#define DeviceState_size 9943 +#define DeviceState_size 9949 #define ChannelFile_size 832 #ifdef __cplusplus diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 8f4a7ffbc..7419ac023 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -164,6 +164,7 @@ typedef struct _MyNodeInfo { pb_size_t air_period_rx_count; uint32_t air_period_rx[24]; bool has_wifi; + float channel_utilization; } MyNodeInfo; typedef struct _Position { @@ -332,7 +333,7 @@ extern "C" { #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0} #define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} -#define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_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, 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 MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_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, 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 LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_default {0, 0, {MyNodeInfo_init_default}} #define ToRadio_init_default {0, {MeshPacket_init_default}} @@ -344,7 +345,7 @@ extern "C" { #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0} #define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} -#define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_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, 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 MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_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, 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 LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} #define FromRadio_init_zero {0, 0, {MyNodeInfo_init_zero}} #define ToRadio_init_zero {0, {MeshPacket_init_zero}} @@ -378,6 +379,7 @@ extern "C" { #define MyNodeInfo_air_period_tx_tag 16 #define MyNodeInfo_air_period_rx_tag 17 #define MyNodeInfo_has_wifi_tag 18 +#define MyNodeInfo_channel_utilization_tag 19 #define Position_latitude_i_tag 1 #define Position_longitude_i_tag 2 #define Position_altitude_tag 3 @@ -559,7 +561,8 @@ X(a, STATIC, SINGULAR, UINT32, min_app_version, 14) \ X(a, STATIC, SINGULAR, UINT32, max_channels, 15) \ X(a, STATIC, REPEATED, UINT32, air_period_tx, 16) \ X(a, STATIC, REPEATED, UINT32, air_period_rx, 17) \ -X(a, STATIC, SINGULAR, BOOL, has_wifi, 18) +X(a, STATIC, SINGULAR, BOOL, has_wifi, 18) \ +X(a, STATIC, SINGULAR, FLOAT, channel_utilization, 19) #define MyNodeInfo_CALLBACK NULL #define MyNodeInfo_DEFAULT NULL @@ -637,9 +640,9 @@ extern const pb_msgdesc_t ToRadio_PeerInfo_msg; #define Data_size 260 #define MeshPacket_size 311 #define NodeInfo_size 270 -#define MyNodeInfo_size 445 +#define MyNodeInfo_size 451 #define LogRecord_size 81 -#define FromRadio_size 454 +#define FromRadio_size 460 #define ToRadio_size 314 #define ToRadio_PeerInfo_size 8 From 672ea5b494f559e80d2015c65868820fe1979048 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 00:12:32 -0800 Subject: [PATCH 05/34] Removed radio config that shouldn't be there. --- src/plugins/PositionPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/PositionPlugin.cpp b/src/plugins/PositionPlugin.cpp index e10f05d1e..0a3a412d7 100644 --- a/src/plugins/PositionPlugin.cpp +++ b/src/plugins/PositionPlugin.cpp @@ -127,7 +127,7 @@ int32_t PositionPlugin::runOnce() { NodeInfo *node = nodeDB.getNode(nodeDB.getNodeNum()); - radioConfig.preferences.position_broadcast_smart = true; + //radioConfig.preferences.position_broadcast_smart = true; // We limit our GPS broadcasts to a max rate uint32_t now = millis(); From 37dec91ed9c1abf25310ced96a3345573a16f097 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 00:36:15 -0800 Subject: [PATCH 06/34] Rename periods to log --- src/airtime.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 62033d847..31947282c 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -2,15 +2,15 @@ #include "NodeDB.h" #include "configuration.h" -#define periodsToLog 24 +#define PERIODS_TO_LOG 24 AirTime *airTime; // Don't read out of this directly. Use the helper functions. struct airtimeStruct { - uint32_t periodTX[periodsToLog]; // AirTime transmitted - uint32_t periodRX[periodsToLog]; // AirTime received and repeated (Only valid mesh packets) - uint32_t periodRX_ALL[periodsToLog]; // AirTime received regardless of valid mesh packet. Could include noise. + uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted + uint32_t periodRX[PERIODS_TO_LOG]; // AirTime received and repeated (Only valid mesh packets) + uint32_t periodRX_ALL[PERIODS_TO_LOG]; // AirTime received regardless of valid mesh packet. Could include noise. uint8_t lastPeriodIndex; } airtimes; @@ -37,7 +37,7 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms) uint8_t AirTime::currentPeriodIndex() { - return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % periodsToLog); + return ((getSecondsSinceBoot() / SECONDS_PER_PERIOD) % PERIODS_TO_LOG); } void AirTime::airtimeRotatePeriod() @@ -46,7 +46,7 @@ void AirTime::airtimeRotatePeriod() if (airtimes.lastPeriodIndex != currentPeriodIndex()) { DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex()); - for (int i = periodsToLog - 2; i >= 0; --i) { + for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) { airtimes.periodTX[i + 1] = airtimes.periodTX[i]; airtimes.periodRX[i + 1] = airtimes.periodRX[i]; airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i]; @@ -80,7 +80,7 @@ uint32_t *airtimeReport(reportTypes reportType) uint8_t AirTime::getPeriodsToLog() { - return periodsToLog; + return PERIODS_TO_LOG; } uint32_t AirTime::getSecondsPerPeriod() @@ -113,8 +113,6 @@ int32_t AirTime::runOnce() uint8_t utilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS; if (firstTime) { - // DEBUG_MSG("AirTime::runOnce()\n"); - airtimeRotatePeriod(); for (uint32_t i = 0; i < CHANNEL_UTILIZATION_PERIODS; i++) { @@ -135,8 +133,6 @@ int32_t AirTime::runOnce() // Update channel_utilization every second. myNodeInfo.channel_utilization = airTime->channelUtilizationPercent(); - - //DEBUG_MSG("Channel Utilization percent %3.1f\n", airTime->channelUtilizationPercent()); } return (1000 * 1); From 7eb00dd5f67901b1a88ec90c889adec74e525476 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 00:36:54 -0800 Subject: [PATCH 07/34] Remove unknown report type --- src/airtime.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 31947282c..9dff7ad0b 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -27,8 +27,6 @@ void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms) } else if (reportType == RX_ALL_LOG) { DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms); airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms; - } else { - DEBUG_MSG("AirTime - Unknown report time. This should never happen!!\n"); } uint8_t channelUtilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS; From bdacd97feafced19a06cd29728ab9775b1790a6c Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 00:45:36 -0800 Subject: [PATCH 08/34] Move airtimes struct into the class --- src/airtime.cpp | 42 +++++++++++++++----------------- src/airtime.h | 10 ++++++++ src/mesh/http/ContentHandler.cpp | 6 ++--- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 9dff7ad0b..3f744d4ac 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -2,31 +2,28 @@ #include "NodeDB.h" #include "configuration.h" -#define PERIODS_TO_LOG 24 AirTime *airTime; // Don't read out of this directly. Use the helper functions. -struct airtimeStruct { - uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted - uint32_t periodRX[PERIODS_TO_LOG]; // AirTime received and repeated (Only valid mesh packets) - uint32_t periodRX_ALL[PERIODS_TO_LOG]; // AirTime received regardless of valid mesh packet. Could include noise. - uint8_t lastPeriodIndex; -} airtimes; + void AirTime::logAirtime(reportTypes reportType, uint32_t airtime_ms) { + + // TODO: Is the airtimes array still necessary? It's now in myNodeInfo anyway + if (reportType == TX_LOG) { DEBUG_MSG("AirTime - Packet transmitted : %ums\n", airtime_ms); - airtimes.periodTX[0] = airtimes.periodTX[0] + airtime_ms; + this->airtimes.periodTX[0] = this->airtimes.periodTX[0] + airtime_ms; myNodeInfo.air_period_tx[0] = myNodeInfo.air_period_tx[0] + airtime_ms; } else if (reportType == RX_LOG) { DEBUG_MSG("AirTime - Packet received : %ums\n", airtime_ms); - airtimes.periodRX[0] = airtimes.periodRX[0] + airtime_ms; + this->airtimes.periodRX[0] = this->airtimes.periodRX[0] + airtime_ms; myNodeInfo.air_period_rx[0] = myNodeInfo.air_period_rx[0] + airtime_ms; } else if (reportType == RX_ALL_LOG) { DEBUG_MSG("AirTime - Packet received (noise?) : %ums\n", airtime_ms); - airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + airtime_ms; + this->airtimes.periodRX_ALL[0] = this->airtimes.periodRX_ALL[0] + airtime_ms; } uint8_t channelUtilPeriod = (getSecondsSinceBoot() / 10) % CHANNEL_UTILIZATION_PERIODS; @@ -41,37 +38,38 @@ uint8_t AirTime::currentPeriodIndex() void AirTime::airtimeRotatePeriod() { - if (airtimes.lastPeriodIndex != currentPeriodIndex()) { + if (this->airtimes.lastPeriodIndex != currentPeriodIndex()) { DEBUG_MSG("Rotating airtimes to a new period = %u\n", currentPeriodIndex()); for (int i = PERIODS_TO_LOG - 2; i >= 0; --i) { - airtimes.periodTX[i + 1] = airtimes.periodTX[i]; - airtimes.periodRX[i + 1] = airtimes.periodRX[i]; - airtimes.periodRX_ALL[i + 1] = airtimes.periodRX_ALL[i]; + this->airtimes.periodTX[i + 1] = this->airtimes.periodTX[i]; + this->airtimes.periodRX[i + 1] = this->airtimes.periodRX[i]; + this->airtimes.periodRX_ALL[i + 1] = this->airtimes.periodRX_ALL[i]; myNodeInfo.air_period_tx[i + 1] = myNodeInfo.air_period_tx[i]; myNodeInfo.air_period_rx[i + 1] = myNodeInfo.air_period_rx[i]; } - airtimes.periodTX[0] = 0; - airtimes.periodRX[0] = 0; - airtimes.periodRX_ALL[0] = 0; + + this->airtimes.periodTX[0] = 0; + this->airtimes.periodRX[0] = 0; + this->airtimes.periodRX_ALL[0] = 0; myNodeInfo.air_period_tx[0] = 0; myNodeInfo.air_period_rx[0] = 0; - airtimes.lastPeriodIndex = currentPeriodIndex(); + this->airtimes.lastPeriodIndex = currentPeriodIndex(); } } -uint32_t *airtimeReport(reportTypes reportType) +uint32_t *AirTime::airtimeReport(reportTypes reportType) { if (reportType == TX_LOG) { - return airtimes.periodTX; + return this->airtimes.periodTX; } else if (reportType == RX_LOG) { - return airtimes.periodRX; + return this->airtimes.periodRX; } else if (reportType == RX_ALL_LOG) { - return airtimes.periodRX_ALL; + return this->airtimes.periodRX_ALL; } return 0; } diff --git a/src/airtime.h b/src/airtime.h index 9c67759c3..bf78ac3a9 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -26,6 +26,8 @@ #define CHANNEL_UTILIZATION_PERIODS 6 #define SECONDS_PER_PERIOD 3600 +#define PERIODS_TO_LOG 24 + enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG }; @@ -48,12 +50,20 @@ class AirTime : private concurrency::OSThread uint8_t getPeriodsToLog(); uint32_t getSecondsPerPeriod(); uint32_t getSecondsSinceBoot(); + uint32_t *airtimeReport(reportTypes reportType); private: bool firstTime = true; uint8_t lastUtilPeriod = 0; uint32_t secSinceBoot = 0; + struct airtimeStruct { + uint32_t periodTX[PERIODS_TO_LOG]; // AirTime transmitted + uint32_t periodRX[PERIODS_TO_LOG]; // AirTime received and repeated (Only valid mesh packets) + uint32_t periodRX_ALL[PERIODS_TO_LOG]; // AirTime received regardless of valid mesh packet. Could include noise. + uint8_t lastPeriodIndex; + } airtimes; + protected: virtual int32_t runOnce() override; }; diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index b5ac29500..c1fced6de 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -502,7 +502,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->print("\"tx_log\": ["); - logArray = airtimeReport(TX_LOG); + logArray = airTime->airtimeReport(TX_LOG); for (int i = 0; i < airTime->getPeriodsToLog(); i++) { uint32_t tmp; tmp = *(logArray + i); @@ -515,7 +515,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->println("],"); res->print("\"rx_log\": ["); - logArray = airtimeReport(RX_LOG); + logArray = airTime->airtimeReport(RX_LOG); for (int i = 0; i < airTime->getPeriodsToLog(); i++) { uint32_t tmp; tmp = *(logArray + i); @@ -528,7 +528,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->println("],"); res->print("\"rx_all_log\": ["); - logArray = airtimeReport(RX_ALL_LOG); + logArray = airTime->airtimeReport(RX_ALL_LOG); for (int i = 0; i < airTime->getPeriodsToLog(); i++) { uint32_t tmp; tmp = *(logArray + i); From 6f3ffc6ef075fa94ca6cec288e3d91a0789c56a3 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 00:52:21 -0800 Subject: [PATCH 09/34] Delete build-nightly.sh Nightly build server has been decomissioned. --- bin/build-nightly.sh | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100755 bin/build-nightly.sh diff --git a/bin/build-nightly.sh b/bin/build-nightly.sh deleted file mode 100755 index de31c6ed1..000000000 --- a/bin/build-nightly.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash -source ~/.bashrc - -# Meshtastic Nightly Build Script. -# McHamster (jm@casler.org) -# -# This is the script that is used for the nightly build server. -# -# It's probably not useful for most people, but you may want to run your own -# nightly builds. -# -# The last line of ~/.bashrc contains an inclusion of platformio in the path. -# Without this, the build script won't run from the crontab: -# -# export PATH="$HOME/.platformio/penv/bin:$PATH" -# -# The crontab contains: -# 0 2 * * * cd ~/meshtastic/github/meshtastic && source "~/.bashrc"; ./build-nightly.sh > ~/cronout.txt 2> ~/cronout.txt - -cd Meshtastic-device - -git pull - -bin/build-all.sh - -date_stamp=$(date +'%Y-%m-%d') - -cd .. - -# TODO: Archive the same binaries used by the build-all script. -#zip -r meshtastic_device_nightly_${date_stamp} Meshtastic-device/release/latest/bins -cp Meshtastic-device/release/archive/`ls -t ./Meshtastic-device/release/archive/| head -1` meshtastic_device_nightly_${date_stamp}.zip - -# Copy the file to the webserver -scp meshtastic_device_nightly_${date_stamp}.zip jm@10.11.12.20:/volume1/web/meshtastic/nightly_builds/ - -# Delete the local copy -rm meshtastic_device_nightly_${date_stamp}.zip From 68c52a8d368670226ebebd7263927db3c0d9d2a8 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 09:22:47 -0800 Subject: [PATCH 10/34] updating proto submodule to latest --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index ec35525ae..1d3b4806a 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit ec35525ae6042999b2b3de368aff0ebc3fdcf308 +Subproject commit 1d3b4806ab5dc4b8ab62063dbb5799ab900464e6 From 7c6d53f297a3d38b5c37f39815c5397102da4de3 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 09:25:01 -0800 Subject: [PATCH 11/34] Support for replies and tap backs https://github.com/meshtastic/Meshtastic-device/issues/1035 --- src/mesh/generated/deviceonly.pb.h | 2 +- src/mesh/generated/mesh.pb.h | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/mesh/generated/deviceonly.pb.h b/src/mesh/generated/deviceonly.pb.h index 284aa68f7..34338b9c4 100644 --- a/src/mesh/generated/deviceonly.pb.h +++ b/src/mesh/generated/deviceonly.pb.h @@ -125,7 +125,7 @@ extern const pb_msgdesc_t ChannelFile_msg; /* Maximum encoded size of messages (where known) */ #define LegacyRadioConfig_size 4 #define LegacyRadioConfig_LegacyPreferences_size 2 -#define DeviceState_size 9949 +#define DeviceState_size 9967 #define ChannelFile_size 832 #ifdef __cplusplus diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 7419ac023..27e7d53cd 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -234,6 +234,8 @@ typedef struct _MeshPacket { MeshPacket_Priority priority; int32_t rx_rssi; MeshPacket_Delayed delayed; + uint32_t reply_id; + bool is_tapback; } MeshPacket; typedef struct _NodeInfo { @@ -331,7 +333,7 @@ extern "C" { #define RouteDiscovery_init_default {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_default {0, {RouteDiscovery_init_default}} #define Data_init_default {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0} -#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} +#define MeshPacket_init_default {0, 0, 0, 0, {Data_init_default}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN, 0, 0} #define NodeInfo_init_default {0, false, User_init_default, false, Position_init_default, 0, 0} #define MyNodeInfo_init_default {0, 0, 0, "", "", "", _CriticalErrorCode_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, 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 LogRecord_init_default {"", 0, "", _LogRecord_Level_MIN} @@ -343,7 +345,7 @@ extern "C" { #define RouteDiscovery_init_zero {0, {0, 0, 0, 0, 0, 0, 0, 0}} #define Routing_init_zero {0, {RouteDiscovery_init_zero}} #define Data_init_zero {_PortNum_MIN, {0, {0}}, 0, 0, 0, 0} -#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN} +#define MeshPacket_init_zero {0, 0, 0, 0, {Data_init_zero}, 0, 0, 0, 0, 0, _MeshPacket_Priority_MIN, 0, _MeshPacket_Delayed_MIN, 0, 0} #define NodeInfo_init_zero {0, false, User_init_zero, false, Position_init_zero, 0, 0} #define MyNodeInfo_init_zero {0, 0, 0, "", "", "", _CriticalErrorCode_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, 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 LogRecord_init_zero {"", 0, "", _LogRecord_Level_MIN} @@ -429,6 +431,8 @@ extern "C" { #define MeshPacket_priority_tag 12 #define MeshPacket_rx_rssi_tag 13 #define MeshPacket_delayed_tag 15 +#define MeshPacket_reply_id_tag 16 +#define MeshPacket_is_tapback_tag 17 #define NodeInfo_num_tag 1 #define NodeInfo_user_tag 2 #define NodeInfo_position_tag 3 @@ -528,7 +532,9 @@ X(a, STATIC, SINGULAR, UINT32, hop_limit, 10) \ X(a, STATIC, SINGULAR, BOOL, want_ack, 11) \ X(a, STATIC, SINGULAR, UENUM, priority, 12) \ X(a, STATIC, SINGULAR, INT32, rx_rssi, 13) \ -X(a, STATIC, SINGULAR, UENUM, delayed, 15) +X(a, STATIC, SINGULAR, UENUM, delayed, 15) \ +X(a, STATIC, SINGULAR, FIXED32, reply_id, 16) \ +X(a, STATIC, SINGULAR, BOOL, is_tapback, 17) #define MeshPacket_CALLBACK NULL #define MeshPacket_DEFAULT NULL #define MeshPacket_payloadVariant_decoded_MSGTYPE Data @@ -638,12 +644,12 @@ extern const pb_msgdesc_t ToRadio_PeerInfo_msg; #define RouteDiscovery_size 40 #define Routing_size 42 #define Data_size 260 -#define MeshPacket_size 311 +#define MeshPacket_size 320 #define NodeInfo_size 270 #define MyNodeInfo_size 451 #define LogRecord_size 81 #define FromRadio_size 460 -#define ToRadio_size 314 +#define ToRadio_size 323 #define ToRadio_PeerInfo_size 8 #ifdef __cplusplus From 41dcfdd7cb4a3bac6808b6511fac9a529befe4a8 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Wed, 29 Dec 2021 11:20:36 -0800 Subject: [PATCH 12/34] Bump to 1.2.50 --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 13eff275e..7c9e94a60 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 1 minor = 2 -build = 49 +build = 50 From c531ea86014a7e88cdf0f0bdcca6a56f8e855ebb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 30 Dec 2021 22:16:46 +0100 Subject: [PATCH 13/34] new Configuration section --- src/configuration.h | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/configuration.h b/src/configuration.h index 597f60094..473a92114 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -323,6 +323,41 @@ along with this program. If not, see . #endif +#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) + +// the default ESP32 Pin of 15 is the Oled SCL, set to 36 and 37 and works fine. +// Tested on Neo6m module. +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 36 +#define GPS_TX_PIN 37 + +#ifndef USE_JTAG // gpio15 is TDO for JTAG, so no I2C on this board while doing jtag +#define I2C_SDA 4 // I2C pins for this board +#define I2C_SCL 15 +#endif + +#define RESET_OLED 16 // If defined, this pin will be used to reset the display controller + +#define LED_PIN 25 // If defined we will blink this LED +#define BUTTON_PIN 0 // If defined, this will be used for user button presses + +#define USE_RF95 +#define LORA_DIO0 26 // a No connect on the SX1262 module +#ifndef USE_JTAG +#define LORA_RESET 14 +#endif +#define LORA_DIO1 33 // Not really used +#define LORA_DIO2 32 // Not really used + +// ratio of voltage divider = 3.20 (R1=100k, R2=220k) +#define ADC_MULTIPLIER 3.2 + +// This string must exactly match the case used in release file names or the android updater won't work +#define HW_VENDOR HardwareModel_HELTEC_V1 + +#define BATTERY_PIN 13 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage + #elif defined(TLORA_V1) // This string must exactly match the case used in release file names or the android updater won't work #define HW_VENDOR HardwareModel_TLORA_V1 From 9c7121df3e9f05e97ec0e2607ef26ce810574ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 30 Dec 2021 22:18:08 +0100 Subject: [PATCH 14/34] Update platformio.ini add new board to platform.io definition --- platformio.ini | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platformio.ini b/platformio.ini index 1d35ddeb9..9c301ea33 100644 --- a/platformio.ini +++ b/platformio.ini @@ -12,6 +12,7 @@ default_envs = tbeam ;default_envs = tbeam0.7 ;default_envs = heltec-v2.0 +;default_envs = heltec-v1 ;default_envs = tlora-v1 ;default_envs = tlora_v1_3 ;default_envs = tlora-v2 @@ -158,6 +159,13 @@ board = ttgo-t-beam build_flags = ${esp32_base.build_flags} -D TBEAM_V07 +[env:heltec-v1] +;build_type = debug ; to make it possible to step through our jtag debugger +extends = esp32_base +board = heltec_wifi_lora_32 +build_flags = + ${esp32_base.build_flags} -D HELTEC_V1 + [env:heltec-v2.0] ;build_type = debug ; to make it possible to step through our jtag debugger extends = esp32_base From e24a2116d836c0dd2c5fdb9d0ac6ae139072c2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 30 Dec 2021 22:19:04 +0100 Subject: [PATCH 15/34] build the new board with build_all --- bin/build-all.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/build-all.sh b/bin/build-all.sh index 922fd4b7d..1cf83c62f 100755 --- a/bin/build-all.sh +++ b/bin/build-all.sh @@ -5,7 +5,7 @@ set -e VERSION=`bin/buildinfo.py long` SHORT_VERSION=`bin/buildinfo.py short` -BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1" +BOARDS_ESP32="tlora-v2 tlora-v1 tlora_v1_3 tlora-v2-1-1.6 tbeam heltec-v1 heltec-v2.0 heltec-v2.1 tbeam0.7 meshtastic-diy-v1" #BOARDS_ESP32=tbeam # FIXME note nrf52840dk build is for some reason only generating a BIN file but not a HEX file nrf52840dk-geeksville is fine From 20497335c27983a78cf3e829ce2452e3df88879a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Thu, 30 Dec 2021 22:20:15 +0100 Subject: [PATCH 16/34] stop old chip from crashing --- src/sleep.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sleep.cpp b/src/sleep.cpp index 558dbf1d4..998645dcd 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -65,7 +65,11 @@ void setCPUFast(bool on) return; } - setCpuFrequencyMhz(on ? 240 : 80); + // The Heltec LORA32 V1 runs at 26 MHz base frequency and doesn't react well to switching to 80 MHz... + #ifndef ARDUINO_HELTEC_WIFI_LORA_32 + setCpuFrequencyMhz(on ? 240 : 80); + #endif + #endif } From a16dcbe9d0256f7681f233ab09d36f4b8dbfd9b5 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Thu, 30 Dec 2021 14:24:44 -0800 Subject: [PATCH 17/34] Don't let S&F send payloads if channel utilization is > 50% --- src/plugins/esp32/StoreForwardPlugin.cpp | 30 ++++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 10dedda41..4b8152a08 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -3,6 +3,7 @@ #include "NodeDB.h" #include "RTC.h" #include "Router.h" +#include "airtime.h" #include "configuration.h" #include "mesh-pb-constants.h" #include "mesh/generated/storeforward.pb.h" @@ -22,20 +23,29 @@ int32_t StoreForwardPlugin::runOnce() if (radioConfig.preferences.is_router) { + // Send out the message queue. if (this->busy) { - // Send out the message queue. + - // DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index); - storeForwardPlugin->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); + // Only send packets if the channel is less than 50% utilized. + if (airTime->channelUtilizationPercent() < 50) { - if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) { - strcpy(this->routerMessage, "** S&F - Done"); - storeForwardPlugin->sendMessage(this->busyTo, this->routerMessage); - // DEBUG_MSG("--- --- --- In busy loop - Done \n"); - this->packetHistoryTXQueue_index = 0; - this->busy = false; + // DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index); + storeForwardPlugin->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); + + if (this->packetHistoryTXQueue_index == packetHistoryTXQueue_size) { + strcpy(this->routerMessage, "** S&F - Done"); + storeForwardPlugin->sendMessage(this->busyTo, this->routerMessage); + + // DEBUG_MSG("--- --- --- In busy loop - Done \n"); + this->packetHistoryTXQueue_index = 0; + this->busy = false; + } else { + this->packetHistoryTXQueue_index++; + } + } else { - this->packetHistoryTXQueue_index++; + DEBUG_MSG("Channel utilization is too high. Skipping this oppurtunity to send and will retry later.\n"); } } DEBUG_MSG("SF myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate); From 8bbdfe45387246b20e2de0b815d2c0bc2368dd69 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Thu, 30 Dec 2021 15:01:19 -0800 Subject: [PATCH 18/34] Fix typo --- src/plugins/esp32/StoreForwardPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index 4b8152a08..f8194563e 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -45,7 +45,7 @@ int32_t StoreForwardPlugin::runOnce() } } else { - DEBUG_MSG("Channel utilization is too high. Skipping this oppurtunity to send and will retry later.\n"); + DEBUG_MSG("Channel utilization is too high. Skipping this opportunity to send and will retry later.\n"); } } DEBUG_MSG("SF myNodeInfo.bitrate = %f bytes / sec\n", myNodeInfo.bitrate); From 6cb4900e0c0af1bebaca80a81aec913d71986646 Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Fri, 31 Dec 2021 13:00:32 +1100 Subject: [PATCH 19/34] Create update_protobufs.yml --- .github/workflows/update_protobufs.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/update_protobufs.yml diff --git a/.github/workflows/update_protobufs.yml b/.github/workflows/update_protobufs.yml new file mode 100644 index 000000000..f84ad98a8 --- /dev/null +++ b/.github/workflows/update_protobufs.yml @@ -0,0 +1,24 @@ +name: "Update protobufs" +on: workflow_dispatch + +jobs: + update-protobufs: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + submodules: true + + - name: Update Submodule + run: | + git pull --recurse-submodules + git submodule update --remote --recursive + - name: Commit update + run: | + git config --global user.name 'github-actions' + git config --global user.email 'bot@noreply.github.com' + git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }} + git add proto + git commit -m "Update protobuf submodule" && git push || echo "No changes to commit" From df75182bcf2cb7ac3e754f98fa8ff9191bfdb894 Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Fri, 31 Dec 2021 13:04:34 +1100 Subject: [PATCH 20/34] Fix protobuf submodule --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index 1d3b4806a..4a64080d1 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 1d3b4806ab5dc4b8ab62063dbb5799ab900464e6 +Subproject commit 4a64080d160f9219768a4126414d41dc82a3d63c From c8aec324f527ec2367c091657f442a613bec3d50 Mon Sep 17 00:00:00 2001 From: Balazs Kelemen Date: Sat, 1 Jan 2022 11:33:17 +0100 Subject: [PATCH 21/34] Channel-binding filter accepts empty channel names. --- src/mesh/MeshPlugin.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/mesh/MeshPlugin.cpp b/src/mesh/MeshPlugin.cpp index f801682d1..85988ec7b 100644 --- a/src/mesh/MeshPlugin.cpp +++ b/src/mesh/MeshPlugin.cpp @@ -96,7 +96,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src) assert(!pi.myReply); // If it is !null it means we have a bug, because it should have been sent the previous time if (wantsPacket) { - DEBUG_MSG("Plugin %s wantsPacket=%d\n", pi.name, wantsPacket); + DEBUG_MSG("Plugin '%s' wantsPacket=%d\n", pi.name, wantsPacket); pluginFound = true; @@ -109,7 +109,10 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src) /// Also: if a packet comes in on the local PC interface, we don't check for bound channels, because it is TRUSTED and it needs to /// to be able to fetch the initial admin packets without yet knowing any channels. - bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || (ch && (strcmp(ch->settings.name, pi.boundChannel) == 0)); + bool rxChannelOk = !pi.boundChannel || (mp.from == 0) || + !ch || + strlen(ch->settings.name) > 0 || + strcmp(ch->settings.name, pi.boundChannel); if (!rxChannelOk) { // no one should have already replied! @@ -134,9 +137,9 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src) // 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); + DEBUG_MSG("Plugin '%s' sent a response\n", pi.name); } else { - DEBUG_MSG("Plugin %s considered\n", pi.name); + DEBUG_MSG("Plugin '%s' considered\n", pi.name); } // If the requester didn't ask for a response we might need to discard unused replies to prevent memory leaks @@ -147,7 +150,7 @@ void MeshPlugin::callPlugins(const MeshPacket &mp, RxSource src) } if (handled == ProcessMessage::STOP) { - DEBUG_MSG("Plugin %s handled and skipped other processing\n", pi.name); + DEBUG_MSG("Plugin '%s' handled and skipped other processing\n", pi.name); break; } } From 475348489ef751c989f5cca134e4f50e96eb36eb Mon Sep 17 00:00:00 2001 From: riddick <93053584+PlumRugOfDoom@users.noreply.github.com> Date: Sat, 1 Jan 2022 19:11:40 +0100 Subject: [PATCH 22/34] Add status LED for diy targets and the core-pcb (#1049) * Update device-install.sh fix for #911 * add status led for diy target Co-authored-by: Ben Meadors --- src/configuration.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/configuration.h b/src/configuration.h index 597f60094..f2fc060d6 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -244,6 +244,7 @@ along with this program. If not, see . #define BUTTON_PIN 39 // The middle button GPIO on the T-Beam #define EXT_NOTIFY_OUT 12 // Overridden default pin to use for Ext Notify Plugin (#975). +#define LED_PIN 2 // add status LED (compatible with core-pcb and DIY targets) #define LORA_DIO0 26 // a No connect on the SX1262/SX1268 module #define LORA_RESET 23 // RST for SX1276, and for SX1262/SX1268 From 6e706e05854073a43353bb1e87cc3805ec8bf176 Mon Sep 17 00:00:00 2001 From: Sjoer van der Ploeg Date: Sat, 1 Jan 2022 20:12:24 +0100 Subject: [PATCH 23/34] Update MQTT.cpp (#1050) Was missing a colon in the logs! --- src/mqtt/MQTT.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 6235f37f7..26ef2a3e7 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -95,7 +95,7 @@ void MQTT::reconnect() } pubSub.setServer(serverAddr, serverPort); - DEBUG_MSG("Connecting to MQTT server %s, port: %d, username: %s, password %s\n", serverAddr, serverPort, mqttUsername, mqttPassword); + DEBUG_MSG("Connecting to MQTT server %s, port: %d, username: %s, password: %s\n", serverAddr, serverPort, mqttUsername, mqttPassword); auto myStatus = (statusTopic + owner.id); bool connected = pubSub.connect(owner.id, mqttUsername, mqttPassword, myStatus.c_str(), 1, true, "offline"); if (connected) { From 333b19580428f403a336b4a50529e2d0f0fb7ec2 Mon Sep 17 00:00:00 2001 From: linagee Date: Sat, 1 Jan 2022 13:00:32 -0700 Subject: [PATCH 24/34] Don't commit vim swap files to repo (#1051) --- .gitignore | 3 +++ bin/.promote-release.sh.swp | Bin 12288 -> 0 bytes 2 files changed, 3 insertions(+) delete mode 100644 bin/.promote-release.sh.swp diff --git a/.gitignore b/.gitignore index 40bba6f69..3d181a39a 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ flash.uf2 cmake-build* __pycache__ +*.swp +*.swo +*~ diff --git a/bin/.promote-release.sh.swp b/bin/.promote-release.sh.swp deleted file mode 100644 index 0dddde02b17cd4bae1d425c6efcf64ae2f262208..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI&ON$dh5CGtcSMh=Vfif$IxXC2ZgBKA*(cnhKN6yWoe32?g%@aySUb#Qb5Uru^(v@BGp$)~AZ zZT8^B_>QrKo{T2r9Sc8f4$L09qFs`WA$x4%lQz$m6m(P}nqr_ymD%iUT++%El;y@| zjdx2IY2c|Q6=)drj%+d|0wS<2Z~<;l#-sGzUjG_iz4B&zT1Fxu0wN#+A|L`HAOa#F z0{^u@YFO z^#A|n_y6}x0N*%1b9~}39Gc@k$4!o(y#7bG&!@f8L_h>YKmYKmV?Bc>Ue{(aTrU=g;0_(*{i?Mu(M&y3O~y9#s*IvjKy4ZC#>u$Cwl5t*J|6 zD~y`3^lA}t^C%o~xDKv*uz;HB5JiFR5-`R)54sjOp(v5$aiG`bd}yaOb^++>o44}ImO!9 z>JXq~(S~a+ylEoxCui$ZTsV*X3Z81$kPmpwe9F_NmZV^bRT4?s(WM+B&K%#Z4QW&9 R?2X9l*mzxgpojxP_ziF4!36*S From 924069f9ad285e4b09b3406fe5059654ad4e3113 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 1 Jan 2022 19:54:49 -0800 Subject: [PATCH 25/34] S&F - Only TX if utilization is below 25% --- src/plugins/esp32/StoreForwardPlugin.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/plugins/esp32/StoreForwardPlugin.cpp b/src/plugins/esp32/StoreForwardPlugin.cpp index f8194563e..f613fc7c0 100644 --- a/src/plugins/esp32/StoreForwardPlugin.cpp +++ b/src/plugins/esp32/StoreForwardPlugin.cpp @@ -27,8 +27,8 @@ int32_t StoreForwardPlugin::runOnce() if (this->busy) { - // Only send packets if the channel is less than 50% utilized. - if (airTime->channelUtilizationPercent() < 50) { + // Only send packets if the channel is less than 25% utilized. + if (airTime->channelUtilizationPercent() < 25) { // DEBUG_MSG("--- --- --- In busy loop 1 %d\n", this->packetHistoryTXQueue_index); storeForwardPlugin->sendPayload(this->busyTo, this->packetHistoryTXQueue_index); @@ -424,9 +424,6 @@ StoreForwardPlugin::StoreForwardPlugin() // Popupate PSRAM with our data structures. this->populatePSRAM(); - // this->packetTimeMax = 2000; - // DEBUG_MSG("SF Time to Transmit maxPacketSize (%d bytes) %d ms\n", maxPacketSize, this->packetTimeMax); - } else { DEBUG_MSG("Device has less than 1M of PSRAM free. Aborting startup.\n"); DEBUG_MSG("Store & Forward Plugin - Aborting Startup.\n"); From 749d127281f851e357a763f30a7e9c4687634875 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 1 Jan 2022 23:10:37 -0800 Subject: [PATCH 26/34] Return an informative message if web content files are unavailable. --- src/mesh/http/ContentHandler.cpp | 12 ++++++++++-- src/mesh/http/WiFiAPClient.cpp | 23 +++++++++++------------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index c1fced6de..9a655839f 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -297,14 +297,21 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res) file = SPIFFS.open(filenameGzip.c_str()); res->setHeader("Content-Encoding", "gzip"); if (!file.available()) { - DEBUG_MSG("File not available\n"); + DEBUG_MSG("File not available - %s\n", filenameGzip.c_str()); } } else { has_set_content_type = true; filenameGzip = "/static/index.html.gz"; file = SPIFFS.open(filenameGzip.c_str()); - res->setHeader("Content-Encoding", "gzip"); res->setHeader("Content-Type", "text/html"); + if (!file.available()) { + DEBUG_MSG("File not available - %s\n", filenameGzip.c_str()); + res->println("Web server is running.

The content you are looking for can't be found. Please see: FAQ.

stats"); + } else { + res->setHeader("Content-Encoding", "gzip"); + } } res->setHeader("Content-Length", httpsserver::intToString(file.size())); @@ -576,6 +583,7 @@ void handleReport(HTTPRequest *req, HTTPResponse *res) res->println("},"); res->println("\"device\": {"); + res->printf("\"channel_utilization\": %3.2f%,\n", airTime->channelUtilizationPercent()); res->printf("\"reboot_counter\": %d\n", myNodeInfo.reboot_count); res->println("},"); diff --git a/src/mesh/http/WiFiAPClient.cpp b/src/mesh/http/WiFiAPClient.cpp index 91892b5de..c5cbe9c93 100644 --- a/src/mesh/http/WiFiAPClient.cpp +++ b/src/mesh/http/WiFiAPClient.cpp @@ -3,9 +3,9 @@ #include "concurrency/Periodic.h" #include "configuration.h" #include "main.h" -#include "mqtt/MQTT.h" #include "mesh/http/WebServer.h" #include "mesh/wifi/WiFiServerAPI.h" +#include "mqtt/MQTT.h" #include "target_specific.h" #include #include @@ -132,30 +132,30 @@ static void onNetworkConnected() initApiServer(); APStartupComplete = true; - } + } // FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected' - if(mqtt) + if (mqtt) mqtt->reconnect(); } // Startup WiFi bool initWifi(bool forceSoftAP) { - if (forceSoftAP) { - DEBUG_MSG("WiFi ... Forced AP Mode\n"); - } else if (radioConfig.preferences.wifi_ap_mode) { - DEBUG_MSG("WiFi ... AP Mode\n"); - } else { - DEBUG_MSG("WiFi ... Client Mode\n"); - } - forcedSoftAP = forceSoftAP; if ((radioConfig.has_preferences && radioConfig.preferences.wifi_ssid[0]) || forceSoftAP) { const char *wifiName = radioConfig.preferences.wifi_ssid; const char *wifiPsw = radioConfig.preferences.wifi_password; + if (forceSoftAP) { + DEBUG_MSG("WiFi ... Forced AP Mode\n"); + } else if (radioConfig.preferences.wifi_ap_mode) { + DEBUG_MSG("WiFi ... AP Mode\n"); + } else { + DEBUG_MSG("WiFi ... Client Mode\n"); + } + createSSLCert(); if (!*wifiPsw) // Treat empty password as no password @@ -176,7 +176,6 @@ bool initWifi(bool forceSoftAP) } else { DEBUG_MSG("Starting WIFI AP: ssid=%s, ok=%d\n", wifiName, WiFi.softAP(wifiName, wifiPsw)); - } WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); From 5d4f039b3e8b04736a9fecd2c91ef719775e33f7 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sat, 1 Jan 2022 23:25:20 -0800 Subject: [PATCH 27/34] updating proto submodule to latest --- proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proto b/proto index 4a64080d1..7b80bde42 160000 --- a/proto +++ b/proto @@ -1 +1 @@ -Subproject commit 4a64080d160f9219768a4126414d41dc82a3d63c +Subproject commit 7b80bde4213c530ab3d85a19d1795025299d4633 From 3857dd7e5228d45953ce648b7df7edd2accee67c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 2 Jan 2022 14:41:41 +0100 Subject: [PATCH 28/34] regen protobuf headers --- src/mesh/generated/mesh.pb.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mesh/generated/mesh.pb.h b/src/mesh/generated/mesh.pb.h index 27e7d53cd..c5c980a35 100644 --- a/src/mesh/generated/mesh.pb.h +++ b/src/mesh/generated/mesh.pb.h @@ -23,6 +23,7 @@ typedef enum _HardwareModel { HardwareModel_TLORA_V1_1p3 = 8, HardwareModel_RAK4631 = 9, HardwareModel_HELTEC_V2_1 = 10, + HardwareModel_HELTEC_V1 = 11, HardwareModel_LORA_RELAY_V1 = 32, HardwareModel_NRF52840DK = 33, HardwareModel_PPR = 34, From 9a87ec73536e9791b0f982e3cbe1a9a249b3cca3 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 2 Jan 2022 11:05:32 -0800 Subject: [PATCH 29/34] Count tx airtime only after it's sent by the radio --- src/mesh/RadioLibInterface.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index cb77d9ec3..4455b971c 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -101,7 +101,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) // Sometimes when testing it is useful to be able to never turn on the xmitter #ifndef LORA_DISABLE_SENDING printPacket("enqueuing for send", p); - uint32_t xmitMsec = getPacketTime(p); DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad); ErrorCode res = txQueue.enqueue(p) ? ERRNO_OK : ERRNO_UNKNOWN; @@ -111,10 +110,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) return res; } - // Count the packet toward our TX airtime utilization. - // We only count it if it can be added to the TX queue. - airTime->logAirtime(TX_LOG, xmitMsec); - // We want all sending/receiving to be done by our daemon thread, We use a delay here because this packet might have been sent // in response to a packet we just received. So we want to make sure the other side has had a chance to reconfigure its radio startTransmitTimer(true); @@ -188,6 +183,10 @@ void RadioLibInterface::onNotify(uint32_t notification) MeshPacket *txp = txQueue.dequeue(); assert(txp); startSend(txp); + + // Packet has been sent, count it toward our TX airtime utilization. + uint32_t xmitMsec = getPacketTime(txp); + airTime->logAirtime(TX_LOG, xmitMsec); } } else { // DEBUG_MSG("done with txqueue\n"); From 4d82a0146b3913141ef8f8f796b980802f62162b Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 2 Jan 2022 19:50:43 -0800 Subject: [PATCH 30/34] Initial checkin of Online OTA SPIFFS update --- platformio.ini | 1 + src/mesh/RadioLibInterface.h | 1 + src/mesh/http/ContentHandler.cpp | 137 ++++++++++++++++++++++++++++++- src/mesh/http/ContentHandler.h | 5 +- 4 files changed, 139 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index 9c301ea33..155460b1c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -115,6 +115,7 @@ lib_deps = paulstoffregen/OneWire@^2.3.5 robtillaart/DS18B20@^0.1.11 h2zero/NimBLE-Arduino@1.3.1 + tobozo/ESP32-targz@^1.1.4 # Hmm - this doesn't work yet # board_build.ldscript = linker/esp32.extram.bss.ld lib_ignore = diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h index 54d9e6744..de3505524 100644 --- a/src/mesh/RadioLibInterface.h +++ b/src/mesh/RadioLibInterface.h @@ -8,6 +8,7 @@ #define RADIOLIB_SOFTWARE_SERIAL_UNSUPPORTED #endif +#define RADIOLIB_EXCLUDE_HTTP #include // ESP32 has special rules about ISR code diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 9a655839f..38fab4848 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -41,6 +41,13 @@ using namespace httpsserver; #include "mesh/http/ContentHandler.h" +#include +#include +HTTPClient http; + +#define DEST_FS_USES_SPIFFS +#include + // We need to specify some content-type mapping, so the resources get delivered with the // right content type and are displayed correctly in the browser char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"}, @@ -50,9 +57,58 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"} {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"}, {".svg", "image/svg+xml"}, {"", ""}}; +const char *tarURL = "https://www.casler.org/temp/meshtastic-web.tar"; +const char *certificate = NULL; // change this as needed, leave as is for no TLS check (yolo security) + // Our API to handle messages to and from the radio. HttpAPI webAPI; +WiFiClient *getTarHTTPClientPtr(WiFiClientSecure *client, const char *url, const char *cert = NULL) +{ + if (cert == NULL) { + // New versions don't have setInsecure + // client->setInsecure(); + } else { + client->setCACert(cert); + } + const char *UserAgent = "ESP32-HTTP-GzUpdater-Client"; + http.setReuse(true); // handle 301 redirects gracefully + http.setUserAgent(UserAgent); + http.setConnectTimeout(10000); // 10s timeout = 10000 + if (!http.begin(*client, url)) { + log_e("Can't open url %s", url); + return nullptr; + } + const char *headerKeys[] = {"location", "redirect", "Content-Type", "Content-Length", "Content-Disposition"}; + const size_t numberOfHeaders = 5; + http.collectHeaders(headerKeys, numberOfHeaders); + int httpCode = http.GET(); + // file found at server + if (httpCode == HTTP_CODE_FOUND || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { + String newlocation = ""; + String headerLocation = http.header("location"); + String headerRedirect = http.header("redirect"); + if (headerLocation != "") { + newlocation = headerLocation; + Serial.printf("302 (location): %s => %s\n", url, headerLocation.c_str()); + } else if (headerRedirect != "") { + Serial.printf("301 (redirect): %s => %s\n", url, headerLocation.c_str()); + newlocation = headerRedirect; + } + http.end(); + if (newlocation != "") { + log_w("Found 302/301 location header: %s", newlocation.c_str()); + return getTarHTTPClientPtr(client, newlocation.c_str(), cert); + } else { + log_e("Empty redirect !!"); + return nullptr; + } + } + if (httpCode != 200) + return nullptr; + return http.getStreamPtr(); +} + void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) { @@ -66,6 +122,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) ResourceNode *nodeHotspotApple = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot); ResourceNode *nodeHotspotAndroid = new ResourceNode("/generate_204", "GET", &handleHotspot); + ResourceNode *nodeUpdateSPIFFS = new ResourceNode("/update", "GET", &handleUpdateSPIFFS); + ResourceNode *nodeRestart = new ResourceNode("/restart", "POST", &handleRestart); ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload); @@ -90,7 +148,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) secureServer->registerNode(nodeJsonSpiffsBrowseStatic); secureServer->registerNode(nodeJsonDelete); secureServer->registerNode(nodeJsonReport); - secureServer->registerNode(nodeRoot); + secureServer->registerNode(nodeUpdateSPIFFS); + secureServer->registerNode(nodeRoot); // This has to be last // Insecure nodes insecureServer->registerNode(nodeAPIv1ToRadioOptions); @@ -105,7 +164,8 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) insecureServer->registerNode(nodeJsonSpiffsBrowseStatic); insecureServer->registerNode(nodeJsonDelete); insecureServer->registerNode(nodeJsonReport); - insecureServer->registerNode(nodeRoot); + insecureServer->registerNode(nodeUpdateSPIFFS); + insecureServer->registerNode(nodeRoot); // This has to be last } void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) @@ -620,6 +680,79 @@ void handleHotspot(HTTPRequest *req, HTTPResponse *res) res->println("\n"); } +void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res) +{ + res->setHeader("Content-Type", "text/html"); + res->setHeader("Access-Control-Allow-Origin", "*"); + res->setHeader("Access-Control-Allow-Methods", "GET"); + + res->println("Updating. Don't leave this page!"); + + DEBUG_MSG("hi!\n"); + + File root = SPIFFS.open("/"); + File file = root.openNextFile(); + + DEBUG_MSG("Deleting files from /static\n"); + + while (file) { + String filePath = String(file.name()); + if (filePath.indexOf("/static") == 0) { + DEBUG_MSG("%s\n", file.name()); + SPIFFS.remove(file.name()); + } + file = root.openNextFile(); + } + + // return; + + WiFiClientSecure *client = new WiFiClientSecure; + Stream *streamptr = getTarHTTPClientPtr(client, tarURL, certificate); + + if (streamptr != nullptr) { + + TarUnpacker *TARUnpacker = new TarUnpacker(); + TARUnpacker->haltOnError(true); // stop on fail (manual restart/reset required) + TARUnpacker->setTarVerify(true); // true = enables health checks but slows down the overall process + TARUnpacker->setupFSCallbacks(targzTotalBytesFn, targzFreeBytesFn); // prevent the partition from exploding, recommended + TARUnpacker->setLoggerCallback(BaseUnpacker::targzPrintLoggerCallback); // gz log verbosity + TARUnpacker->setTarProgressCallback( + BaseUnpacker::defaultProgressCallback); // prints the untarring progress for each individual file + TARUnpacker->setTarStatusProgressCallback( + BaseUnpacker::defaultTarStatusProgressCallback); // print the filenames as they're expanded + TARUnpacker->setTarMessageCallback(BaseUnpacker::targzPrintLoggerCallback); // tar log verbosity + + String contentLengthStr = http.header("Content-Length"); + contentLengthStr.trim(); + int64_t streamSize = -1; + if (contentLengthStr != "") { + streamSize = atoi(contentLengthStr.c_str()); + Serial.printf("Stream size %d\n", streamSize); + res->printf("Stream size %d\n", streamSize); + } + + if (!TARUnpacker->tarStreamExpander(streamptr, streamSize, SPIFFS, "/static")) { + Serial.printf("tarStreamExpander failed with return code #%d\n", TARUnpacker->tarGzGetError()); + } else { + // print leftover bytes if any (probably zero-fill from the server) + while (http.connected()) { + size_t streamSize = streamptr->available(); + if (streamSize) { + Serial.printf("%02x ", streamptr->read()); + } else + break; + } + + res->println("Done"); + } + + } else { + Serial.println("Failed to establish http connection"); + } + + res->println("Done"); +} + void handleRestart(HTTPRequest *req, HTTPResponse *res) { res->setHeader("Content-Type", "text/html"); diff --git a/src/mesh/http/ContentHandler.h b/src/mesh/http/ContentHandler.h index cc07cb833..f456d0a1f 100644 --- a/src/mesh/http/ContentHandler.h +++ b/src/mesh/http/ContentHandler.h @@ -1,5 +1,6 @@ #pragma once + void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer); // Declare some handler functions for the various URLs on the server @@ -14,9 +15,7 @@ void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res); void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res); void handleBlinkLED(HTTPRequest *req, HTTPResponse *res); void handleReport(HTTPRequest *req, HTTPResponse *res); - -void middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function next); -void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function next); +void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res); // Interface to the PhoneAPI to access the protobufs with messages class HttpAPI : public PhoneAPI From 893472e36a671047006e5f32dbdf0a62e35ed428 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 2 Jan 2022 20:05:13 -0800 Subject: [PATCH 31/34] Update text and tar URL --- src/mesh/http/ContentHandler.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 38fab4848..737335b83 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -57,7 +57,7 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"} {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"}, {".svg", "image/svg+xml"}, {"", ""}}; -const char *tarURL = "https://www.casler.org/temp/meshtastic-web.tar"; +const char *tarURL = "https://github.com/meshtastic/meshtastic-web/releases/download/latest/build.tar"; const char *certificate = NULL; // change this as needed, leave as is for no TLS check (yolo security) // Our API to handle messages to and from the radio. @@ -368,7 +368,7 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res) DEBUG_MSG("File not available - %s\n", filenameGzip.c_str()); res->println("Web server is running.

The content you are looking for can't be found. Please see: FAQ.

stats"); + "href=/json/report>stats

Experemntal Web Content OTA Update"); } else { res->setHeader("Content-Encoding", "gzip"); } @@ -742,8 +742,6 @@ void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res) } else break; } - - res->println("Done"); } } else { From b2011a1889e585f62332b4b308475e3f158e6ad9 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 2 Jan 2022 20:37:52 -0800 Subject: [PATCH 32/34] Switching url to casler.org. github has too many redirections. --- src/mesh/http/ContentHandler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 737335b83..3f622b65c 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -57,7 +57,8 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"} {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"}, {".svg", "image/svg+xml"}, {"", ""}}; -const char *tarURL = "https://github.com/meshtastic/meshtastic-web/releases/download/latest/build.tar"; +//const char *tarURL = "https://github.com/meshtastic/meshtastic-web/releases/download/latest/build.tar"; +const char *tarURL = "https://www.casler.org/temp/meshtastic-web.tar"; const char *certificate = NULL; // change this as needed, leave as is for no TLS check (yolo security) // Our API to handle messages to and from the radio. From 6d0368b13d421331a434714d7f88a9fc6a996d5b Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 2 Jan 2022 22:10:55 -0800 Subject: [PATCH 33/34] Update URL to proper meshtastic web download location & disable halting --- src/mesh/http/ContentHandler.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 3f622b65c..3e35ee5fd 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -57,8 +57,8 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"} {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"}, {".svg", "image/svg+xml"}, {"", ""}}; -//const char *tarURL = "https://github.com/meshtastic/meshtastic-web/releases/download/latest/build.tar"; -const char *tarURL = "https://www.casler.org/temp/meshtastic-web.tar"; +//const char *tarURL = "https://www.casler.org/temp/meshtastic-web.tar"; +const char *tarURL = "https://api-production-871d.up.railway.app/mirror/webui"; const char *certificate = NULL; // change this as needed, leave as is for no TLS check (yolo security) // Our API to handle messages to and from the radio. @@ -687,9 +687,7 @@ void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res) res->setHeader("Access-Control-Allow-Origin", "*"); res->setHeader("Access-Control-Allow-Methods", "GET"); - res->println("Updating. Don't leave this page!"); - - DEBUG_MSG("hi!\n"); + res->println("Downloading Meshtastic Web Content..."); File root = SPIFFS.open("/"); File file = root.openNextFile(); @@ -713,8 +711,8 @@ void handleUpdateSPIFFS(HTTPRequest *req, HTTPResponse *res) if (streamptr != nullptr) { TarUnpacker *TARUnpacker = new TarUnpacker(); - TARUnpacker->haltOnError(true); // stop on fail (manual restart/reset required) - TARUnpacker->setTarVerify(true); // true = enables health checks but slows down the overall process + TARUnpacker->haltOnError(false); // stop on fail (manual restart/reset required) + TARUnpacker->setTarVerify(false); // true = enables health checks but slows down the overall process TARUnpacker->setupFSCallbacks(targzTotalBytesFn, targzFreeBytesFn); // prevent the partition from exploding, recommended TARUnpacker->setLoggerCallback(BaseUnpacker::targzPrintLoggerCallback); // gz log verbosity TARUnpacker->setTarProgressCallback( From 063d7a7d8117271b084f18f925143d723381cf78 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Sun, 2 Jan 2022 22:17:26 -0800 Subject: [PATCH 34/34] Cleanup API endpoint debug output --- src/mesh/http/ContentHandler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index 3e35ee5fd..c051e0cda 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -172,7 +172,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) { - DEBUG_MSG("+++++++++++++++ webAPI handleAPIv1FromRadio\n"); + DEBUG_MSG("webAPI handleAPIv1FromRadio\n"); /* For documentation, see: @@ -217,12 +217,12 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) res->write(txBuf, len); } - DEBUG_MSG("--------------- webAPI handleAPIv1FromRadio, len %d\n", len); + DEBUG_MSG("webAPI handleAPIv1FromRadio, len %d\n", len); } void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) { - DEBUG_MSG("+++++++++++++++ webAPI handleAPIv1ToRadio\n"); + DEBUG_MSG("webAPI handleAPIv1ToRadio\n"); /* For documentation, see: @@ -249,7 +249,7 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) webAPI.handleToRadio(buffer, s); res->write(buffer, s); - DEBUG_MSG("--------------- webAPI handleAPIv1ToRadio\n"); + DEBUG_MSG("webAPI handleAPIv1ToRadio\n"); } void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res)