Skip to content

Commit 22d63fa

Browse files
NomDeTomCopilot
andauthored
Lora settings expansion and validation logic improvement (#9878)
* Enhance LoRa configuration with modem presets and validation logic * Rename bootstrapLoRaConfigFromPreset tests to validateModemConfig for clarity and consistency * additional tidy-ups to the validateModemConfig - still fundamentally broken at this point * Enhance region validation by adding numPresets to RegionInfo and implementing validateRegionConfig in RadioInterface * Add validation for modem configuration in applyModemConfig * Fix region unset handling and improve modem config validation in handleSetConfig * Refactor LoRa configuration validation methods and introduce clamping method for invalid settings * Update handleSetConfig to use fromOthers parameter to either correct or reject invalid settings * Fix some of the copilot review comments for LoRa configuration validation and clamping methods; add tests for region and preset handling * Redid the slot default checking and calculation. Should resolve the outstanding comments. * Add bandwidth calculation for LoRa modem preset fallback in clampConfigLora * Remove unused preset name variable in validateConfigLora and fix default frequency slot check in applyModemConfig * update tests for region handling * Got the synthetic colleague to add mock service for testing * Flash savings... hopefully * Refactor modem preset handling to use sentinel values and improve default preset retrieval * Refactor region handling to use profile structures for modem presets and channel calculations * added comments for clarity on parameters * Add shadow table tests and validateConfigLora enhancements for region presets * Add isFromUs tests for preset validation in AdminModule * Respond to copilot github review * address copilot comments * address null poointers * fix build errors * Fix the fix, undo the silly suggestions from synthetic reviewer. * we all float here * Fix include path for AdminModule in test_main.cpp * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * More suggestion fixes * admin module merge conflicts * admin module fixes from merge hell * fix: initialize default frequency slot and custom channel name; update LNA mode handling * save some bytes... * fix: simplify error logging for bandwidth checks in LoRa configuration * Update src/mesh/MeshRadio.h Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent fc030d2 commit 22d63fa

File tree

11 files changed

+1350
-247
lines changed

11 files changed

+1350
-247
lines changed

src/graphics/draw/MenuHandler.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "modules/TraceRouteModule.h"
2626
#include <algorithm>
2727
#include <array>
28+
#include <cmath>
2829
#include <functional>
2930
#include <utility>
3031

@@ -265,13 +266,24 @@ void menuHandler::FrequencySlotPicker()
265266
optionsEnumArray[options++] = 0;
266267

267268
// Calculate number of channels (copied from RadioInterface::applyModemConfig())
269+
268270
meshtastic_Config_LoRaConfig &loraConfig = config.lora;
269271
double bw = loraConfig.use_preset ? modemPresetToBwKHz(loraConfig.modem_preset, myRegion->wideLora)
270272
: bwCodeToKHz(loraConfig.bandwidth);
271273

272274
uint32_t numChannels = 0;
273275
if (myRegion) {
274-
numChannels = (uint32_t)floor((myRegion->freqEnd - myRegion->freqStart) / (myRegion->spacing + (bw / 1000.0)));
276+
// Match RadioInterface::applyModemConfig(): include padding, add spacing in numerator, and use round()
277+
const double spacing = myRegion->profile->spacing;
278+
const double padding = myRegion->profile->padding;
279+
const double channelBandwidthMHz = bw / 1000.0;
280+
const double numerator = (myRegion->freqEnd - myRegion->freqStart) + spacing;
281+
const double denominator = spacing + (padding * 2) + channelBandwidthMHz;
282+
if (denominator > 0.0) {
283+
numChannels = static_cast<uint32_t>(round(numerator / denominator));
284+
} else {
285+
LOG_WARN("Invalid region configuration: non-positive channel spacing/width");
286+
}
275287
} else {
276288
LOG_WARN("Region not set, cannot calculate number of channels");
277289
return;

src/mesh/MeshRadio.h

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,52 @@
55
#include "PointerQueue.h"
66
#include "configuration.h"
77

8+
// Sentinel marking the end of a modem preset array
9+
static constexpr meshtastic_Config_LoRaConfig_ModemPreset MODEM_PRESET_END =
10+
static_cast<meshtastic_Config_LoRaConfig_ModemPreset>(0xFF);
11+
12+
// Region profile: bundles the preset list with regulatory parameters shared across regions
13+
struct RegionProfile {
14+
const meshtastic_Config_LoRaConfig_ModemPreset *presets; // sentinel-terminated; first entry is the default
15+
float spacing; // gaps between radio channels
16+
float padding; // padding at each side of the "operating channel"
17+
bool audioPermitted;
18+
bool licensedOnly; // a region profile for licensed operators only
19+
int8_t textThrottle; // throttle for text - future expansion
20+
int8_t positionThrottle; // throttle for location data - future expansion
21+
int8_t telemetryThrottle; // throttle for telemetry - future expansion
22+
uint8_t overrideSlot; // a per-region override slot for if we need to fix it in place
23+
};
24+
25+
extern const RegionProfile PROFILE_STD;
26+
extern const RegionProfile PROFILE_EU868;
27+
extern const RegionProfile PROFILE_UNDEF;
28+
// extern const RegionProfile PROFILE_LITE;
29+
// extern const RegionProfile PROFILE_NARROW;
30+
// extern const RegionProfile PROFILE_HAM;
31+
832
// Map from old region names to new region enums
933
struct RegionInfo {
1034
meshtastic_Config_LoRaConfig_RegionCode code;
1135
float freqStart;
1236
float freqEnd;
13-
float dutyCycle;
14-
float spacing;
37+
float dutyCycle; // modified by getEffectiveDutyCycle
1538
uint8_t powerLimit; // Or zero for not set
16-
bool audioPermitted;
1739
bool freqSwitching;
1840
bool wideLora;
41+
const RegionProfile *profile;
1942
const char *name; // EU433 etc
43+
44+
// Preset accessors (delegate through profile)
45+
meshtastic_Config_LoRaConfig_ModemPreset getDefaultPreset() const { return profile->presets[0]; }
46+
const meshtastic_Config_LoRaConfig_ModemPreset *getAvailablePresets() const { return profile->presets; }
47+
size_t getNumPresets() const
48+
{
49+
size_t n = 0;
50+
while (profile->presets[n] != MODEM_PRESET_END)
51+
n++;
52+
return n;
53+
}
2054
};
2155

2256
extern const RegionInfo regions[];

src/mesh/NodeDB.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1299,7 +1299,7 @@ void NodeDB::loadFromDisk()
12991299
// Coerce LoRa config fields derived from presets while bootstrapping.
13001300
// Some clients/UI components display bandwidth/spread_factor directly from config even in preset mode.
13011301
if (config.has_lora && config.lora.use_preset) {
1302-
RadioInterface::bootstrapLoRaConfigFromPreset(config.lora);
1302+
RadioInterface::clampConfigLora(config.lora);
13031303
}
13041304

13051305
#if defined(USERPREFS_LORA_TX_DISABLED) && USERPREFS_LORA_TX_DISABLED

0 commit comments

Comments
 (0)