Skip to content

Commit a5cb0c2

Browse files
authored
Merge pull request meshcore-dev#2140 from Quency-D/cli-lna-command
Add CLI control to LoRa's fem LNA.
2 parents d5f74e9 + 5300fa1 commit a5cb0c2

19 files changed

Lines changed: 142 additions & 18 deletions

File tree

docs/cli_commands.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,20 @@ This document provides an overview of CLI commands that can be sent to MeshCore
263263

264264
---
265265

266+
#### View or change the LoRa FEM receive-path gain state on supported boards
267+
**Usage:**
268+
- `get radio.fem.rxgain`
269+
- `set radio.fem.rxgain <state>`
270+
271+
**Parameters:**
272+
- `state`: `on`|`off`
273+
274+
**Notes:**
275+
- This controls the external LoRa FEM receive-path LNA where the board supports it.
276+
- This is separate from `radio.rxgain`, which controls the radio chip receive gain mode.
277+
278+
---
279+
266280
### System
267281

268282
#### View or change this node's name

examples/simple_repeater/MyMesh.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
917917
_prefs.rx_boosted_gain = 1; // enabled by default;
918918
#endif
919919
#endif
920+
_prefs.radio_fem_rxgain = 1;
920921

921922
pending_discover_tag = 0;
922923
pending_discover_until = 0;
@@ -965,6 +966,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
965966
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
966967
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
967968
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
969+
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
968970

969971
updateAdvertTimer();
970972
updateFloodAdvertTimer();

examples/simple_repeater/UITask.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
4141
}
4242

4343
// v1.2.3 (1 Jan 2025)
44-
sprintf(_version_info, "%s (%s)", version, build_date);
44+
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
45+
free(version);
4546
}
4647

4748
void UITask::renderCurrScreen() {

examples/simple_room_server/MyMesh.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
658658
_prefs.gps_enabled = 0;
659659
_prefs.gps_interval = 0;
660660
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
661+
_prefs.radio_fem_rxgain = 1;
661662

662663
next_post_idx = 0;
663664
next_client_idx = 0;
@@ -699,6 +700,7 @@ void MyMesh::begin(FILESYSTEM *fs) {
699700

700701
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
701702
radio_driver.setTxPower(_prefs.tx_power_dbm);
703+
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
702704

703705
updateAdvertTimer();
704706
updateFloodAdvertTimer();

examples/simple_room_server/UITask.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
4141
}
4242

4343
// v1.2.3 (1 Jan 2025)
44-
sprintf(_version_info, "%s (%s)", version, build_date);
44+
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
45+
free(version);
4546
}
4647

4748
void UITask::renderCurrScreen() {

examples/simple_sensor/SensorMesh.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
731731
_prefs.gps_enabled = 0;
732732
_prefs.gps_interval = 0;
733733
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
734+
_prefs.radio_fem_rxgain = 1;
734735

735736
memset(default_scope.key, 0, sizeof(default_scope.key));
736737
}
@@ -766,6 +767,7 @@ void SensorMesh::begin(FILESYSTEM* fs) {
766767

767768
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
768769
radio_driver.setTxPower(_prefs.tx_power_dbm);
770+
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
769771

770772
updateAdvertTimer();
771773
updateFloodAdvertTimer();

examples/simple_sensor/UITask.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
4141
}
4242

4343
// v1.2.3 (1 Jan 2025)
44-
sprintf(_version_info, "%s (%s)", version, build_date);
44+
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
45+
free(version);
4546
}
4647

