Quency-D 11 hours ago
committed by GitHub
parent
commit
3b8d55b4ff
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 14
      docs/cli_commands.md
  2. 2
      examples/companion_radio/DataStore.cpp
  3. 29
      examples/companion_radio/MyMesh.cpp
  4. 3
      examples/companion_radio/NodePrefs.h
  5. 2
      examples/simple_repeater/MyMesh.cpp
  6. 3
      examples/simple_repeater/UITask.cpp
  7. 2
      examples/simple_room_server/MyMesh.cpp
  8. 3
      examples/simple_room_server/UITask.cpp
  9. 2
      examples/simple_sensor/SensorMesh.cpp
  10. 3
      examples/simple_sensor/UITask.cpp
  11. 3
      src/MeshCore.h
  12. 53
      src/helpers/CommonCLI.cpp
  13. 1
      src/helpers/CommonCLI.h
  14. 3
      variants/heltec_t096/LoRaFEMControl.h
  15. 20
      variants/heltec_t096/T096Board.cpp
  16. 3
      variants/heltec_t096/T096Board.h
  17. 18
      variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp
  18. 3
      variants/heltec_tracker_v2/HeltecTrackerV2Board.h
  19. 3
      variants/heltec_tracker_v2/LoRaFEMControl.h
  20. 18
      variants/heltec_v4/HeltecV4Board.cpp
  21. 3
      variants/heltec_v4/HeltecV4Board.h
  22. 3
      variants/heltec_v4/LoRaFEMControl.h

14
docs/cli_commands.md

@ -263,6 +263,20 @@ This document provides an overview of CLI commands that can be sent to MeshCore
---
#### View or change the LoRa FEM receive-path gain state on supported boards
**Usage:**
- `get radio.fem.rxgain`
- `set radio.fem.rxgain <state>`
**Parameters:**
- `state`: `on`|`off`
**Notes:**
- This controls the external LoRa FEM receive-path LNA where the board supports it.
- This is separate from `radio.rxgain`, which controls the radio chip receive gain mode.
---
### System
#### View or change this node's name

2
examples/companion_radio/DataStore.cpp

