From d5b57840d9f1019230c5b8dc31fcd1f42f6c2abd Mon Sep 17 00:00:00 2001 From: Jm Date: Thu, 24 Dec 2020 22:12:59 -0800 Subject: [PATCH 01/10] checking in a little of the airtime so i can switch to the laptop. --- src/airtime.cpp | 31 +++++++++++++++++++++++++++++++ src/airtime.h | 6 ++++++ 2 files changed, 37 insertions(+) create mode 100644 src/airtime.cpp create mode 100644 src/airtime.h diff --git a/src/airtime.cpp b/src/airtime.cpp new file mode 100644 index 00000000..1fec1e0c --- /dev/null +++ b/src/airtime.cpp @@ -0,0 +1,31 @@ +/* +We will keep hourly stats for 48 hours and daily stats for 7 days + +3600 seconds in an hour, uint16_t per hour +86400 seconds in a day, uint32_t per day + +Memory to store 48 hours = 96 bytes +Memory to store 7 days = 28 bytes + + +*/ + +void logTXairtime(uint32_t airtime_ms) +{ + /* + + How many hours since power up? + + Millis / 1000 / 3600 + + + + */ +} + +void logRXairtime() +{ + /* + + */ +} diff --git a/src/airtime.h b/src/airtime.h new file mode 100644 index 00000000..65edbd20 --- /dev/null +++ b/src/airtime.h @@ -0,0 +1,6 @@ +#pragma once + +#include "configuration.h" +#include +#include + From ded2b86e55fe86545390f9de054475e2c8b31f93 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Fri, 25 Dec 2020 16:10:38 -0800 Subject: [PATCH 02/10] Calculate TX air time duty cycles #588 -- UNTESTED --- src/airtime.cpp | 91 ++++++++++++++++++++++++++-------- src/airtime.h | 10 ++++ src/mesh/RadioInterface.h | 3 +- src/mesh/RadioLibInterface.cpp | 6 +++ 4 files changed, 88 insertions(+), 22 deletions(-) diff --git a/src/airtime.cpp b/src/airtime.cpp index 1fec1e0c..8f0f20f1 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -1,31 +1,80 @@ -/* -We will keep hourly stats for 48 hours and daily stats for 7 days +#include "airtime.h" +#include -3600 seconds in an hour, uint16_t per hour -86400 seconds in a day, uint32_t per day +#define hoursToLog 48 -Memory to store 48 hours = 96 bytes -Memory to store 7 days = 28 bytes +// Here for convience and to avoid magic numbers. +uint16_t secondsPerHour = 3600; +// Don't read out of this directly. Use the helper functions. +struct airtimeStruct { + uint16_t hourTX[hoursToLog]; + uint16_t hourRX[hoursToLog]; + uint16_t hourRX_ALL[hoursToLog]; + uint8_t lastHourIndex; +} airtimes; -*/ - -void logTXairtime(uint32_t airtime_ms) +void logAirtime(reportTypes reportType, uint32_t airtime_ms) { - /* + currentHourIndexReset(); - How many hours since power up? - - Millis / 1000 / 3600 - - - - */ + if (reportType == TX_LOG) { + airtimes.hourTX[currentHourIndex()] = airtimes.hourTX[currentHourIndex()] + round(airtime_ms / 1000); + } else if (reportType == RX_LOG) { + airtimes.hourRX[currentHourIndex()] = airtimes.hourRX[currentHourIndex()] + round(airtime_ms / 1000); + } else if (reportType == RX_ALL_LOG) { + airtimes.hourRX_ALL[currentHourIndex()] = airtimes.hourRX_ALL[currentHourIndex()] + round(airtime_ms / 1000); + } else { + // Unknown report type + + } } -void logRXairtime() +// This will let us easily switch away from using millis at some point. +// todo: Don't use millis, instead maintain our own count of time since +// boot in seconds. +uint32_t secondsSinceBoot() { - /* - - */ + return millis() / 1000; } + +uint8_t currentHourIndex() +{ + // return ((secondsSinceBoot() - (secondsSinceBoot() / (hoursToLog * secondsPerHour))) / secondsPerHour); + return ((secondsSinceBoot() / secondsPerHour) % hoursToLog); +} + +// currentHourIndexReset() should be called every time we receive a packet to log (either RX or TX) +// and every time we are asked to report on airtime usage. +void currentHourIndexReset() +{ + if (airtimes.lastHourIndex != currentHourIndex()) { + airtimes.hourTX[currentHourIndex()] = 0; + airtimes.hourRX[currentHourIndex()] = 0; + airtimes.hourRX_ALL[currentHourIndex()] = 0; + + airtimes.lastHourIndex = currentHourIndex(); + } +} + +uint16_t *airtimeReport(reportTypes reportType) +{ + static uint16_t array[hoursToLog]; + + currentHourIndexReset(); + + for (int i = 0; i < hoursToLog; i++) { + if (reportType == TX_LOG) { + array[i] = airtimes.hourTX[(airtimes.lastHourIndex + i) % hoursToLog]; + } else if (reportType == RX_LOG) { + array[i] = airtimes.hourRX[(airtimes.lastHourIndex + i) % hoursToLog]; + } else if (reportType == RX_ALL_LOG) { + array[i] = airtimes.hourRX_ALL[(airtimes.lastHourIndex + i) % hoursToLog]; + } else { + // Unknown report type + return array; + } + } + + return array; +} \ No newline at end of file diff --git a/src/airtime.h b/src/airtime.h index 65edbd20..5df916a5 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -4,3 +4,13 @@ #include #include +enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG }; + +void logAirtime(reportTypes reportType, uint32_t airtime_ms); + +void currentHourIndexReset(); +uint8_t currentHourIndex(); + +uint32_t secondsSinceBoot(); + +uint16_t *airtimeReport(reportTypes reportType); \ No newline at end of file diff --git a/src/mesh/RadioInterface.h b/src/mesh/RadioInterface.h index e5253d7a..b76d3035 100644 --- a/src/mesh/RadioInterface.h +++ b/src/mesh/RadioInterface.h @@ -5,6 +5,7 @@ #include "MeshTypes.h" #include "Observer.h" #include "PointerQueue.h" +#include "airtime.h" #include "mesh.pb.h" #define MAX_TX_QUEUE 16 // max number of packets which can be waiting for transmission @@ -36,7 +37,7 @@ typedef struct { * * This defines the SOLE API for talking to radios (because soon we will have alternate radio implementations) */ -class RadioInterface +class RadioInterface { friend class MeshRadio; // for debugging we let that class touch pool PointerQueue *rxDest = NULL; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 9a5ec536..c8159745 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -88,6 +88,7 @@ ErrorCode RadioLibInterface::send(MeshPacket *p) 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, 0) ? ERRNO_OK : ERRNO_UNKNOWN; @@ -96,6 +97,11 @@ 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. + 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); From e321528a6d14a0f18c49c26b50e80fba40280303 Mon Sep 17 00:00:00 2001 From: Jm Date: Sat, 26 Dec 2020 22:39:43 -0800 Subject: [PATCH 03/10] #588 - Calculate TX air time --- platformio.ini | 4 +- src/airtime.cpp | 73 +++++++++++----------- src/airtime.h | 8 ++- src/main.cpp | 4 ++ src/meshwifi/meshhttp.cpp | 124 ++++++++++++++++++++++++++++++++------ 5 files changed, 153 insertions(+), 60 deletions(-) diff --git a/platformio.ini b/platformio.ini index 50d381c8..14e6ddbd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -38,8 +38,8 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n ;upload_port = /dev/ttyUSB0 ;monitor_port = /dev/ttyUSB0 -;upload_port = /dev/cu.SLAB_USBtoUART -;monitor_port = /dev/cu.SLAB_USBtoUART +upload_port = /dev/cu.SLAB_USBtoUART +monitor_port = /dev/cu.SLAB_USBtoUART ; the default is esptool ; upload_protocol = esp-prog diff --git a/src/airtime.cpp b/src/airtime.cpp index 8f0f20f1..fb2b2251 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -3,8 +3,13 @@ #define hoursToLog 48 -// Here for convience and to avoid magic numbers. +// A reminder that there are 3600 seconds in an hour so I don't have +// to keep googling it. +// This can be changed to a smaller number to speed up testing. +// uint16_t secondsPerHour = 3600; +uint32_t lastMillis = 0; +uint32_t secSinceBoot = 0; // Don't read out of this directly. Use the helper functions. struct airtimeStruct { @@ -16,65 +21,63 @@ struct airtimeStruct { void logAirtime(reportTypes reportType, uint32_t airtime_ms) { - currentHourIndexReset(); if (reportType == TX_LOG) { - airtimes.hourTX[currentHourIndex()] = airtimes.hourTX[currentHourIndex()] + round(airtime_ms / 1000); + airtimes.hourTX[0] = airtimes.hourTX[0] + round(airtime_ms / 1000); } else if (reportType == RX_LOG) { - airtimes.hourRX[currentHourIndex()] = airtimes.hourRX[currentHourIndex()] + round(airtime_ms / 1000); + airtimes.hourRX[0] = airtimes.hourRX[0] + round(airtime_ms / 1000); } else if (reportType == RX_ALL_LOG) { - airtimes.hourRX_ALL[currentHourIndex()] = airtimes.hourRX_ALL[currentHourIndex()] + round(airtime_ms / 1000); + airtimes.hourRX_ALL[0] = airtimes.hourRX_ALL[0] + round(airtime_ms / 1000); } else { // Unknown report type - } } -// This will let us easily switch away from using millis at some point. -// todo: Don't use millis, instead maintain our own count of time since -// boot in seconds. -uint32_t secondsSinceBoot() +uint32_t getSecondsSinceBoot() { - return millis() / 1000; + return secSinceBoot; } uint8_t currentHourIndex() { // return ((secondsSinceBoot() - (secondsSinceBoot() / (hoursToLog * secondsPerHour))) / secondsPerHour); - return ((secondsSinceBoot() / secondsPerHour) % hoursToLog); + return ((getSecondsSinceBoot() / secondsPerHour) % hoursToLog); } -// currentHourIndexReset() should be called every time we receive a packet to log (either RX or TX) -// and every time we are asked to report on airtime usage. -void currentHourIndexReset() +void airtimeCalculator() { - if (airtimes.lastHourIndex != currentHourIndex()) { - airtimes.hourTX[currentHourIndex()] = 0; - airtimes.hourRX[currentHourIndex()] = 0; - airtimes.hourRX_ALL[currentHourIndex()] = 0; + if (millis() - lastMillis > 1000) { + lastMillis = millis(); + secSinceBoot++; + // DEBUG_MSG("------- lastHourIndex %i currentHourIndex %i\n", airtimes.lastHourIndex, currentHourIndex()); + if (airtimes.lastHourIndex != currentHourIndex()) { + for (int i = hoursToLog - 2; i >= 0; --i) { + airtimes.hourTX[i + 1] = airtimes.hourTX[i]; + airtimes.hourRX[i + 1] = airtimes.hourRX[i]; + airtimes.hourRX_ALL[i + 1] = airtimes.hourRX_ALL[i]; + } + airtimes.hourTX[0] = 0; - airtimes.lastHourIndex = currentHourIndex(); + airtimes.lastHourIndex = currentHourIndex(); + } } } uint16_t *airtimeReport(reportTypes reportType) { - static uint16_t array[hoursToLog]; + // currentHourIndexReset(); - currentHourIndexReset(); - - for (int i = 0; i < hoursToLog; i++) { - if (reportType == TX_LOG) { - array[i] = airtimes.hourTX[(airtimes.lastHourIndex + i) % hoursToLog]; - } else if (reportType == RX_LOG) { - array[i] = airtimes.hourRX[(airtimes.lastHourIndex + i) % hoursToLog]; - } else if (reportType == RX_ALL_LOG) { - array[i] = airtimes.hourRX_ALL[(airtimes.lastHourIndex + i) % hoursToLog]; - } else { - // Unknown report type - return array; - } + if (reportType == TX_LOG) { + return airtimes.hourTX; + } else if (reportType == RX_LOG) { + return airtimes.hourRX; + } else if (reportType == RX_ALL_LOG) { + return airtimes.hourRX_ALL; } + return 0; +} - return array; +uint8_t getHoursToLog() +{ + return hoursToLog; } \ No newline at end of file diff --git a/src/airtime.h b/src/airtime.h index 5df916a5..0324cd56 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -8,9 +8,11 @@ enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG }; void logAirtime(reportTypes reportType, uint32_t airtime_ms); -void currentHourIndexReset(); -uint8_t currentHourIndex(); +void airtimeCalculator(); -uint32_t secondsSinceBoot(); +uint8_t currentHourIndex(); +uint8_t getHoursToLog(); + +uint32_t getSecondsSinceBoot(); uint16_t *airtimeReport(reportTypes reportType); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 3f028613..762cf5e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,6 +5,7 @@ #include "NodeDB.h" #include "PowerFSM.h" #include "UBloxGPS.h" +#include "airtime.h" #include "configuration.h" #include "error.h" #include "power.h" @@ -558,4 +559,7 @@ void loop() // We want to sleep as long as possible here - because it saves power mainDelay.delay(delayMsec); // if (didWake) DEBUG_MSG("wake!\n"); + + // Handles cleanup for the airtime calculator. + airtimeCalculator(); } diff --git a/src/meshwifi/meshhttp.cpp b/src/meshwifi/meshhttp.cpp index b6953c32..e24f6717 100644 --- a/src/meshwifi/meshhttp.cpp +++ b/src/meshwifi/meshhttp.cpp @@ -1,10 +1,11 @@ #include "meshwifi/meshhttp.h" #include "NodeDB.h" +#include "PowerFSM.h" +#include "airtime.h" #include "configuration.h" #include "main.h" #include "meshhttpStatic.h" #include "meshwifi/meshwifi.h" -#include "PowerFSM.h" #include "sleep.h" #include #include @@ -64,6 +65,7 @@ void handleScanNetworks(HTTPRequest *req, HTTPResponse *res); 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); @@ -80,7 +82,7 @@ char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"} {".js", "text/javascript"}, {".png", "image/png"}, {".jpg", "image/jpg"}, {".gz", "application/gzip"}, {".gif", "image/gif"}, {".json", "application/json"}, - {".css", "text/css"}, {".ico","image/vnd.microsoft.icon"}, + {".css", "text/css"}, {".ico", "image/vnd.microsoft.icon"}, {".svg", "image/svg+xml"}, {"", ""}}; void handleWebResponse() @@ -248,6 +250,7 @@ void initWebServer() ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload); ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks); ResourceNode *nodeJsonBlinkLED = new ResourceNode("/json/blink", "POST", &handleBlinkLED); + ResourceNode *nodeJsonReport = new ResourceNode("/json/report", "GET", &handleReport); ResourceNode *nodeJsonSpiffsBrowseStatic = new ResourceNode("/json/spiffs/browse/static/", "GET", &handleSpiffsBrowseStatic); ResourceNode *nodeJsonDelete = new ResourceNode("/json/spiffs/delete/static", "DELETE", &handleSpiffsDeleteStatic); @@ -267,6 +270,7 @@ void initWebServer() secureServer->registerNode(nodeJsonBlinkLED); secureServer->registerNode(nodeJsonSpiffsBrowseStatic); secureServer->registerNode(nodeJsonDelete); + secureServer->registerNode(nodeJsonReport); secureServer->setDefaultNode(node404); secureServer->addMiddleware(&middlewareSpeedUp240); @@ -287,6 +291,7 @@ void initWebServer() insecureServer->registerNode(nodeJsonBlinkLED); insecureServer->registerNode(nodeJsonSpiffsBrowseStatic); insecureServer->registerNode(nodeJsonDelete); + insecureServer->registerNode(nodeJsonReport); insecureServer->setDefaultNode(node404); insecureServer->addMiddleware(&middlewareSpeedUp160); @@ -458,26 +463,26 @@ void handleSpiffsBrowseStatic(HTTPRequest *req, HTTPResponse *res) void handleSpiffsDeleteStatic(HTTPRequest *req, HTTPResponse *res) { - ResourceParameters *params = req->getParams(); - std::string paramValDelete; + ResourceParameters *params = req->getParams(); + std::string paramValDelete; - res->setHeader("Content-Type", "application/json"); - if (params->getQueryParameter("delete", paramValDelete)) { - std::string pathDelete = "/" + paramValDelete; - if (SPIFFS.remove(pathDelete.c_str())) { - Serial.println(pathDelete.c_str()); - res->println("{"); - res->println("\"status\": \"ok\""); - res->println("}"); - return; - } else { - Serial.println(pathDelete.c_str()); - res->println("{"); - res->println("\"status\": \"Error\""); - res->println("}"); - return; + res->setHeader("Content-Type", "application/json"); + if (params->getQueryParameter("delete", paramValDelete)) { + std::string pathDelete = "/" + paramValDelete; + if (SPIFFS.remove(pathDelete.c_str())) { + Serial.println(pathDelete.c_str()); + res->println("{"); + res->println("\"status\": \"ok\""); + res->println("}"); + return; + } else { + Serial.println(pathDelete.c_str()); + res->println("{"); + res->println("\"status\": \"Error\""); + res->println("}"); + return; + } } - } } void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res) @@ -1041,6 +1046,85 @@ void handleBlinkLED(HTTPRequest *req, HTTPResponse *res) res->println("}"); } +void handleReport(HTTPRequest *req, HTTPResponse *res) +{ + + ResourceParameters *params = req->getParams(); + std::string content; + + if (!params->getQueryParameter("content", content)) { + content = "json"; + } + + if (content == "json") { + res->setHeader("Content-Type", "application/json"); + + } else { + res->setHeader("Content-Type", "text/html"); + res->println("
");
+    }
+
+    res->println("{");
+
+    res->println("\"data\": {");
+
+    res->println("\"airtime\": {");
+
+    uint16_t *logArray;
+
+    res->print("\"tx_log\": [");
+
+    logArray = airtimeReport(TX_LOG);
+    for (int i = 0; i < getHoursToLog(); i++) {
+        uint16_t tmp;
+        tmp = *(logArray + i);
+        res->printf("%d", tmp);
+        if (i != getHoursToLog() - 1) {
+            res->print(", ");
+        }
+    }
+
+    res->println("],");
+    res->print("\"rx_log\": [");
+
+    logArray = airtimeReport(RX_LOG);
+    for (int i = 0; i < getHoursToLog(); i++) {
+        uint16_t tmp;
+        tmp = *(logArray + i);
+        res->printf("%d", tmp);
+        if (i != getHoursToLog() - 1) {
+            res->print(", ");
+        }
+    }
+
+    res->println("],");
+    res->print("\"rx_all_log\": [");
+
+    logArray = airtimeReport(RX_ALL_LOG);
+    for (int i = 0; i < getHoursToLog(); i++) {
+        uint16_t tmp;
+        tmp = *(logArray + i);
+        res->printf("%d", tmp);
+        if (i != getHoursToLog() - 1) {
+            res->print(", ");
+        }
+    }
+
+    res->println("],");
+    res->printf("\"seconds_since_boot\": %u,\n", getSecondsSinceBoot());
+    res->printf("\"hours_to_log\": %u\n", getHoursToLog());
+
+    res->println("},");
+
+    res->println("\"something\": 123,");
+    res->println("\"something_else\": 123");
+
+    res->println("},");
+
+    res->println("\"status\": \"ok\"");
+    res->println("}");
+}
+
 void handleScanNetworks(HTTPRequest *req, HTTPResponse *res)
 {
     res->setHeader("Content-Type", "application/json");

From 3c69beef94cfdc955a8d12703acddade4b633781 Mon Sep 17 00:00:00 2001
From: Jm 
Date: Sat, 26 Dec 2020 23:37:04 -0800
Subject: [PATCH 04/10] Update to the airtime calculator. I didn't 0 out the RX
 log.

---
 src/airtime.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/airtime.cpp b/src/airtime.cpp
index fb2b2251..82f0d3bf 100644
--- a/src/airtime.cpp
+++ b/src/airtime.cpp
@@ -57,6 +57,8 @@ void airtimeCalculator()
                 airtimes.hourRX_ALL[i + 1] = airtimes.hourRX_ALL[i];
             }
             airtimes.hourTX[0] = 0;
+            airtimes.hourRX[0] = 0;
+            airtimes.hourRX_ALL[0] = 0;
 
             airtimes.lastHourIndex = currentHourIndex();
         }

From 58859848a35a25e7be0225a81ae964587a8ecc7a Mon Sep 17 00:00:00 2001
From: Jm Casler 
Date: Sun, 27 Dec 2020 09:29:48 -0800
Subject: [PATCH 05/10] Add RX and RX_ALL analytics for #588

---
 proto                          |  2 +-
 src/airtime.h                  | 18 ++++++++++++++++++
 src/mesh/RadioLibInterface.cpp | 12 ++++++++----
 3 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/proto b/proto
index 323b814f..ce422b7c 160000
--- a/proto
+++ b/proto
@@ -1 +1 @@
-Subproject commit 323b814f4392ae0f9c42a0f14557c6b9333efce3
+Subproject commit ce422b7c448906c6fee3eef64bbd41adfbc990f0
diff --git a/src/airtime.h b/src/airtime.h
index 0324cd56..482ab394 100644
--- a/src/airtime.h
+++ b/src/airtime.h
@@ -4,6 +4,24 @@
 #include 
 #include 
 
+/*
+  TX_LOG      - Time on air this device has transmitted
+
+  RX_LOG      - Time on air used by valid and routable mesh packets, does not include
+                TX air time
+
+  RX_ALL_LOG  - Time of all received lora packets. This includes packets that are not
+                for meshtastic devices. Does not include TX air time.
+
+  Example analytics:
+
+  TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel.
+
+  TX_LOG + RX_LOG = Total air time for a perticular meshtastic channel, including
+                    other lora radios. 
+
+  RX_ALL_LOG - RX_LOG = Other lora radios on our frequency channel.
+*/
 enum reportTypes { TX_LOG, RX_LOG, RX_ALL_LOG };
 
 void logAirtime(reportTypes reportType, uint32_t airtime_ms);
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index c8159745..f4ceeded 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -58,7 +58,6 @@ void INTERRUPT_ATTR RadioLibInterface::isrTxLevel0()
  */
 RadioLibInterface *RadioLibInterface::instance;
 
-
 /** Could we send right now (i.e. either not actively receving or transmitting)? */
 bool RadioLibInterface::canSendImmediately()
 {
@@ -88,7 +87,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
     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, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
 
@@ -100,7 +98,6 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
     // Count the packet toward our TX airtime utilization.
     //   We only count it if it can be added to the TX queue.
     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
@@ -211,12 +208,16 @@ void RadioLibInterface::completeSending()
 
 void RadioLibInterface::handleReceiveInterrupt()
 {
+    uint32_t xmitMsec;
     assert(isReceiving);
     isReceiving = false;
 
     // read the number of actually received bytes
     size_t length = iface->getPacketLength();
 
+    xmitMsec = getPacketTime(length);
+    logAirtime(RX_ALL_LOG, xmitMsec);
+
     int state = iface->readData(radiobuf, length);
     if (state != ERR_NONE) {
         DEBUG_MSG("ignoring received packet due to error=%d\n", state);
@@ -256,11 +257,14 @@ void RadioLibInterface::handleReceiveInterrupt()
 
             printPacket("Lora RX", mp);
 
+            xmitMsec = getPacketTime(mp);
+            logAirtime(RX_LOG, xmitMsec);
+
             deliverToReceiver(mp);
         }
     }
 }
- 
+
 /** start an immediate transmit */
 void RadioLibInterface::startSend(MeshPacket *txp)
 {

From 6e4cf22cf0251cc93d1fb083d8774da99e53c6ba Mon Sep 17 00:00:00 2001
From: Jm Casler 
Date: Sun, 27 Dec 2020 09:49:23 -0800
Subject: [PATCH 06/10] Accidently checked in my platform.ini

---
 platformio.ini | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/platformio.ini b/platformio.ini
index 14e6ddbd..50d381c8 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -38,8 +38,8 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n
 ;upload_port = /dev/ttyUSB0
 ;monitor_port = /dev/ttyUSB0
 
-upload_port = /dev/cu.SLAB_USBtoUART
-monitor_port = /dev/cu.SLAB_USBtoUART
+;upload_port = /dev/cu.SLAB_USBtoUART
+;monitor_port = /dev/cu.SLAB_USBtoUART
 
 ; the default is esptool
 ; upload_protocol = esp-prog

From 15a0b3694dff71bbdc32edd46896ab1901403437 Mon Sep 17 00:00:00 2001
From: Jm 
Date: Sun, 27 Dec 2020 10:50:52 -0800
Subject: [PATCH 07/10] Update to #588 - Change "hour" to "period"

---
 src/airtime.cpp           | 69 ++++++++++++++++++++-------------------
 src/airtime.h             |  8 +++--
 src/meshwifi/meshhttp.cpp | 15 +++++----
 3 files changed, 49 insertions(+), 43 deletions(-)

diff --git a/src/airtime.cpp b/src/airtime.cpp
index 82f0d3bf..ec0bf8c8 100644
--- a/src/airtime.cpp
+++ b/src/airtime.cpp
@@ -1,47 +1,41 @@
 #include "airtime.h"
 #include 
 
-#define hoursToLog 48
+#define periodsToLog 48
 
 // A reminder that there are 3600 seconds in an hour so I don't have
 // to keep googling it.
 //   This can be changed to a smaller number to speed up testing.
 //
-uint16_t secondsPerHour = 3600;
+uint32_t secondsPerPeriod = 3600;
 uint32_t lastMillis = 0;
 uint32_t secSinceBoot = 0;
 
 // Don't read out of this directly. Use the helper functions.
 struct airtimeStruct {
-    uint16_t hourTX[hoursToLog];
-    uint16_t hourRX[hoursToLog];
-    uint16_t hourRX_ALL[hoursToLog];
-    uint8_t lastHourIndex;
+    uint16_t periodTX[periodsToLog];
+    uint16_t periodRX[periodsToLog];
+    uint16_t periodRX_ALL[periodsToLog];
+    uint8_t lastPeriodIndex;
 } airtimes;
 
 void logAirtime(reportTypes reportType, uint32_t airtime_ms)
 {
 
     if (reportType == TX_LOG) {
-        airtimes.hourTX[0] = airtimes.hourTX[0] + round(airtime_ms / 1000);
+        airtimes.periodTX[0] = airtimes.periodTX[0] + round(airtime_ms / 1000);
     } else if (reportType == RX_LOG) {
-        airtimes.hourRX[0] = airtimes.hourRX[0] + round(airtime_ms / 1000);
+        airtimes.periodRX[0] = airtimes.periodRX[0] + round(airtime_ms / 1000);
     } else if (reportType == RX_ALL_LOG) {
-        airtimes.hourRX_ALL[0] = airtimes.hourRX_ALL[0] + round(airtime_ms / 1000);
+        airtimes.periodRX_ALL[0] = airtimes.periodRX_ALL[0] + round(airtime_ms / 1000);
     } else {
         // Unknown report type
     }
 }
 
-uint32_t getSecondsSinceBoot()
+uint8_t currentPeriodIndex()
 {
-    return secSinceBoot;
-}
-
-uint8_t currentHourIndex()
-{
-    // return ((secondsSinceBoot() - (secondsSinceBoot() / (hoursToLog * secondsPerHour))) / secondsPerHour);
-    return ((getSecondsSinceBoot() / secondsPerHour) % hoursToLog);
+    return ((getSecondsSinceBoot() / secondsPerPeriod) % periodsToLog);
 }
 
 void airtimeCalculator()
@@ -49,18 +43,17 @@ void airtimeCalculator()
     if (millis() - lastMillis > 1000) {
         lastMillis = millis();
         secSinceBoot++;
-        // DEBUG_MSG("------- lastHourIndex %i currentHourIndex %i\n", airtimes.lastHourIndex, currentHourIndex());
-        if (airtimes.lastHourIndex != currentHourIndex()) {
-            for (int i = hoursToLog - 2; i >= 0; --i) {
-                airtimes.hourTX[i + 1] = airtimes.hourTX[i];
-                airtimes.hourRX[i + 1] = airtimes.hourRX[i];
-                airtimes.hourRX_ALL[i + 1] = airtimes.hourRX_ALL[i];
+        if (airtimes.lastPeriodIndex != currentPeriodIndex()) {
+            for (int i = periodsToLog - 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];
             }
-            airtimes.hourTX[0] = 0;
-            airtimes.hourRX[0] = 0;
-            airtimes.hourRX_ALL[0] = 0;
+            airtimes.periodTX[0] = 0;
+            airtimes.periodRX[0] = 0;
+            airtimes.periodRX_ALL[0] = 0;
 
-            airtimes.lastHourIndex = currentHourIndex();
+            airtimes.lastPeriodIndex = currentPeriodIndex();
         }
     }
 }
@@ -70,16 +63,26 @@ uint16_t *airtimeReport(reportTypes reportType)
     // currentHourIndexReset();
 
     if (reportType == TX_LOG) {
-        return airtimes.hourTX;
+        return airtimes.periodTX;
     } else if (reportType == RX_LOG) {
-        return airtimes.hourRX;
+        return airtimes.periodRX;
     } else if (reportType == RX_ALL_LOG) {
-        return airtimes.hourRX_ALL;
+        return airtimes.periodRX_ALL;
     }
     return 0;
 }
 
-uint8_t getHoursToLog()
+uint8_t getPeriodsToLog()
 {
-    return hoursToLog;
-}
\ No newline at end of file
+    return periodsToLog;
+}
+
+uint32_t getSecondsPerPeriod()
+{
+    return secondsPerPeriod;
+}
+
+uint32_t getSecondsSinceBoot()
+{
+    return secSinceBoot;
+}
diff --git a/src/airtime.h b/src/airtime.h
index 482ab394..4cfbb82c 100644
--- a/src/airtime.h
+++ b/src/airtime.h
@@ -28,9 +28,11 @@ void logAirtime(reportTypes reportType, uint32_t airtime_ms);
 
 void airtimeCalculator();
 
-uint8_t currentHourIndex();
-uint8_t getHoursToLog();
+uint8_t currentPeriodIndex();
+uint8_t getPeriodsToLog();
 
 uint32_t getSecondsSinceBoot();
 
-uint16_t *airtimeReport(reportTypes reportType);
\ No newline at end of file
+uint16_t *airtimeReport(reportTypes reportType);
+
+uint32_t getSecondsPerPeriod();
\ No newline at end of file
diff --git a/src/meshwifi/meshhttp.cpp b/src/meshwifi/meshhttp.cpp
index e24f6717..851499a0 100644
--- a/src/meshwifi/meshhttp.cpp
+++ b/src/meshwifi/meshhttp.cpp
@@ -1075,11 +1075,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
     res->print("\"tx_log\": [");
 
     logArray = airtimeReport(TX_LOG);
