From ded2b86e55fe86545390f9de054475e2c8b31f93 Mon Sep 17 00:00:00 2001 From: Jm Casler Date: Fri, 25 Dec 2020 16:10:38 -0800 Subject: [PATCH] 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 1fec1e0cb..8f0f20f17 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 65edbd207..5df916a5e 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 e5253d7a3..b76d30353 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 9a5ec536c..c8159745a 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);