From 3b1e34efa13f4ee3813426b39b9ad636e9e23ffa Mon Sep 17 00:00:00 2001 From: GUVWAF Date: Sat, 26 Nov 2022 20:50:00 +0100 Subject: [PATCH] Refrain from transmitting if duty cycle exceeded --- src/airtime.cpp | 14 ++++++++++++++ src/airtime.h | 2 ++ src/mesh/NodeDB.cpp | 1 + src/mesh/Router.cpp | 13 +++++++++++++ 4 files changed, 30 insertions(+) diff --git a/src/airtime.cpp b/src/airtime.cpp index fed4ef8aa..1c2fb3233 100644 --- a/src/airtime.cpp +++ b/src/airtime.cpp @@ -117,6 +117,20 @@ float AirTime::utilizationTXPercent() return (float(sum) / float(MS_IN_HOUR)) * 100; } +// Get the amount of minutes we have to be silent before we can send again +uint8_t AirTime::getSilentMinutes(float txPercent, float dutyCycle) +{ + float newTxPercent = txPercent; + for (int8_t i = MINUTES_IN_HOUR-1; i >= 0; --i) { + newTxPercent -= ((float)this->utilizationTX[i] / (MS_IN_MINUTE * MINUTES_IN_HOUR / 100)); + if (newTxPercent < dutyCycle) + return MINUTES_IN_HOUR-1-i; + } + + return MINUTES_IN_HOUR; +} + + AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) { } diff --git a/src/airtime.h b/src/airtime.h index f6b9bdcb5..3f38f39f8 100644 --- a/src/airtime.h +++ b/src/airtime.h @@ -29,6 +29,7 @@ #define PERIODS_TO_LOG 8 #define MINUTES_IN_HOUR 60 #define SECONDS_IN_MINUTE 60 +#define MS_IN_MINUTE (SECONDS_IN_MINUTE * 1000) #define MS_IN_HOUR (MINUTES_IN_HOUR * SECONDS_IN_MINUTE * 1000) @@ -57,6 +58,7 @@ class AirTime : private concurrency::OSThread uint32_t getSecondsPerPeriod(); uint32_t getSecondsSinceBoot(); uint32_t *airtimeReport(reportTypes reportType); + uint8_t getSilentMinutes(float txPercent, float dutyCycle); private: bool firstTime = true; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 6b2d5bfb3..c30542def 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -162,6 +162,7 @@ void NodeDB::installDefaultConfig() config.has_network = true; config.has_bluetooth = true; config.lora.tx_enabled = true; // FIXME: maybe false in the future, and setting region to enable it. (unset region forces it off) + config.lora.override_duty_cycle = false; config.lora.region = Config_LoRaConfig_RegionCode_UNSET; config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST; config.lora.hop_limit = HOP_RELIABLE; diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index e0746bdd9..fd69aa492 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -2,6 +2,7 @@ #include "Channels.h" #include "CryptoEngine.h" #include "NodeDB.h" +#include "MeshRadio.h" #include "RTC.h" #include "configuration.h" #include "main.h" @@ -188,6 +189,18 @@ ErrorCode Router::send(MeshPacket *p) { assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal + // Abort sending if we are violating the duty cycle + if (!config.lora.override_duty_cycle && myRegion->dutyCycle != 100) { + float hourlyTxPercent = airTime->utilizationTXPercent(); + if (hourlyTxPercent > myRegion->dutyCycle) { + uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle); + DEBUG_MSG("WARNING: Duty cycle limit exceeded. Aborting send for now, you can send again in %d minutes.\n", silentMinutes); + Routing_Error err = Routing_Error_DUTY_CYCLE_LIMIT; + abortSendAndNak(err, p); + return err; + } + } + // PacketId nakId = p->decoded.which_ackVariant == SubPacket_fail_id_tag ? p->decoded.ackVariant.fail_id : 0; // assert(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with // assert