fix: apply LoRa config changes live without rebooting

The configChanged observer already calls reconfigure() on all radio
interfaces when LoRa config is saved, which puts the radio in standby,
reprograms all modem parameters (SF, BW, CR, freq, power), and restarts
receive. The reboot was therefore redundant.

This commit:
- Removes the reboot trigger for LoRa config changes in AdminModule
- Rejects LORA_24 region at runtime with BAD_REQUEST if the active radio
  does not support 2.4 GHz, replacing the startup-only reboot-based check
- Moves the BW/SF/CR display formatting into DebugRenderer, keeping
  getModemPresetDisplayName() semantics stable for non-display callers
  (RadioInterface frequency slot hashing, Channels default-channel detection)

Portduino with SimRadio already skipped the reboot via the same reasoning.
This commit is contained in:
elwimen
2026-03-17 23:29:53 +01:00
parent 19d070c284
commit d63bba36e9
3 changed files with 27 additions and 15 deletions
+2 -1
View File
@@ -4,7 +4,8 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
bool usePreset)
{
// If use_preset is false, always return "Custom"
// If use_preset is false, always return "Custom" — callers such as RadioInterface and Channels
// rely on this being a stable literal for channel-name hashing and default-channel detection.
if (!usePreset) {
return "Custom";
}
+10 -2
View File
@@ -408,7 +408,15 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
display->drawString(nameX, getTextPositions(display)[line++], device_role);
// === Third Row: Radio Preset ===
auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, config.lora.use_preset);
// For custom modem settings show the actual parameters; for presets use the preset name.
char modeStr[16];
if (!config.lora.use_preset) {
snprintf(modeStr, sizeof(modeStr), "BW%d-SF%d-CR%d", config.lora.bandwidth, config.lora.spread_factor,
config.lora.coding_rate);
} else {
strncpy(modeStr, DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, false, true), sizeof(modeStr) - 1);
modeStr[sizeof(modeStr) - 1] = '\0';
}
char regionradiopreset[25];
const char *region = myRegion ? myRegion->name : NULL;
@@ -416,7 +424,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x,
if (currentResolution == ScreenResolution::UltraLow) {
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s", region);
} else {
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, mode);
snprintf(regionradiopreset, sizeof(regionradiopreset), "%s/%s", region, modeStr);
}
}
textWidth = display->getStringWidth(regionradiopreset);
+15 -12
View File
@@ -25,6 +25,7 @@
#include "Default.h"
#include "MeshRadio.h"
#include "TypeConversions.h"
#include "mesh/RadioLibInterface.h"
#if !MESHTASTIC_EXCLUDE_MQTT
#include "mqtt/MQTT.h"
@@ -199,7 +200,16 @@ bool AdminModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshta
case meshtastic_AdminMessage_set_config_tag:
LOG_DEBUG("Client set config");
handleSetConfig(r->set_config);
// Reject LORA_24 at runtime if the active radio hardware does not support 2.4 GHz.
if (r->set_config.which_payload_variant == meshtastic_Config_lora_tag &&
r->set_config.payload_variant.lora.region == meshtastic_Config_LoRaConfig_RegionCode_LORA_24
&& RadioLibInterface::instance && !RadioLibInterface::instance->wideLora())
{
LOG_WARN("Radio hardware does not support 2.4 GHz; rejecting LORA_24 region");
myReply = allocErrorResponse(meshtastic_Routing_Error_BAD_REQUEST, &mp);
} else {
handleSetConfig(r->set_config);
}
break;
case meshtastic_AdminMessage_set_module_config_tag:
@@ -768,17 +778,10 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c)
validatedLora.spread_factor = LORA_SF_DEFAULT;
}
// If no lora radio parameters change, don't need to reboot
if (oldLoraConfig.use_preset == validatedLora.use_preset && oldLoraConfig.region == validatedLora.region &&
oldLoraConfig.modem_preset == validatedLora.modem_preset && oldLoraConfig.bandwidth == validatedLora.bandwidth &&
oldLoraConfig.spread_factor == validatedLora.spread_factor &&
oldLoraConfig.coding_rate == validatedLora.coding_rate && oldLoraConfig.tx_power == validatedLora.tx_power &&
oldLoraConfig.frequency_offset == validatedLora.frequency_offset &&
oldLoraConfig.override_frequency == validatedLora.override_frequency &&
oldLoraConfig.channel_num == validatedLora.channel_num &&
oldLoraConfig.sx126x_rx_boosted_gain == validatedLora.sx126x_rx_boosted_gain) {
requiresReboot = false;
}
// LoRa radio changes are applied live via the configChanged observer which calls reconfigure().
// reconfigure() puts the radio in standby, reprograms all modem parameters, and restarts receive.
// sx126x_rx_boosted_gain is only applied during init(), so a reboot is still required for that setting.
requiresReboot = (oldLoraConfig.sx126x_rx_boosted_gain != validatedLora.sx126x_rx_boosted_gain);
#if defined(ARCH_PORTDUINO)
// If running on portduino and using SimRadio, do not require reboot