mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-13 22:32:27 +00:00
Compare commits
2 Commits
cce8cbfe34
...
eu866
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
68f8f3219c | ||
|
|
cd1cc032ed |
@@ -34,6 +34,9 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE:
|
||||
return useShortName ? "LongM" : "LongMod";
|
||||
break;
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_LITE_FAST:
|
||||
return useShortName ? "LiteF" : "LiteFast";
|
||||
break;
|
||||
default:
|
||||
return useShortName ? "Custom" : "Invalid";
|
||||
break;
|
||||
|
||||
@@ -133,11 +133,12 @@ bool AirTime::isTxAllowedChannelUtil(bool polite)
|
||||
|
||||
bool AirTime::isTxAllowedAirUtil()
|
||||
{
|
||||
if (!config.lora.override_duty_cycle && myRegion->dutyCycle < 100) {
|
||||
if (utilizationTXPercent() < myRegion->dutyCycle * polite_duty_cycle_percent / 100) {
|
||||
float effectiveDutyCycle = getEffectiveDutyCycle();
|
||||
if (!config.lora.override_duty_cycle && effectiveDutyCycle < 100) {
|
||||
if (utilizationTXPercent() < effectiveDutyCycle * polite_duty_cycle_percent / 100) {
|
||||
return true;
|
||||
} else {
|
||||
LOG_WARN("TX air util. >%f%%. Skip send", myRegion->dutyCycle * polite_duty_cycle_percent / 100);
|
||||
LOG_WARN("TX air util. >%f%%. Skip send", effectiveDutyCycle * polite_duty_cycle_percent / 100);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,8 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
"KZ_433",
|
||||
"KZ_863",
|
||||
"NP_865",
|
||||
"BR_902"};
|
||||
"BR_902",
|
||||
"EU_866"};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
#if defined(M5STACK_UNITC6L)
|
||||
bannerOptions.message = "LoRa Region";
|
||||
@@ -111,7 +112,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
#endif
|
||||
bannerOptions.durationMs = duration;
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 27;
|
||||
bannerOptions.optionsCount = 28;
|
||||
bannerOptions.InitialSelected = 0;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected != 0 && config.lora.region != _meshtastic_Config_LoRaConfig_RegionCode(selected)) {
|
||||
@@ -141,7 +142,7 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
}
|
||||
config.lora.tx_enabled = true;
|
||||
initRegion();
|
||||
if (myRegion->dutyCycle < 100) {
|
||||
if (getEffectiveDutyCycle() < 100) {
|
||||
config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit
|
||||
}
|
||||
|
||||
@@ -194,8 +195,8 @@ void menuHandler::DeviceRolePicker()
|
||||
|
||||
void menuHandler::RadioPresetPicker()
|
||||
{
|
||||
static const char *optionsArray[] = {"Back", "LongSlow", "LongModerate", "LongFast", "MediumSlow",
|
||||
"MediumFast", "ShortSlow", "ShortFast", "ShortTurbo"};
|
||||
static const char *optionsArray[] = {"Back", "LongSlow", "LongModerate", "LongFast", "MediumSlow",
|
||||
"MediumFast", "ShortSlow", "ShortFast", "ShortTurbo", "LiteFast"};
|
||||
enum optionsNumbers {
|
||||
Back = 0,
|
||||
radiopreset_LongSlow = 1,
|
||||
@@ -205,12 +206,13 @@ void menuHandler::RadioPresetPicker()
|
||||
radiopreset_MediumFast = 5,
|
||||
radiopreset_ShortSlow = 6,
|
||||
radiopreset_ShortFast = 7,
|
||||
radiopreset_ShortTurbo = 8
|
||||
radiopreset_ShortTurbo = 8,
|
||||
radiopreset_LiteFast = 9
|
||||
};
|
||||
BannerOverlayOptions bannerOptions;
|
||||
bannerOptions.message = "Radio Preset";
|
||||
bannerOptions.optionsArrayPtr = optionsArray;
|
||||
bannerOptions.optionsCount = 9;
|
||||
bannerOptions.optionsCount = 10;
|
||||
bannerOptions.bannerCallback = [](int selected) -> void {
|
||||
if (selected == Back) {
|
||||
menuHandler::menuQueue = menuHandler::lora_Menu;
|
||||
@@ -232,6 +234,8 @@ void menuHandler::RadioPresetPicker()
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST;
|
||||
} else if (selected == radiopreset_ShortTurbo) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO;
|
||||
} else if (selected == radiopreset_LiteFast) {
|
||||
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LITE_FAST;
|
||||
}
|
||||
service->reloadConfig(SEGMENT_CONFIG);
|
||||
rebootAtMsec = (millis() + DEFAULT_REBOOT_SECONDS * 1000);
|
||||
|
||||
@@ -22,4 +22,11 @@ struct RegionInfo {
|
||||
extern const RegionInfo regions[];
|
||||
extern const RegionInfo *myRegion;
|
||||
|
||||
extern void initRegion();
|
||||
extern void initRegion();
|
||||
|
||||
/**
|
||||
* Get the effective duty cycle for the current region based on device role.
|
||||
* For EU_866, returns 10% for fixed devices (ROUTER, ROUTER_LATE) and 2.5% for mobile devices.
|
||||
* For other regions, returns the standard duty cycle.
|
||||
*/
|
||||
extern float getEffectiveDutyCycle();
|
||||
@@ -187,6 +187,13 @@ const RegionInfo regions[] = {
|
||||
*/
|
||||
RDEF(BR_902, 902.0f, 907.5f, 100, 0, 30, true, false, false),
|
||||
|
||||
/*
|
||||
EU 866MHz RFID band (ETSI EN 302 208): 4 channels at 865.7/866.3/866.9/867.5 MHz
|
||||
475 kHz gap between channels, 27 dBm, duty cycle 2.5% (mobile) or 10% (fixed)
|
||||
https://www.etsi.org/deliver/etsi_en/302200_302299/302208/03.04.01_60/en_302208v030401p.pdf
|
||||
*/
|
||||
RDEF(EU_866, 865.6375f, 867.5625f, 2.5, 0.475, 27, true, false, false),
|
||||
|
||||
/*
|
||||
2.4 GHZ WLAN Band equivalent. Only for SX128x chips.
|
||||
*/
|
||||
@@ -219,6 +226,23 @@ void initRegion()
|
||||
myRegion = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duty cycle for current region. EU_866: 10% for routers, 2.5% for mobile.
|
||||
*/
|
||||
float getEffectiveDutyCycle()
|
||||
{
|
||||
if (myRegion->code == meshtastic_Config_LoRaConfig_RegionCode_EU_866) {
|
||||
if (config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER ||
|
||||
config.device.role == meshtastic_Config_DeviceConfig_Role_ROUTER_LATE) {
|
||||
return 10.0f;
|
||||
} else {
|
||||
return 2.5f;
|
||||
}
|
||||
}
|
||||
// For all other regions, return the standard duty cycle
|
||||
return myRegion->dutyCycle;
|
||||
}
|
||||
|
||||
/**
|
||||
* ## LoRaWAN for North America
|
||||
|
||||
@@ -518,6 +542,11 @@ void RadioInterface::applyModemConfig()
|
||||
cr = 8;
|
||||
sf = 12;
|
||||
break;
|
||||
case meshtastic_Config_LoRaConfig_ModemPreset_LITE_FAST:
|
||||
bw = 125;
|
||||
cr = 5;
|
||||
sf = 9;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sf = loraConfig.spread_factor;
|
||||
@@ -551,6 +580,19 @@ void RadioInterface::applyModemConfig()
|
||||
// Set to default modem preset
|
||||
loraConfig.use_preset = true;
|
||||
loraConfig.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST;
|
||||
} else if (myRegion->code == meshtastic_Config_LoRaConfig_RegionCode_EU_866 && bw != 125) {
|
||||
static const char *err_string = "EU_866 requires 125kHz bandwidth. Fall back to LiteFast preset";
|
||||
LOG_ERROR(err_string);
|
||||
RECORD_CRITICALERROR(meshtastic_CriticalErrorCode_INVALID_RADIO_SETTING);
|
||||
|
||||
meshtastic_ClientNotification *cn = clientNotificationPool.allocZeroed();
|
||||
cn->level = meshtastic_LogRecord_Level_ERROR;
|
||||
sprintf(cn->message, err_string);
|
||||
service->sendClientNotification(cn);
|
||||
|
||||
// Set to LiteFast preset which is compliant
|
||||
loraConfig.use_preset = true;
|
||||
loraConfig.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LITE_FAST;
|
||||
} else {
|
||||
validConfig = true;
|
||||
}
|
||||
@@ -569,8 +611,9 @@ void RadioInterface::applyModemConfig()
|
||||
// Set final tx_power back onto config
|
||||
loraConfig.tx_power = (int8_t)power; // cppcheck-suppress assignmentAddressToInteger
|
||||
|
||||
// Calculate the number of channels
|
||||
uint32_t numChannels = floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000)));
|
||||
// Calculate number of channels: spacing = gap between channels (0 for continuous spectrum)
|
||||
float channelSpacing = myRegion->spacing + (bw / 1000);
|
||||
uint32_t numChannels = round((myRegion->freqEnd - myRegion->freqStart + myRegion->spacing) / channelSpacing);
|
||||
|
||||
// If user has manually specified a channel num, then use that, otherwise generate one by hashing the name
|
||||
const char *channelName = channels.getName(channels.getPrimaryIndex());
|
||||
@@ -582,11 +625,8 @@ void RadioInterface::applyModemConfig()
|
||||
channel_num ==
|
||||
hash(DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset)) % numChannels;
|
||||
|
||||
// Old frequency selection formula
|
||||
// float freq = myRegion->freqStart + ((((myRegion->freqEnd - myRegion->freqStart) / numChannels) / 2) * channel_num);
|
||||
|
||||
// New frequency selection formula
|
||||
float freq = myRegion->freqStart + (bw / 2000) + (channel_num * (bw / 1000));
|
||||
// Calculate frequency: freqStart is band edge, add half bandwidth to get first channel center
|
||||
float freq = myRegion->freqStart + (bw / 2000) + (channel_num * channelSpacing);
|
||||
|
||||
// override if we have a verbatim frequency
|
||||
if (loraConfig.override_frequency) {
|
||||
|
||||
@@ -294,10 +294,11 @@ ErrorCode Router::send(meshtastic_MeshPacket *p)
|
||||
} // 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 effectiveDutyCycle = getEffectiveDutyCycle();
|
||||
if (!config.lora.override_duty_cycle && effectiveDutyCycle < 100) {
|
||||
float hourlyTxPercent = airTime->utilizationTXPercent();
|
||||
if (hourlyTxPercent > myRegion->dutyCycle) {
|
||||
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, myRegion->dutyCycle);
|
||||
if (hourlyTxPercent > effectiveDutyCycle) {
|
||||
uint8_t silentMinutes = airTime->getSilentMinutes(hourlyTxPercent, effectiveDutyCycle);
|
||||
|
||||
LOG_WARN("Duty cycle limit exceeded. Aborting send for now, you can send again in %d mins", silentMinutes);
|
||||
|
||||
|
||||
@@ -793,7 +793,7 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
|
||||
}
|
||||
config.lora.tx_enabled = true;
|
||||
initRegion();
|
||||
if (myRegion->dutyCycle < 100) {
|
||||
if (getEffectiveDutyCycle() < 100) {
|
||||
config.lora.ignore_mqtt = true; // Ignore MQTT by default if region has a duty cycle limit
|
||||
}
|
||||
// Compare the entire string, we are sure of the length as a topic has never been set
|
||||
|
||||
Reference in New Issue
Block a user