mirror of
https://github.com/meshtastic/firmware.git
synced 2025-05-01 03:39:18 +00:00
Merge pull request #1998 from GUVWAF/dutyCycleLimit
Completely refrain from transmitting if duty cycle limit exceeded
This commit is contained in:
commit
0dff05e881
@ -117,6 +117,20 @@ float AirTime::utilizationTXPercent()
|
|||||||
return (float(sum) / float(MS_IN_HOUR)) * 100;
|
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({}) {
|
AirTime::AirTime() : concurrency::OSThread("AirTime"),airtimes({}) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#define PERIODS_TO_LOG 8
|
#define PERIODS_TO_LOG 8
|
||||||
#define MINUTES_IN_HOUR 60
|
#define MINUTES_IN_HOUR 60
|
||||||
#define SECONDS_IN_MINUTE 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)
|
#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 getSecondsPerPeriod();
|
||||||
uint32_t getSecondsSinceBoot();
|
uint32_t getSecondsSinceBoot();
|
||||||
uint32_t *airtimeReport(reportTypes reportType);
|
uint32_t *airtimeReport(reportTypes reportType);
|
||||||
|
uint8_t getSilentMinutes(float txPercent, float dutyCycle);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool firstTime = true;
|
bool firstTime = true;
|
||||||
|
@ -162,6 +162,7 @@ void NodeDB::installDefaultConfig()
|
|||||||
config.has_network = true;
|
config.has_network = true;
|
||||||
config.has_bluetooth = 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.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.region = Config_LoRaConfig_RegionCode_UNSET;
|
||||||
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST;
|
config.lora.modem_preset = Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||||
config.lora.hop_limit = HOP_RELIABLE;
|
config.lora.hop_limit = HOP_RELIABLE;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "Channels.h"
|
#include "Channels.h"
|
||||||
#include "CryptoEngine.h"
|
#include "CryptoEngine.h"
|
||||||
#include "NodeDB.h"
|
#include "NodeDB.h"
|
||||||
|
#include "MeshRadio.h"
|
||||||
#include "RTC.h"
|
#include "RTC.h"
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@ -187,6 +188,18 @@ ErrorCode Router::send(MeshPacket *p)
|
|||||||
{
|
{
|
||||||
assert(p->to != nodeDB.getNodeNum()); // should have already been handled by sendLocal
|
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;
|
// 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(!nakId); // I don't think we ever send 0hop naks over the wire (other than to the phone), test that assumption with
|
||||||
// assert
|
// assert
|
||||||
|
@ -54,7 +54,7 @@ extern const pb_msgdesc_t ChannelSet_msg;
|
|||||||
#define ChannelSet_fields &ChannelSet_msg
|
#define ChannelSet_fields &ChannelSet_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define ChannelSet_size 582
|
#define ChannelSet_size 584
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
@ -126,6 +126,7 @@ typedef struct _Config_LoRaConfig {
|
|||||||
bool tx_enabled;
|
bool tx_enabled;
|
||||||
int8_t tx_power;
|
int8_t tx_power;
|
||||||
uint16_t channel_num;
|
uint16_t channel_num;
|
||||||
|
bool override_duty_cycle;
|
||||||
pb_size_t ignore_incoming_count;
|
pb_size_t ignore_incoming_count;
|
||||||
uint32_t ignore_incoming[3];
|
uint32_t ignore_incoming[3];
|
||||||
} Config_LoRaConfig;
|
} Config_LoRaConfig;
|
||||||
@ -235,7 +236,7 @@ extern "C" {
|
|||||||
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
#define Config_NetworkConfig_init_default {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_default}
|
||||||
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
#define Config_NetworkConfig_IpV4Config_init_default {0, 0, 0, 0}
|
||||||
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
|
#define Config_DisplayConfig_init_default {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
|
||||||
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
#define Config_LoRaConfig_init_default {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||||
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
#define Config_BluetoothConfig_init_default {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||||
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
|
#define Config_init_zero {0, {Config_DeviceConfig_init_zero}}
|
||||||
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
#define Config_DeviceConfig_init_zero {_Config_DeviceConfig_Role_MIN, 0, 0, 0, 0}
|
||||||
@ -244,7 +245,7 @@ extern "C" {
|
|||||||
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
#define Config_NetworkConfig_init_zero {0, "", "", "", 0, _Config_NetworkConfig_EthMode_MIN, false, Config_NetworkConfig_IpV4Config_init_zero}
|
||||||
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
#define Config_NetworkConfig_IpV4Config_init_zero {0, 0, 0, 0}
|
||||||
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
|
#define Config_DisplayConfig_init_zero {0, _Config_DisplayConfig_GpsCoordinateFormat_MIN, 0, 0, 0, _Config_DisplayConfig_DisplayUnits_MIN, _Config_DisplayConfig_OledType_MIN}
|
||||||
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, {0, 0, 0}}
|
#define Config_LoRaConfig_init_zero {0, _Config_LoRaConfig_ModemPreset_MIN, 0, 0, 0, 0, _Config_LoRaConfig_RegionCode_MIN, 0, 0, 0, 0, 0, 0, {0, 0, 0}}
|
||||||
#define Config_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
#define Config_BluetoothConfig_init_zero {0, _Config_BluetoothConfig_PairingMode_MIN, 0}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
@ -274,6 +275,7 @@ extern "C" {
|
|||||||
#define Config_LoRaConfig_tx_enabled_tag 9
|
#define Config_LoRaConfig_tx_enabled_tag 9
|
||||||
#define Config_LoRaConfig_tx_power_tag 10
|
#define Config_LoRaConfig_tx_power_tag 10
|
||||||
#define Config_LoRaConfig_channel_num_tag 11
|
#define Config_LoRaConfig_channel_num_tag 11
|
||||||
|
#define Config_LoRaConfig_override_duty_cycle_tag 12
|
||||||
#define Config_LoRaConfig_ignore_incoming_tag 103
|
#define Config_LoRaConfig_ignore_incoming_tag 103
|
||||||
#define Config_NetworkConfig_IpV4Config_ip_tag 1
|
#define Config_NetworkConfig_IpV4Config_ip_tag 1
|
||||||
#define Config_NetworkConfig_IpV4Config_gateway_tag 2
|
#define Config_NetworkConfig_IpV4Config_gateway_tag 2
|
||||||
@ -407,6 +409,7 @@ X(a, STATIC, SINGULAR, UINT32, hop_limit, 8) \
|
|||||||
X(a, STATIC, SINGULAR, BOOL, tx_enabled, 9) \
|
X(a, STATIC, SINGULAR, BOOL, tx_enabled, 9) \
|
||||||
X(a, STATIC, SINGULAR, INT32, tx_power, 10) \
|
X(a, STATIC, SINGULAR, INT32, tx_power, 10) \
|
||||||
X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \
|
X(a, STATIC, SINGULAR, UINT32, channel_num, 11) \
|
||||||
|
X(a, STATIC, SINGULAR, BOOL, override_duty_cycle, 12) \
|
||||||
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
|
X(a, STATIC, REPEATED, UINT32, ignore_incoming, 103)
|
||||||
#define Config_LoRaConfig_CALLBACK NULL
|
#define Config_LoRaConfig_CALLBACK NULL
|
||||||
#define Config_LoRaConfig_DEFAULT NULL
|
#define Config_LoRaConfig_DEFAULT NULL
|
||||||
@ -443,7 +446,7 @@ extern const pb_msgdesc_t Config_BluetoothConfig_msg;
|
|||||||
#define Config_BluetoothConfig_size 10
|
#define Config_BluetoothConfig_size 10
|
||||||
#define Config_DeviceConfig_size 18
|
#define Config_DeviceConfig_size 18
|
||||||
#define Config_DisplayConfig_size 22
|
#define Config_DisplayConfig_size 22
|
||||||
#define Config_LoRaConfig_size 68
|
#define Config_LoRaConfig_size 70
|
||||||
#define Config_NetworkConfig_IpV4Config_size 20
|
#define Config_NetworkConfig_IpV4Config_size 20
|
||||||
#define Config_NetworkConfig_size 161
|
#define Config_NetworkConfig_size 161
|
||||||
#define Config_PositionConfig_size 42
|
#define Config_PositionConfig_size 42
|
||||||
|
@ -150,7 +150,7 @@ extern const pb_msgdesc_t LocalModuleConfig_msg;
|
|||||||
#define LocalModuleConfig_fields &LocalModuleConfig_msg
|
#define LocalModuleConfig_fields &LocalModuleConfig_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
#define LocalConfig_size 385
|
#define LocalConfig_size 387
|
||||||
#define LocalModuleConfig_size 361
|
#define LocalModuleConfig_size 361
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -185,9 +185,11 @@ typedef enum _Routing_Error {
|
|||||||
/* TODO: REPLACE */
|
/* TODO: REPLACE */
|
||||||
Routing_Error_NO_RESPONSE = 8,
|
Routing_Error_NO_RESPONSE = 8,
|
||||||
/* TODO: REPLACE */
|
/* TODO: REPLACE */
|
||||||
Routing_Error_BAD_REQUEST = 32,
|
Routing_Error_DUTY_CYCLE_LIMIT = 9,
|
||||||
/* The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37.
|
/* The new version of the heltec WiFi_Lora_32_V2 board that has battery sensing hooked to GPIO 37.
|
||||||
Sadly they did not update anything on the silkscreen to identify this board */
|
Sadly they did not update anything on the silkscreen to identify this board */
|
||||||
|
Routing_Error_BAD_REQUEST = 32,
|
||||||
|
/* Ancient heltec WiFi_Lora_32 board */
|
||||||
Routing_Error_NOT_AUTHORIZED = 33
|
Routing_Error_NOT_AUTHORIZED = 33
|
||||||
} Routing_Error;
|
} Routing_Error;
|
||||||
|
|
||||||
|
@ -192,6 +192,7 @@ bool AdminModule::handleReceivedProtobuf(const MeshPacket &mp, AdminMessage *r)
|
|||||||
void AdminModule::handleSetOwner(const User &o)
|
void AdminModule::handleSetOwner(const User &o)
|
||||||
{
|
{
|
||||||
int changed = 0;
|
int changed = 0;
|
||||||
|
bool licensed_changed = false;
|
||||||
|
|
||||||
if (*o.long_name) {
|
if (*o.long_name) {
|
||||||
changed |= strcmp(owner.long_name, o.long_name);
|
changed |= strcmp(owner.long_name, o.long_name);
|
||||||
@ -207,12 +208,14 @@ void AdminModule::handleSetOwner(const User &o)
|
|||||||
}
|
}
|
||||||
if (owner.is_licensed != o.is_licensed) {
|
if (owner.is_licensed != o.is_licensed) {
|
||||||
changed = 1;
|
changed = 1;
|
||||||
|
licensed_changed = true;
|
||||||
owner.is_licensed = o.is_licensed;
|
owner.is_licensed = o.is_licensed;
|
||||||
|
config.lora.override_duty_cycle = owner.is_licensed; // override duty cycle for licensed operators
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
|
if (changed) { // If nothing really changed, don't broadcast on the network or write to flash
|
||||||
service.reloadOwner(!hasOpenEditTransaction);
|
service.reloadOwner(!hasOpenEditTransaction);
|
||||||
saveChanges(SEGMENT_DEVICESTATE);
|
licensed_changed ? saveChanges(SEGMENT_CONFIG | SEGMENT_DEVICESTATE) : saveChanges(SEGMENT_DEVICESTATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user