@ -233,6 +233,7 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no
file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89
file.read((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90
file.read((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121
file.read((uint8_t *)&_prefs.radio_fem_rxgain, sizeof(_prefs.radio_fem_rxgain)); // 122
file.close();
}
@ -273,6 +274,7 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89
file.write((uint8_t *)_prefs.default_scope_name, sizeof(_prefs.default_scope_name)); // 90
file.write((uint8_t *)_prefs.default_scope_key, sizeof(_prefs.default_scope_key)); // 121
file.write((uint8_t *)&_prefs.radio_fem_rxgain, sizeof(_prefs.radio_fem_rxgain)); // 122
file.close();
}

29
examples/companion_radio/MyMesh.cpp

@ -62,6 +62,8 @@
#define CMD_SET_DEFAULT_FLOOD_SCOPE 63
#define CMD_GET_DEFAULT_FLOOD_SCOPE 64
#define CMD_SEND_RAW_PACKET 65
#define CMD_GET_RADIO_FEM_RXGAIN 66
#define CMD_SET_RADIO_FEM_RXGAIN 67
// Stats sub-types for CMD_GET_STATS
#define STATS_TYPE_CORE 0
@ -886,6 +888,7 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe
_prefs.rx_boosted_gain = 1; // enabled by default
#endif
#endif
_prefs.radio_fem_rxgain = 1;
}
void MyMesh::begin(bool has_display) {
@ -935,6 +938,7 @@ void MyMesh::begin(bool has_display) {
_prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, -9, MAX_LORA_TX_POWER);
_prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1
_prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours
_prefs.radio_fem_rxgain = constrain(_prefs.radio_fem_rxgain, 0, 1);
#ifdef BLE_PIN_CODE // 123456 by default
if (_prefs.ble_pin == 0) {
@ -964,6 +968,7 @@ void MyMesh::begin(bool has_display) {
radio_driver.setParams(_prefs.freq, _prefs.bw, _prefs.sf, _prefs.cr);
radio_driver.setTxPower(_prefs.tx_power_dbm);
radio_driver.setRxBoostedGainMode(_prefs.rx_boosted_gain);
board.setLoRaFemLnaEnabled(_prefs.radio_fem_rxgain);
MESH_DEBUG_PRINTLN("RX Boosted Gain Mode: %s",
radio_driver.getRxBoostedGainMode() ? "Enabled" : "Disabled");
}
@ -1821,6 +1826,30 @@ void MyMesh::handleCmdFrame(size_t len) {
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_GET_RADIO_FEM_RXGAIN) {
if (!board.canControlLoRaFemLna()) {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
} else {
out_frame[0] = RESP_CODE_OK;
uint8_t value = board.isLoRaFemLnaEnabled() ? 1 : 0;
memcpy(&out_frame[1], &value, 1);
_serial->writeFrame(out_frame, 2);
}
} else if (cmd_frame[0] == CMD_SET_RADIO_FEM_RXGAIN && len >= 2) {
uint8_t value = cmd_frame[1];
if (!board.canControlLoRaFemLna()) {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
} else if (value <= 1) {
_prefs.radio_fem_rxgain = value;
if (board.setLoRaFemLnaEnabled(value != 0)) {
savePrefs();
writeOKFrame();
} else {
writeErrFrame(ERR_CODE_UNSUPPORTED_CMD);
}
} else {
writeErrFrame(ERR_CODE_ILLEGAL_ARG);
}
} else if (cmd_frame[0] == CMD_GET_ADVERT_PATH && len >= PUB_KEY_SIZE+2) {
// FUTURE use: uint8_t reserved = cmd_frame[1];
uint8_t *pub_key = &cmd_frame[2];

3
examples/companion_radio/NodePrefs.h

@ -29,9 +29,10 @@ struct NodePrefs { // persisted to file
uint32_t gps_interval; // GPS read interval in seconds
uint8_t autoadd_config; // bitmask for auto-add contacts config
uint8_t rx_boosted_gain; // SX126x RX boosted gain mode (0=power saving, 1=boosted)
uint8_t radio_fem_rxgain; // LoRa FEM RX gain setting
uint8_t client_repeat;
uint8_t path_hash_mode; // which path mode to use when sending
uint8_t autoadd_max_hops; // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops (max 64)
char default_scope_name[31];
uint8_t default_scope_key[16];
};
};

2
examples/simple_repeater/MyMesh.cpp

@ -917,6 +917,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.rx_boosted_gain = 1; // enabled by default;
#endif
#endif
_prefs.radio_fem_rxgain = 1;
pending_discover_tag = 0;
pending_discover_until = 0;
@ -965,6 +966,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);
updateAdvertTimer();
updateFloodAdvertTimer();

3
examples/simple_repeater/UITask.cpp

@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
}
// v1.2.3 (1 Jan 2025)
sprintf(_version_info, "%s (%s)", version, build_date);
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
free(version);
}
void UITask::renderCurrScreen() {

2
examples/simple_room_server/MyMesh.cpp

@ -658,6 +658,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
_prefs.gps_enabled = 0;
_prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
_prefs.radio_fem_rxgain = 1;
next_post_idx = 0;
next_client_idx = 0;
@ -699,6 +700,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);
updateAdvertTimer();
updateFloodAdvertTimer();

3
examples/simple_room_server/UITask.cpp

@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
}
// v1.2.3 (1 Jan 2025)
sprintf(_version_info, "%s (%s)", version, build_date);
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
free(version);
}
void UITask::renderCurrScreen() {

2
examples/simple_sensor/SensorMesh.cpp

@ -731,6 +731,7 @@ SensorMesh::SensorMesh(mesh::MainBoard& board, mesh::Radio& radio, mesh::Millise
_prefs.gps_enabled = 0;
_prefs.gps_interval = 0;
_prefs.advert_loc_policy = ADVERT_LOC_PREFS;
_prefs.radio_fem_rxgain = 1;
memset(default_scope.key, 0, sizeof(default_scope.key));
}
@ -766,6 +767,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);
updateAdvertTimer();
updateFloodAdvertTimer();