-    for (int i = 0; i < getHoursToLog(); i++) {
+    for (int i = 0; i < getPeriodsToLog(); i++) {
         uint16_t tmp;
         tmp = *(logArray + i);
         res->printf("%d", tmp);
-        if (i != getHoursToLog() - 1) {
+        if (i != getPeriodsToLog() - 1) {
             res->print(", ");
         }
     }
@@ -1088,11 +1088,11 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
     res->print("\"rx_log\": [");
 
     logArray = airtimeReport(RX_LOG);
-    for (int i = 0; i < getHoursToLog(); i++) {
+    for (int i = 0; i < getPeriodsToLog(); i++) {
         uint16_t tmp;
         tmp = *(logArray + i);
         res->printf("%d", tmp);
-        if (i != getHoursToLog() - 1) {
+        if (i != getPeriodsToLog() - 1) {
             res->print(", ");
         }
     }
@@ -1101,18 +1101,19 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
     res->print("\"rx_all_log\": [");
 
     logArray = airtimeReport(RX_ALL_LOG);
-    for (int i = 0; i < getHoursToLog(); i++) {
+    for (int i = 0; i < getPeriodsToLog(); i++) {
         uint16_t tmp;
         tmp = *(logArray + i);
         res->printf("%d", tmp);
-        if (i != getHoursToLog() - 1) {
+        if (i != getPeriodsToLog() - 1) {
             res->print(", ");
         }
     }
 
     res->println("],");
     res->printf("\"seconds_since_boot\": %u,\n", getSecondsSinceBoot());
-    res->printf("\"hours_to_log\": %u\n", getHoursToLog());
+    res->printf("\"seconds_per_period\": %u,\n", getSecondsPerPeriod());
+    res->printf("\"periods_to_log\": %u\n", getPeriodsToLog());
 
     res->println("},");
 

From 621306e610fe3490ce0ec2b8cc3ae95a5cf0c20f Mon Sep 17 00:00:00 2001
From: Jm 
Date: Sun, 27 Dec 2020 15:03:32 -0800
Subject: [PATCH 08/10] Add IP address and rssi to /json/report

---
 platformio.ini            |  4 ++--
 src/meshwifi/meshhttp.cpp | 16 ++++++++++++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/platformio.ini b/platformio.ini
index 50d381c8..14e6ddbd 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -38,8 +38,8 @@ build_flags = -Wno-missing-field-initializers -Isrc -Isrc/mesh -Isrc/gps -Ilib/n
 ;upload_port = /dev/ttyUSB0
 ;monitor_port = /dev/ttyUSB0
 
-;upload_port = /dev/cu.SLAB_USBtoUART
-;monitor_port = /dev/cu.SLAB_USBtoUART
+upload_port = /dev/cu.SLAB_USBtoUART
+monitor_port = /dev/cu.SLAB_USBtoUART
 
 ; the default is esptool
 ; upload_protocol = esp-prog
diff --git a/src/meshwifi/meshhttp.cpp b/src/meshwifi/meshhttp.cpp
index 851499a0..d6d2e22b 100644
--- a/src/meshwifi/meshhttp.cpp
+++ b/src/meshwifi/meshhttp.cpp
@@ -1117,8 +1117,20 @@ void handleReport(HTTPRequest *req, HTTPResponse *res)
 
     res->println("},");
 
-    res->println("\"something\": 123,");
-    res->println("\"something_else\": 123");
+    res->println("\"wifi\": {");
+
+    res->println("\"rssi\": " + String(WiFi.RSSI()) + ",");
+
+    if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) {
+        res->println("\"ip\": \"" + String(WiFi.softAPIP().toString().c_str()) + "\"");
+    } else {
+        res->println("\"ip\": \"" + String(WiFi.localIP().toString().c_str()) + "\"");
+    }
+
+
+    res->println("},");
+
+    res->println("\"test\": 123");
 
     res->println("},");
 

From 997ed283bffdd078f43cc5174aa6703d7a79519a Mon Sep 17 00:00:00 2001
From: Jm 
Date: Mon, 28 Dec 2020 01:12:42 -0800
Subject: [PATCH 09/10] #601 - tbeam draws too much power from USB port

---
 src/Power.cpp | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/Power.cpp b/src/Power.cpp
index ba908e3f..3d185cb2 100644
--- a/src/Power.cpp
+++ b/src/Power.cpp
@@ -268,7 +268,9 @@ bool Power::axp192Init()
             DEBUG_MSG("DCDC3: %s\n", axp.isDCDC3Enable() ? "ENABLE" : "DISABLE");
             DEBUG_MSG("Exten: %s\n", axp.isExtenEnable() ? "ENABLE" : "DISABLE");
 
-            axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
+            //axp.setChargeControlCur(AXP1XX_CHARGE_CUR_1320MA); // actual limit (in HW) on the tbeam is 450mA
+            axp.setChargeControlCur(AXP1XX_CHARGE_CUR_450MA); // There's no HW limit on the tbeam. Setting to 450mz to be a good neighbor on the usb bus.
+            
 #if 0
 
       // Not connected

From 698102371f39209496fcfc33450fc2aa2290acea Mon Sep 17 00:00:00 2001
From: Tobias Schwarz 
Date: Mon, 28 Dec 2020 11:20:43 +0100
Subject: [PATCH 10/10] case with large gps antenna option

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 851a1b2e..bd914356 100644
--- a/README.md
+++ b/README.md
@@ -32,6 +32,7 @@ We currently support three models of radios.
   - 3D printable cases
     - [T-Beam V0](https://www.thingiverse.com/thing:3773717) (GPS and LoRa antenna misaligned if GPS placed as pictured)
     - [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:3830711)
+    - [T-Beam V1 (SMA-antenna)](https://www.thingiverse.com/thing:4677388) (Mounting option for larger GPS antenna but LoRa antenna enclosed)
     - [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4587297) (GPS and LoRa antenna misaligned if GPS placed as pictured)
     - [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4589651)
     - [T-Beam V1 (IPEX-antenna)](https://www.thingiverse.com/thing:4619981) (GPS and LoRa antenna misaligned if GPS placed as pictured)