diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index b95f3a47..6bbc563e 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -970,6 +970,7 @@ void MyMesh::begin(bool has_display) { radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain); MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s", radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled"); + board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain); // LoRa FEM LNA (FEM boards only) } const char *MyMesh::getNodeName() { diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 672e8ea8..03a2e810 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1073,6 +1073,7 @@ void MyMesh::begin(FILESYSTEM *fs) { radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain); MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s", radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled"); + board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain); // LoRa FEM LNA (FEM boards only) updateAdvertTimer(); updateFloodAdvertTimer(); diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 69fd99fb..d9b93a69 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -735,6 +735,7 @@ void MyMesh::begin(FILESYSTEM *fs) { radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); radio_driver.setTxPower(_prefs.tx_power_dbm); + board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain); // LoRa FEM LNA (FEM boards only) updateAdvertTimer(); updateFloodAdvertTimer(); diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index bdd35fc0..475a38ff 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -772,6 +772,7 @@ void SensorMesh::begin(FILESYSTEM* fs) { radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr); radio_driver.setTxPower(_prefs.tx_power_dbm); + board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain); // LoRa FEM LNA (FEM boards only) updateAdvertTimer(); updateFloodAdvertTimer(); diff --git a/src/MeshCore.h b/src/MeshCore.h index 6a17a4b6..f0c8f387 100644 --- a/src/MeshCore.h +++ b/src/MeshCore.h @@ -69,6 +69,12 @@ public: // dry_run is true the build is only reported, not flashed. Observer (ESP32+WiFi) builds only. virtual bool otaFromManifest(const char* current_ver, bool dry_run, char reply[]) { return false; } + // LoRa front-end-module LNA (RX gain) control. Only FEM-equipped boards override + // these; others report they can't control it. Driven by NodePrefs.radio_fem_rxgain. + virtual bool setLoRaFemLnaEnabled(bool enable) { return false; } + virtual bool canControlLoRaFemLna() const { return false; } + virtual bool isLoRaFemLnaEnabled() const { return false; } + // Power management interface (boards with power management override these) virtual bool isExternalPowered() { return false; } virtual uint16_t getBootVoltage() { return 0; } diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 9d832f93..8b9ef130 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -984,6 +984,28 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep _prefs->cad_enabled = memcmp(&config[4], "on", 2) == 0; savePrefs(); strcpy(reply, "OK"); + } else if (memcmp(config, "radio.fem.rxgain ", 17) == 0) { + if (!_board->canControlLoRaFemLna()) { + strcpy(reply, "Error: unsupported"); + } else if (memcmp(&config[17], "on", 2) == 0) { + if (_board->setLoRaFemLnaEnabled(true)) { + _prefs->radio_fem_rxgain = 1; + savePrefs(); + strcpy(reply, "OK - LoRa FEM RX gain on"); + } else { + strcpy(reply, "Error: failed to apply LoRa FEM RX gain"); + } + } else if (memcmp(&config[17], "off", 3) == 0) { + if (_board->setLoRaFemLnaEnabled(false)) { + _prefs->radio_fem_rxgain = 0; + savePrefs(); + strcpy(reply, "OK - LoRa FEM RX gain off"); + } else { + strcpy(reply, "Error: failed to apply LoRa FEM RX gain"); + } + } else { + strcpy(reply, "Error: state must be on or off"); + } } else if (memcmp(config, "agc.reset.interval ", 19) == 0) { _prefs->agc_reset_interval = atoi(&config[19]) / 4; savePrefs(); @@ -1272,6 +1294,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep sprintf(reply, "> %d", (uint32_t) _prefs->interference_threshold); } else if (memcmp(config, "cad", 3) == 0) { sprintf(reply, "> %s", _prefs->cad_enabled ? "on" : "off"); + } else if (memcmp(config, "radio.fem.rxgain", 16) == 0) { + if (!_board->canControlLoRaFemLna()) { + strcpy(reply, "Error: unsupported"); + } else { + sprintf(reply, "> %s", _board->isLoRaFemLnaEnabled() ? "on" : "off"); + } } else if (memcmp(config, "agc.reset.interval", 18) == 0) { sprintf(reply, "> %d", ((uint32_t) _prefs->agc_reset_interval) * 4); } else if (memcmp(config, "multi.acks", 10) == 0) { diff --git a/variants/heltec_v4/HeltecV4Board.cpp b/variants/heltec_v4/HeltecV4Board.cpp index 8f013797..ac804cc2 100644 --- a/variants/heltec_v4/HeltecV4Board.cpp +++ b/variants/heltec_v4/HeltecV4Board.cpp @@ -83,3 +83,20 @@ void HeltecV4Board::begin() { return loRaFEMControl.getFEMType() == KCT8103L_PA ? "Heltec V4.3 OLED" : "Heltec V4 OLED"; #endif } + + bool HeltecV4Board::setLoRaFemLnaEnabled(bool enable) { + if (!loRaFEMControl.isLnaCanControl()) { + return false; + } + loRaFEMControl.setLNAEnable(enable); + loRaFEMControl.setRxModeEnable(); + return true; + } + + bool HeltecV4Board::canControlLoRaFemLna() const { + return loRaFEMControl.isLnaCanControl(); + } + + bool HeltecV4Board::isLoRaFemLnaEnabled() const { + return loRaFEMControl.isLNAEnabled(); + } diff --git a/variants/heltec_v4/HeltecV4Board.h b/variants/heltec_v4/HeltecV4Board.h index 95def06c..d59f730d 100644 --- a/variants/heltec_v4/HeltecV4Board.h +++ b/variants/heltec_v4/HeltecV4Board.h @@ -36,4 +36,8 @@ public: } float getAdcMultiplier() const override { return adc_mult; } const char* getManufacturerName() const override; + + bool setLoRaFemLnaEnabled(bool enable) override; + bool canControlLoRaFemLna() const override; + bool isLoRaFemLnaEnabled() const override; }; diff --git a/variants/heltec_v4/LoRaFEMControl.h b/variants/heltec_v4/LoRaFEMControl.h index 13225bd5..4ab9b9c9 100644 --- a/variants/heltec_v4/LoRaFEMControl.h +++ b/variants/heltec_v4/LoRaFEMControl.h @@ -18,7 +18,8 @@ class LoRaFEMControl void setRxModeEnable(void); void setRxModeEnableWhenMCUSleep(void); void setLNAEnable(bool enabled); - bool isLnaCanControl(void) { return lna_can_control; } + bool isLnaCanControl(void) const { return lna_can_control; } + bool isLNAEnabled(void) const { return lna_enabled; } void setLnaCanControl(bool can_control) { lna_can_control = can_control; } LoRaFEMType getFEMType(void) const { return fem_type; } private: