Add MEDIUM_TURBO modem preset (#10988)

* Protobufs

* Wire up MEDIUM_TURBO modem preset

MEDIUM_TURBO (500 kHz, SF9, CR 4/5) already existed in the protobuf enum but
was never wired into firmware, so selecting it silently fell through to the
LONG_FAST default and rendered an "Invalid" display name.

Add its bw/sf/cr mapping (modemPresetToParams), display name (MediumTurbo/MedT),
PRESETS_STD membership (standard regions only — 500 kHz does not fit EU868's
250 kHz band, so it stays out of PRESETS_EU_868 and is rejected/clamped there),
and the MEDIUM SNR-grading bucket. Includes positive coverage in test_radio,
EU868-reject + US-accept coverage in test_admin_radio and test_mesh_beacon,
the STD preset count 9->10, an extended fuzz range, and the client-spec doc.

* Address review feedback on MEDIUM_TURBO tests

- test_mesh_beacon: assert has_mesh_beacon before checking the invalid preset was
  cleared, so the EU868-cleared test can't pass on a dropped message (matches the
  existing SHORT_TURBO test).
- test_fuzz_packets: draw modem presets from _ModemPreset_ARRAYSIZE instead of a
  hard-coded 17 so the fuzz range tracks future enum additions automatically.