4748
void UITask::renderCurrScreen() {

src/MeshCore.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ class MainBoard {
6464
virtual uint8_t getStartupReason() const = 0;
6565
virtual bool getBootloaderVersion(char* version, size_t max_len) { return false; }
6666
virtual bool startOTAUpdate(const char* id, char reply[]) { return false; } // not supported
67+
virtual bool setLoRaFemLnaEnabled(bool enable) { return false; }
68+
virtual bool canControlLoRaFemLna() const { return false; }
69+
virtual bool isLoRaFemLnaEnabled() const { return false; }
6770

6871
// Power management interface (boards with power management override these)
6972
virtual bool isExternalPowered() { return false; }

src/helpers/CommonCLI.cpp

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,11 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
8888
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
8989
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
9090
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
91-
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
92-
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
93-
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
94-
// next: 293
91+
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
92+
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
93+
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
94+
file.read((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
95+
// next: 294
9596

9697
// sanitise bad pref values
9798
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
@@ -121,6 +122,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
121122

122123
// sanitise settings
123124
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
125+
_prefs->radio_fem_rxgain = constrain(_prefs->radio_fem_rxgain, 0, 1); // boolean
124126

125127
file.close();
126128
}
@@ -181,10 +183,11 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
181183
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
182184
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
183185
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
184-
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
185-
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
186-
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
187-
// next: 293
186+
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
187+
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
188+
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
189+
file.write((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
190+
// next: 294
188191

189192
file.close();
190193
}
@@ -568,6 +571,28 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
568571
savePrefs();
569572
_callbacks->setRxBoostedGain(_prefs->rx_boosted_gain);
570573
#endif
574+
} else if (memcmp(config, "radio.fem.rxgain ", 17) == 0) {
575+
if (!_board->canControlLoRaFemLna()) {
576+
strcpy(reply, "Error: unsupported");
577+
} else if (memcmp(&config[17], "on", 2) == 0) {
578+
if (_board->setLoRaFemLnaEnabled(true)) {
579+
_prefs->radio_fem_rxgain = 1;
580+
savePrefs();
581+
strcpy(reply, "OK - LoRa FEM RX gain on");
582+
} else {
583+
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
584+
}
585+
} else if (memcmp(&config[17], "off", 3) == 0) {
586+
if (_board->setLoRaFemLnaEnabled(false)) {
587+
_prefs->radio_fem_rxgain = 0;
588+
savePrefs();
589+
strcpy(reply, "OK - LoRa FEM RX gain off");
590+
} else {
591+
strcpy(reply, "Error: failed to apply LoRa FEM RX gain");
592+
}
593+
} else {
594+
strcpy(reply, "Error: state must be on or off");
595+
}
571596
} else if (memcmp(config, "radio ", 6) == 0) {
572597
strcpy(tmp, &config[6]);
573598
const char *parts[4];
@@ -757,7 +782,7 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
757782
}
758783
} else {
759784
_prefs->adc_multiplier = 0.0f;
760-
strcpy(reply, "Error: unsupported by this board");
785+
strcpy(reply, "Error: unsupported");
761786
};
762787
} else {
763788
strcpy(reply, "unknown config: ");
@@ -805,6 +830,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
805830
} else if (memcmp(config, "radio.rxgain", 12) == 0) {
806831
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off");
807832
#endif
833+
} else if (memcmp(config, "radio.fem.rxgain", 16) == 0) {
834+
if (!_board->canControlLoRaFemLna()) {
835+
strcpy(reply, "Error: unsupported");
836+
} else {
837+
sprintf(reply, "> %s", _board->isLoRaFemLnaEnabled() ? "on" : "off");
838+
}
808839
} else if (memcmp(config, "radio", 5) == 0) {
809840
char freq[16], bw[16];
810841
strcpy(freq, StrHelper::ftoa(_prefs->freq));
@@ -890,12 +921,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
890921
strcpy(reply, "> unknown");
891922
}
892923
#else
893-
strcpy(reply, "ERROR: unsupported");
924+
strcpy(reply, "Error: unsupported");
894925
#endif
895926
} else if (memcmp(config, "adc.multiplier", 14) == 0) {
896927
float adc_mult = _board->getAdcMultiplier();
897928
if (adc_mult == 0.0f) {
898-
strcpy(reply, "Error: unsupported by this board");
929+
strcpy(reply, "Error: unsupported");
899930
} else {
900931
sprintf(reply, "> %.3f", adc_mult);
901932
}

src/helpers/CommonCLI.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct NodePrefs { // persisted to file
6161
float adc_multiplier;
6262
char owner_info[120];
6363
uint8_t rx_boosted_gain; // power settings
64+
uint8_t radio_fem_rxgain; // LoRa FEM RX gain setting
6465
uint8_t path_hash_mode; // which path mode to use when sending
6566
uint8_t loop_detect;
6667
};

0 commit comments

Comments
 (0)