3
examples/simple_sensor/UITask.cpp

@ -41,7 +41,8 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi
}
// v1.2.3 (1 Jan 2025)
sprintf(_version_info, "%s (%s)", version, build_date);
snprintf(_version_info, sizeof(_version_info), "%s (%s)", version, build_date);
free(version);
}
void UITask::renderCurrScreen() {

3
src/MeshCore.h

@ -64,6 +64,9 @@ public:
virtual uint8_t getStartupReason() const = 0;
virtual bool getBootloaderVersion(char* version, size_t max_len) { return false; }
virtual bool startOTAUpdate(const char* id, char reply[]) { return false; } // not supported
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; }

53
src/helpers/CommonCLI.cpp

@ -88,10 +88,11 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
file.read((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
file.read((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
file.read((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
// next: 293
file.read((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
file.read((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
file.read((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
file.read((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
// next: 294
// sanitise bad pref values
_prefs->rx_delay_base = constrain(_prefs->rx_delay_base, 0, 20.0f);
@ -121,6 +122,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
// sanitise settings
_prefs->rx_boosted_gain = constrain(_prefs->rx_boosted_gain, 0, 1); // boolean
_prefs->radio_fem_rxgain = constrain(_prefs->radio_fem_rxgain, 0, 1); // boolean
file.close();
}
@ -181,10 +183,11 @@ void CommonCLI::savePrefs(FILESYSTEM* fs) {
file.write((uint8_t *)&_prefs->discovery_mod_timestamp, sizeof(_prefs->discovery_mod_timestamp)); // 162
file.write((uint8_t *)&_prefs->adc_multiplier, sizeof(_prefs->adc_multiplier)); // 166
file.write((uint8_t *)_prefs->owner_info, sizeof(_prefs->owner_info)); // 170
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
// next: 293
file.write((uint8_t *)&_prefs->rx_boosted_gain, sizeof(_prefs->rx_boosted_gain)); // 290
file.write((uint8_t *)&_prefs->flood_max_unscoped, sizeof(_prefs->flood_max_unscoped)); // 291
file.write((uint8_t *)&_prefs->flood_max_advert, sizeof(_prefs->flood_max_advert)); // 292
file.write((uint8_t *)&_prefs->radio_fem_rxgain, sizeof(_prefs->radio_fem_rxgain)); // 293
// next: 294
file.close();
}
@ -568,6 +571,28 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
savePrefs();
_callbacks->setRxBoostedGain(_prefs->rx_boosted_gain);
#endif
} 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, "radio ", 6) == 0) {
strcpy(tmp, &config[6]);
const char *parts[4];
@ -757,7 +782,7 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
}
} else {
_prefs->adc_multiplier = 0.0f;
strcpy(reply, "Error: unsupported by this board");
strcpy(reply, "Error: unsupported");
};
} else {
strcpy(reply, "unknown config: ");
@ -805,6 +830,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
} else if (memcmp(config, "radio.rxgain", 12) == 0) {
sprintf(reply, "> %s", _prefs->rx_boosted_gain ? "on" : "off");
#endif
} 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, "radio", 5) == 0) {
char freq[16], bw[16];
strcpy(freq, StrHelper::ftoa(_prefs->freq));
@ -890,12 +921,12 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
strcpy(reply, "> unknown");
}
#else
strcpy(reply, "ERROR: unsupported");
strcpy(reply, "Error: unsupported");
#endif
} else if (memcmp(config, "adc.multiplier", 14) == 0) {
float adc_mult = _board->getAdcMultiplier();
if (adc_mult == 0.0f) {
strcpy(reply, "Error: unsupported by this board");
strcpy(reply, "Error: unsupported");
} else {
sprintf(reply, "> %.3f", adc_mult);
}

1
src/helpers/CommonCLI.h

@ -61,6 +61,7 @@ struct NodePrefs { // persisted to file
float adc_multiplier;
char owner_info[120];
uint8_t rx_boosted_gain; // power settings
uint8_t radio_fem_rxgain; // LoRa FEM RX gain setting
uint8_t path_hash_mode; // which path mode to use when sending
uint8_t loop_detect;
};

3
variants/heltec_t096/LoRaFEMControl.h

@ -12,8 +12,9 @@ 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; }
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
bool isLNAEnabled(void) const { return lna_enabled; }
private:
bool lna_enabled = false;

20
variants/heltec_t096/T096Board.cpp

@ -123,4 +123,22 @@ void T096Board::powerOff() {
const char* T096Board::getManufacturerName() const {
return "Heltec T096";
}
}
bool T096Board::setLoRaFemLnaEnabled(bool enable) {
if (!loRaFEMControl.isLnaCanControl()) {
return false;
}
loRaFEMControl.setLNAEnable(enable);
loRaFEMControl.setRxModeEnable();
return true;
}
bool T096Board::canControlLoRaFemLna() const {
return loRaFEMControl.isLnaCanControl();
}
bool T096Board::isLoRaFemLnaEnabled() const {
return loRaFEMControl.isLNAEnabled();
}

3
variants/heltec_t096/T096Board.h

@ -25,4 +25,7 @@ public:
uint16_t getBattMilliVolts() override;
const char* getManufacturerName() const override ;
void powerOff() override;
bool setLoRaFemLnaEnabled(bool enable) override;
bool canControlLoRaFemLna() const override;
bool isLoRaFemLnaEnabled() const override;
};

18
variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp

@ -82,3 +82,21 @@ void HeltecTrackerV2Board::begin() {
const char* HeltecTrackerV2Board::getManufacturerName() const {
return "Heltec Tracker V2";
}
bool HeltecTrackerV2Board::setLoRaFemLnaEnabled(bool enable) {
if (!loRaFEMControl.isLnaCanControl()) {
return false;
}
loRaFEMControl.setLNAEnable(enable);
loRaFEMControl.setRxModeEnable();
return true;
}
bool HeltecTrackerV2Board::canControlLoRaFemLna() const {
return loRaFEMControl.isLnaCanControl();
}
bool HeltecTrackerV2Board::isLoRaFemLnaEnabled() const {
return loRaFEMControl.isLNAEnabled();
}

3
variants/heltec_tracker_v2/HeltecTrackerV2Board.h

@ -21,5 +21,8 @@ public:
void powerOff() override;
uint16_t getBattMilliVolts() override;
const char* getManufacturerName() const override ;
bool setLoRaFemLnaEnabled(bool enable) override;
bool canControlLoRaFemLna() const override;
bool isLoRaFemLnaEnabled() const override;
};

3
variants/heltec_tracker_v2/LoRaFEMControl.h

@ -12,8 +12,9 @@ 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; }
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
bool isLNAEnabled(void) const { return lna_enabled; }
private:
bool lna_enabled = false;

18
variants/heltec_v4/HeltecV4Board.cpp

@ -83,3 +83,21 @@ 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();
}

3
variants/heltec_v4/HeltecV4Board.h

@ -25,6 +25,9 @@ public:
void onAfterTransmit(void) override;
void enterDeepSleep(uint32_t secs, int pin_wake_btn = -1);
void powerOff() override;
bool setLoRaFemLnaEnabled(bool enable) override;
bool canControlLoRaFemLna() const override;
bool isLoRaFemLnaEnabled() const override;
uint16_t getBattMilliVolts() override;
bool setAdcMultiplier(float multiplier) override {
if (multiplier == 0.0f) {

3
variants/heltec_v4/LoRaFEMControl.h

@ -18,8 +18,9 @@ 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; }
void setLnaCanControl(bool can_control) { lna_can_control = can_control; }
bool isLNAEnabled(void) const { return lna_enabled; }
LoRaFEMType getFEMType(void) const { return fem_type; }
private:
LoRaFEMType fem_type=OTHER_FEM_TYPES;

Loading…
Cancel
Save