This commit is contained in:
Ben Meadors
2026-07-11 08:24:35 -05:00
committed by GitHub
co-authored by GitHub
parent ca833d944c
commit c5355641d3
13 changed files with 129 additions and 25 deletions
+1
View File
@@ -1,5 +1,6 @@
.pio .pio
pio pio
.pio-docker
pio.tar pio.tar
web web
web.tar web.tar
@@ -69,7 +69,7 @@ message LoRaRegionPresetMap {
### 2.3 Why grouped (and the size envelope clients should respect) ### 2.3 Why grouped (and the size envelope clients should respect)
A `FromRadio` packet is capped at **512 bytes** (`MAX_TO_FROM_RADIO_SIZE`). Most regions A `FromRadio` packet is capped at **512 bytes** (`MAX_TO_FROM_RADIO_SIZE`). Most regions
share one identical preset list (the "standard" 9-preset list), so the map is delivered share one identical preset list (the "standard" 10-preset list), so the map is delivered
**grouped**: `groups` holds each _distinct_ preset list once, and `region_groups` maps every **grouped**: `groups` holds each _distinct_ preset list once, and `region_groups` maps every
known region to one of those groups by index. This keeps the encoded size additive known region to one of those groups by index. This keeps the encoded size additive
(`groups` + `region_groups`) rather than multiplicative, well under the cap. (`groups` + `region_groups`) rather than multiplicative, well under the cap.
@@ -247,8 +247,8 @@ indices are assigned in region-table order (first region to use a profile create
so they are stable as listed here: so they are stable as listed here:
| group_index | default_preset | licensed_only | presets | | group_index | default_preset | licensed_only | presets |
| ----------------------- | -------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | | ----------------------- | -------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| 0 (standard) | `LONG_FAST` | false | LONG_FAST, LONG_SLOW, MEDIUM_SLOW, MEDIUM_FAST, SHORT_SLOW, SHORT_FAST, LONG_MODERATE, SHORT_TURBO, LONG_TURBO | | 0 (standard) | `LONG_FAST` | false | LONG_FAST, LONG_SLOW, MEDIUM_SLOW, MEDIUM_FAST, SHORT_SLOW, SHORT_FAST, LONG_MODERATE, SHORT_TURBO, LONG_TURBO, MEDIUM_TURBO |
| 1 (EU 868) | `LONG_FAST` | false | LONG_FAST, LONG_SLOW, MEDIUM_SLOW, MEDIUM_FAST, SHORT_SLOW, SHORT_FAST, LONG_MODERATE | | 1 (EU 868) | `LONG_FAST` | false | LONG_FAST, LONG_SLOW, MEDIUM_SLOW, MEDIUM_FAST, SHORT_SLOW, SHORT_FAST, LONG_MODERATE |
| 2 (EU 866 SRD / "lite") | `LITE_FAST` | false | LITE_FAST, LITE_SLOW | | 2 (EU 866 SRD / "lite") | `LITE_FAST` | false | LITE_FAST, LITE_SLOW |
| 3 (EU 868 narrow) | `NARROW_SLOW` | false | NARROW_FAST, NARROW_SLOW | | 3 (EU 868 narrow) | `NARROW_SLOW` | false | NARROW_FAST, NARROW_SLOW |
+3
View File
@@ -27,6 +27,9 @@ const char *DisplayFormatters::getModemPresetDisplayName(meshtastic_Config_LoRaC
case PRESET(MEDIUM_FAST): case PRESET(MEDIUM_FAST):
return useShortName ? "MedF" : "MediumFast"; return useShortName ? "MedF" : "MediumFast";
break; break;
case PRESET(MEDIUM_TURBO):
return useShortName ? "MedT" : "MediumTurbo";
break;
case PRESET(LONG_SLOW): case PRESET(LONG_SLOW):
return useShortName ? "LongS" : "LongSlow"; return useShortName ? "LongS" : "LongSlow";
break; break;
+1
View File
@@ -844,6 +844,7 @@ void UIRenderer::drawFavoriteNode(OLEDDisplay *display, OLEDDisplayUiState *stat
return -6.0f; return -6.0f;
case PRESET(MEDIUM_SLOW): case PRESET(MEDIUM_SLOW):
case PRESET(MEDIUM_FAST): case PRESET(MEDIUM_FAST):
case PRESET(MEDIUM_TURBO):
return -5.5f; return -5.5f;
case PRESET(SHORT_SLOW): case PRESET(SHORT_SLOW):
case PRESET(SHORT_FAST): case PRESET(SHORT_FAST):
+5
View File
@@ -229,6 +229,11 @@ static inline void modemPresetToParams(meshtastic_Config_LoRaConfig_ModemPreset
cr = 5; cr = 5;
sf = 10; sf = 10;
break; break;
case PRESET(MEDIUM_TURBO):
bwKHz = wideLora ? 1625.0f : 500.0f;
cr = 5;
sf = 9;
break;
case PRESET(LONG_TURBO): case PRESET(LONG_TURBO):
bwKHz = wideLora ? 1625.0f : 500.0f; bwKHz = wideLora ? 1625.0f : 500.0f;
cr = 8; cr = 8;
+2 -2
View File
@@ -39,8 +39,8 @@
#endif #endif
static const meshtastic_Config_LoRaConfig_ModemPreset PRESETS_STD[] = { static const meshtastic_Config_LoRaConfig_ModemPreset PRESETS_STD[] = {
PRESET(LONG_FAST), PRESET(LONG_SLOW), PRESET(MEDIUM_SLOW), PRESET(MEDIUM_FAST), PRESET(SHORT_SLOW), PRESET(LONG_FAST), PRESET(LONG_SLOW), PRESET(MEDIUM_SLOW), PRESET(MEDIUM_FAST), PRESET(SHORT_SLOW), PRESET(SHORT_FAST),
PRESET(SHORT_FAST), PRESET(LONG_MODERATE), PRESET(SHORT_TURBO), PRESET(LONG_TURBO), MODEM_PRESET_END}; PRESET(LONG_MODERATE), PRESET(SHORT_TURBO), PRESET(LONG_TURBO), PRESET(MEDIUM_TURBO), MODEM_PRESET_END};
static const meshtastic_Config_LoRaConfig_ModemPreset PRESETS_EU_868[] = { static const meshtastic_Config_LoRaConfig_ModemPreset PRESETS_EU_868[] = {
PRESET(LONG_FAST), PRESET(LONG_SLOW), PRESET(MEDIUM_SLOW), PRESET(MEDIUM_FAST), PRESET(LONG_FAST), PRESET(LONG_SLOW), PRESET(MEDIUM_SLOW), PRESET(MEDIUM_FAST),
+7 -3
View File
@@ -374,7 +374,11 @@ typedef enum _meshtastic_Config_LoRaConfig_ModemPreset {
Note: TCXO with tight tolerances (±5 ppm or better) is *absolutely required* at these narrow bandwidths. Note: TCXO with tight tolerances (±5 ppm or better) is *absolutely required* at these narrow bandwidths.
Only compatible with SX127x and SX126x chipsets. Only compatible with SX127x and SX126x chipsets.
Comparable link budget and data rate to LONG_MODERATE. */ Comparable link budget and data rate to LONG_MODERATE. */
meshtastic_Config_LoRaConfig_ModemPreset_TINY_SLOW = 15 meshtastic_Config_LoRaConfig_ModemPreset_TINY_SLOW = 15,
/* Medium Range - Turbo
This preset performs similarly to MEDIUM_FAST, but with 500kHz bandwidth.
It is not legal to use in all regions due to this wider bandwidth. */
meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO = 16
} meshtastic_Config_LoRaConfig_ModemPreset; } meshtastic_Config_LoRaConfig_ModemPreset;
typedef enum _meshtastic_Config_LoRaConfig_FEM_LNA_Mode { typedef enum _meshtastic_Config_LoRaConfig_FEM_LNA_Mode {
@@ -767,8 +771,8 @@ extern "C" {
#define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ITU2_125CM+1)) #define _meshtastic_Config_LoRaConfig_RegionCode_ARRAYSIZE ((meshtastic_Config_LoRaConfig_RegionCode)(meshtastic_Config_LoRaConfig_RegionCode_ITU2_125CM+1))
#define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST #define _meshtastic_Config_LoRaConfig_ModemPreset_MIN meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST
#define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_TINY_SLOW #define _meshtastic_Config_LoRaConfig_ModemPreset_MAX meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO
#define _meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE ((meshtastic_Config_LoRaConfig_ModemPreset)(meshtastic_Config_LoRaConfig_ModemPreset_TINY_SLOW+1)) #define _meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE ((meshtastic_Config_LoRaConfig_ModemPreset)(meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO+1))
#define _meshtastic_Config_LoRaConfig_FEM_LNA_Mode_MIN meshtastic_Config_LoRaConfig_FEM_LNA_Mode_DISABLED #define _meshtastic_Config_LoRaConfig_FEM_LNA_Mode_MIN meshtastic_Config_LoRaConfig_FEM_LNA_Mode_DISABLED
#define _meshtastic_Config_LoRaConfig_FEM_LNA_Mode_MAX meshtastic_Config_LoRaConfig_FEM_LNA_Mode_NOT_PRESENT #define _meshtastic_Config_LoRaConfig_FEM_LNA_Mode_MAX meshtastic_Config_LoRaConfig_FEM_LNA_Mode_NOT_PRESENT
+1
View File
@@ -2118,6 +2118,7 @@ static float getSnrLimit(meshtastic_Config_LoRaConfig_ModemPreset preset)
return -6.0f; return -6.0f;
case PRESET(MEDIUM_SLOW): case PRESET(MEDIUM_SLOW):
case PRESET(MEDIUM_FAST): case PRESET(MEDIUM_FAST):
case PRESET(MEDIUM_TURBO):
return -5.5f; return -5.5f;
case PRESET(SHORT_SLOW): case PRESET(SHORT_SLOW):
case PRESET(SHORT_FAST): case PRESET(SHORT_FAST):
+12 -8
View File
@@ -484,7 +484,7 @@ static void test_validateConfigLora_allStdPresetsValidForUS()
meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST,
meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST,
meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO, meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO,
meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO, meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO,
}; };
for (size_t i = 0; i < sizeof(stdPresets) / sizeof(stdPresets[0]); i++) { for (size_t i = 0; i < sizeof(stdPresets) / sizeof(stdPresets[0]); i++) {
@@ -498,7 +498,8 @@ static void test_validateConfigLora_allStdPresetsValidForUS()
static void test_validateConfigLora_turboPresetsInvalidForEU868() static void test_validateConfigLora_turboPresetsInvalidForEU868()
{ {
// EU_868 has PRESETS_EU_868 which excludes SHORT_TURBO and LONG_TURBO // EU_868 has PRESETS_EU_868 which excludes the 500 kHz turbo presets
// (SHORT_TURBO, LONG_TURBO, MEDIUM_TURBO)
meshtastic_Config_LoRaConfig cfg = meshtastic_Config_LoRaConfig_init_zero; meshtastic_Config_LoRaConfig cfg = meshtastic_Config_LoRaConfig_init_zero;
cfg.region = meshtastic_Config_LoRaConfig_RegionCode_EU_868; cfg.region = meshtastic_Config_LoRaConfig_RegionCode_EU_868;
cfg.use_preset = true; cfg.use_preset = true;
@@ -508,6 +509,9 @@ static void test_validateConfigLora_turboPresetsInvalidForEU868()
cfg.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO; cfg.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO;
TEST_ASSERT_FALSE_MESSAGE(RadioInterface::validateConfigLora(cfg), "LONG_TURBO should be invalid for EU_868"); TEST_ASSERT_FALSE_MESSAGE(RadioInterface::validateConfigLora(cfg), "LONG_TURBO should be invalid for EU_868");
cfg.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO;
TEST_ASSERT_FALSE_MESSAGE(RadioInterface::validateConfigLora(cfg), "MEDIUM_TURBO should be invalid for EU_868");
} }
static void test_validateConfigLora_validPresetsForEU868() static void test_validateConfigLora_validPresetsForEU868()
@@ -598,13 +602,13 @@ static void test_validateConfigLora_unsetRegionOnlyAcceptsLongFast()
static void test_validateConfigLora_allPresetsValidForLORA24() static void test_validateConfigLora_allPresetsValidForLORA24()
{ {
// LORA_24 uses PROFILE_STD (9 presets) with wideLora=true // LORA_24 uses PROFILE_STD (10 presets) with wideLora=true
meshtastic_Config_LoRaConfig_ModemPreset stdPresets[] = { meshtastic_Config_LoRaConfig_ModemPreset stdPresets[] = {
meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST, meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST, meshtastic_Config_LoRaConfig_ModemPreset_LONG_SLOW,
meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_FAST,
meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_SLOW, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST,
meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO, meshtastic_Config_LoRaConfig_ModemPreset_LONG_MODERATE, meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO,
meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO, meshtastic_Config_LoRaConfig_ModemPreset_LONG_TURBO, meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO,
}; };
for (size_t i = 0; i < sizeof(stdPresets) / sizeof(stdPresets[0]); i++) { for (size_t i = 0; i < sizeof(stdPresets) / sizeof(stdPresets[0]); i++) {
@@ -792,11 +796,11 @@ static void test_validateConfigLora_siblingLockedPresetStillFailsValidation()
// RegionInfo preset list integrity tests // RegionInfo preset list integrity tests
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
static void test_presetsStd_hasNineEntries() static void test_presetsStd_hasTenEntries()
{ {
// PROFILE_STD should have exactly 9 presets // PROFILE_STD should have exactly 10 presets (adds MEDIUM_TURBO to the turbo cluster)
const RegionInfo *us = getRegion(meshtastic_Config_LoRaConfig_RegionCode_US); const RegionInfo *us = getRegion(meshtastic_Config_LoRaConfig_RegionCode_US);
TEST_ASSERT_EQUAL(9, us->getNumPresets()); TEST_ASSERT_EQUAL(10, us->getNumPresets());
TEST_ASSERT_EQUAL_PTR(PROFILE_STD.presets, us->getAvailablePresets()); TEST_ASSERT_EQUAL_PTR(PROFILE_STD.presets, us->getAvailablePresets());
} }
@@ -1320,7 +1324,7 @@ void setup()
RUN_TEST(test_validateConfigLora_siblingLockedPresetStillFailsValidation); RUN_TEST(test_validateConfigLora_siblingLockedPresetStillFailsValidation);
// RegionInfo preset list integrity // RegionInfo preset list integrity
RUN_TEST(test_presetsStd_hasNineEntries); RUN_TEST(test_presetsStd_hasTenEntries);
RUN_TEST(test_presetsEU868_hasSevenEntries); RUN_TEST(test_presetsEU868_hasSevenEntries);
RUN_TEST(test_presetsUndef_hasOneEntry); RUN_TEST(test_presetsUndef_hasOneEntry);
RUN_TEST(test_defaultPresetIsInAvailablePresets); RUN_TEST(test_defaultPresetIsInAvailablePresets);
+3 -2
View File
@@ -450,7 +450,8 @@ static meshtastic_AdminMessage fuzzAdminMessage()
// manual bandwidth==0 path that used to SIGFPE the validator. // manual bandwidth==0 path that used to SIGFPE the validator.
r.set_config.which_payload_variant = meshtastic_Config_lora_tag; r.set_config.which_payload_variant = meshtastic_Config_lora_tag;
r.set_config.payload_variant.lora.region = (meshtastic_Config_LoRaConfig_RegionCode)rngRange(32); r.set_config.payload_variant.lora.region = (meshtastic_Config_LoRaConfig_RegionCode)rngRange(32);
r.set_config.payload_variant.lora.modem_preset = (meshtastic_Config_LoRaConfig_ModemPreset)rngRange(16); r.set_config.payload_variant.lora.modem_preset =
(meshtastic_Config_LoRaConfig_ModemPreset)rngRange(_meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE);
r.set_config.payload_variant.lora.use_preset = (rngRange(2) == 0); r.set_config.payload_variant.lora.use_preset = (rngRange(2) == 0);
r.set_config.payload_variant.lora.bandwidth = rngRange(512); // includes 0 r.set_config.payload_variant.lora.bandwidth = rngRange(512); // includes 0
r.set_config.payload_variant.lora.channel_num = rngNext(); r.set_config.payload_variant.lora.channel_num = rngNext();
@@ -553,7 +554,7 @@ static meshtastic_MeshBeacon fuzzBeacon()
fuzzChannelSettings(b.offer_channel); fuzzChannelSettings(b.offer_channel);
b.offer_region = (meshtastic_Config_LoRaConfig_RegionCode)rngRange(32); b.offer_region = (meshtastic_Config_LoRaConfig_RegionCode)rngRange(32);
b.has_offer_preset = (rngRange(2) == 0); b.has_offer_preset = (rngRange(2) == 0);
b.offer_preset = (meshtastic_Config_LoRaConfig_ModemPreset)rngRange(16); b.offer_preset = (meshtastic_Config_LoRaConfig_ModemPreset)rngRange(_meshtastic_Config_LoRaConfig_ModemPreset_ARRAYSIZE);
return b; return b;
} }
+40
View File
@@ -251,6 +251,44 @@ static void test_adminValidation_turboPresetOnUS_isAccepted(void)
TEST_ASSERT_EQUAL(meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO, moduleConfig.mesh_beacon.broadcast_on_preset); TEST_ASSERT_EQUAL(meshtastic_Config_LoRaConfig_ModemPreset_SHORT_TURBO, moduleConfig.mesh_beacon.broadcast_on_preset);
} }
/**
* Verify MEDIUM_TURBO is also cleared for EU_868. Like SHORT_TURBO/LONG_TURBO it is a 500 kHz preset
* that does not fit EU_868's 250 kHz band, so it must not survive admin validation there.
*/
static void test_adminValidation_mediumTurboPresetOnEU868_isCleared(void)
{
resetConfig();
meshtastic_ModuleConfig_MeshBeaconConfig bcfg = meshtastic_ModuleConfig_MeshBeaconConfig_init_zero;
bcfg.has_broadcast_on_preset = true;
bcfg.broadcast_on_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO;
testAdmin->handleSetModuleConfig(makeBeaconModuleConfig(bcfg));
TEST_ASSERT_TRUE(moduleConfig.has_mesh_beacon);
TEST_ASSERT_FALSE(moduleConfig.mesh_beacon.has_broadcast_on_preset);
}
/**
* Verify MEDIUM_TURBO passes validation for US (PROFILE_STD allows the full turbo family).
* The same 500 kHz preset that is illegal in EU_868 must be preserved in permissive regions.
*/
static void test_adminValidation_mediumTurboPresetOnUS_isAccepted(void)
{
resetConfig();
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US;
initRegion();
meshtastic_ModuleConfig_MeshBeaconConfig bcfg = meshtastic_ModuleConfig_MeshBeaconConfig_init_zero;
bcfg.has_broadcast_on_preset = true;
bcfg.broadcast_on_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO;
testAdmin->handleSetModuleConfig(makeBeaconModuleConfig(bcfg));
TEST_ASSERT_TRUE(moduleConfig.mesh_beacon.has_broadcast_on_preset);
TEST_ASSERT_EQUAL(meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO, moduleConfig.mesh_beacon.broadcast_on_preset);
}
/** /**
* Verify an out-of-range region code (255) is sanitised to UNSET rather than stored verbatim. * Verify an out-of-range region code (255) is sanitised to UNSET rather than stored verbatim.
* Important to prevent invalid proto enum values from reaching the broadcaster and being broadcast * Important to prevent invalid proto enum values from reaching the broadcaster and being broadcast
@@ -1360,6 +1398,8 @@ BEACON_TEST_ENTRY void setup()
RUN_TEST(test_adminValidation_turboPresetOnEU868_isCleared); RUN_TEST(test_adminValidation_turboPresetOnEU868_isCleared);
RUN_TEST(test_adminValidation_longTurboPresetOnEU868_isCleared); RUN_TEST(test_adminValidation_longTurboPresetOnEU868_isCleared);
RUN_TEST(test_adminValidation_turboPresetOnUS_isAccepted); RUN_TEST(test_adminValidation_turboPresetOnUS_isAccepted);
RUN_TEST(test_adminValidation_mediumTurboPresetOnEU868_isCleared);
RUN_TEST(test_adminValidation_mediumTurboPresetOnUS_isAccepted);
RUN_TEST(test_adminValidation_unknownOfferRegion_isCleared); RUN_TEST(test_adminValidation_unknownOfferRegion_isCleared);
RUN_TEST(test_adminValidation_validOfferRegion_isPreserved); RUN_TEST(test_adminValidation_validOfferRegion_isPreserved);
RUN_TEST(test_adminValidation_targetUnknownRegion_isCleared); RUN_TEST(test_adminValidation_targetUnknownRegion_isCleared);
+44
View File
@@ -195,6 +195,47 @@ static void test_applyModemConfig_customCodingRateLowerThanPreset()
TEST_ASSERT_EQUAL_UINT8(8, testRadio->getCr()); TEST_ASSERT_EQUAL_UINT8(8, testRadio->getCr());
} }
// MEDIUM_TURBO performs like MEDIUM_FAST (sf=9, cr=5) but at 500 kHz. Verify the params resolve.
static void test_applyModemConfig_mediumTurbo()
{
config.lora = meshtastic_Config_LoRaConfig_init_zero;
config.lora.region = meshtastic_Config_LoRaConfig_RegionCode_US;
config.lora.use_preset = true;
config.lora.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO;
testRadio->reconfigure();
TEST_ASSERT_EQUAL_UINT8(5, testRadio->getCr());
TEST_ASSERT_EQUAL_UINT8(9, testRadio->getSf());
TEST_ASSERT_FLOAT_WITHIN(0.01f, 500.0f, testRadio->getBw());
}
// MEDIUM_TURBO is a 500 kHz preset, so it is invalid for EU_868 and must clamp to the region default.
static void test_clampConfigLora_mediumTurboInvalidForEU868()
{
meshtastic_Config_LoRaConfig cfg = meshtastic_Config_LoRaConfig_init_zero;
cfg.use_preset = true;
cfg.region = meshtastic_Config_LoRaConfig_RegionCode_EU_868;
cfg.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO;
RadioInterface::clampConfigLora(cfg);
TEST_ASSERT_EQUAL(meshtastic_Config_LoRaConfig_ModemPreset_LONG_FAST, cfg.modem_preset);
}
// MEDIUM_TURBO is valid for US (PROFILE_STD) and must be left unchanged.
static void test_clampConfigLora_mediumTurboValidForUS()
{
meshtastic_Config_LoRaConfig cfg = meshtastic_Config_LoRaConfig_init_zero;
cfg.use_preset = true;
cfg.region = meshtastic_Config_LoRaConfig_RegionCode_US;
cfg.modem_preset = meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO;
RadioInterface::clampConfigLora(cfg);
TEST_ASSERT_EQUAL(meshtastic_Config_LoRaConfig_ModemPreset_MEDIUM_TURBO, cfg.modem_preset);
}
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
// getRegionPresetMap() - region->valid-preset map sent to clients during want_config // getRegionPresetMap() - region->valid-preset map sent to clients during want_config
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@@ -317,6 +358,9 @@ void setup()
RUN_TEST(test_applyModemConfig_codingRateMatchesPreset); RUN_TEST(test_applyModemConfig_codingRateMatchesPreset);
RUN_TEST(test_applyModemConfig_customCodingRateHigherThanPreset); RUN_TEST(test_applyModemConfig_customCodingRateHigherThanPreset);
RUN_TEST(test_applyModemConfig_customCodingRateLowerThanPreset); RUN_TEST(test_applyModemConfig_customCodingRateLowerThanPreset);
RUN_TEST(test_applyModemConfig_mediumTurbo);
RUN_TEST(test_clampConfigLora_mediumTurboInvalidForEU868);
RUN_TEST(test_clampConfigLora_mediumTurboValidForUS);
RUN_TEST(test_regionPresetMap_coversAllRegionsWithinBounds); RUN_TEST(test_regionPresetMap_coversAllRegionsWithinBounds);
RUN_TEST(test_regionPresetMap_matchesRegionTable); RUN_TEST(test_regionPresetMap_matchesRegionTable);
exit(UNITY_END()); exit(UNITY_END());