From d63bba36e9df7f8e5b08312e053be9cfa253a800 Mon Sep 17 00:00:00 2001 From: elwimen Date: Tue, 17 Mar 2026 17:58:59 +0100 Subject: [PATCH] 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. --- src/DisplayFormatters.cpp | 3 ++- src/graphics/draw/DebugRenderer.cpp | 12 ++++++++++-- src/modules/AdminModule.cpp | 27 +++++++++++++++------------ 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/DisplayFormatters.cpp b/src/DisplayFormatters.cpp index d88f9fc9f..fdcf840dc 100644 --- a/src/DisplayFormatters.cpp +++ b/src/DisplayFormatters.cpp @@ -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"; } diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 2069c71ec..d1ec3e997 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -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); diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 6ffde70db..89f31a708 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -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