clamp TX on station G2, refactor "set af"

This commit is contained in:
liquidraver
2026-02-21 20:19:16 +01:00
parent 9034e87a7f
commit 521955bc05
5 changed files with 56 additions and 5 deletions
+18
View File
@@ -256,6 +256,24 @@ config ZEPHCORE_RADIO_LR1110
endchoice
config ZEPHCORE_DEFAULT_TX_POWER_DBM
int "Default TX power (dBm)"
default 22
range -9 22
help
Default SX1262 TX power in dBm for fresh devices (no saved prefs).
Boards with external PA should set this lower to avoid overdriving.
Example: Station G2 with 20dB PA gain uses 15 dBm (→ 35 dBm output).
config ZEPHCORE_MAX_TX_POWER_DBM
int "Maximum TX power (dBm)"
default 22
range -9 22
help
Hard cap on SX1262 TX power. The radio adapter clamps any value
above this, protecting external PAs from damage.
Example: Station G2 caps at 19 dBm to stay below PA P1dB (35 dBm).
endmenu # Radio Configuration
menu "Board Configuration"
@@ -186,6 +186,11 @@ void LoRaRadioBase::buildModemConfig(struct lora_modem_config &cfg, bool tx)
cfg.preamble_len = LoRaConfig::PREAMBLE_LEN;
cfg.tx_power = _prefs ? (int8_t)_prefs->tx_power_dbm
: LoRaConfig::TX_POWER_DBM;
#ifdef CONFIG_ZEPHCORE_MAX_TX_POWER_DBM
if (cfg.tx_power > CONFIG_ZEPHCORE_MAX_TX_POWER_DBM) {
cfg.tx_power = CONFIG_ZEPHCORE_MAX_TX_POWER_DBM;
}
#endif
cfg.tx = tx;
cfg.iq_inverted = false;
cfg.public_network = false;
@@ -17,5 +17,11 @@ CONFIG_BT_DIS_MODEL_NUMBER_STR="BQ Station G2"
# Radio type — SX1262 via Zephyr native LoRa driver
CONFIG_ZEPHCORE_RADIO_NATIVE=y
# TX power limits — Station G2 has ~20dB external PA.
# Default 15 dBm → ~35 dBm output (P1dB point).
# Cap at 19 dBm → ~39 dBm absolute max (matches Arduino MAX_LORA_TX_POWER).
CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM=15
CONFIG_ZEPHCORE_MAX_TX_POWER_DBM=19
# Flash size — 16MB (override Zephyr default)
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
+23 -5
View File
@@ -111,6 +111,11 @@ void CommonCLI::loadPrefs(const char* path) {
_prefs->sf = constrain(_prefs->sf, (uint8_t)5, (uint8_t)12);
_prefs->cr = constrain(_prefs->cr, (uint8_t)5, (uint8_t)8);
_prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, (uint8_t)1, (uint8_t)30);
#ifdef CONFIG_ZEPHCORE_MAX_TX_POWER_DBM
if (_prefs->tx_power_dbm > CONFIG_ZEPHCORE_MAX_TX_POWER_DBM) {
_prefs->tx_power_dbm = (uint8_t)CONFIG_ZEPHCORE_MAX_TX_POWER_DBM;
}
#endif
_prefs->multi_acks = constrain(_prefs->multi_acks, (uint8_t)0, (uint8_t)1);
_prefs->adc_multiplier = constrain(_prefs->adc_multiplier, 0.0f, 10.0f);
_prefs->powersaving_enabled = constrain(_prefs->powersaving_enabled, (uint8_t)0, (uint8_t)1);
@@ -317,7 +322,8 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else if (memcmp(command, "get ", 4) == 0) {
const char* config = &command[4];
if (memcmp(config, "af", 2) == 0) {
snprintf(reply, CLI_REPLY_SIZE, "> %.0f%%", (double)_prefs->airtime_factor);
int dc = (_prefs->airtime_factor == 0.0f) ? 100 : (int)_prefs->airtime_factor;
snprintf(reply, CLI_REPLY_SIZE, "> Duty Cycle: %d%%", dc);
} else if (memcmp(config, "int.thresh", 10) == 0) {
snprintf(reply, CLI_REPLY_SIZE, "> %u", (uint32_t)_prefs->interference_threshold);
} else if (memcmp(config, "agc.reset.interval", 18) == 0) {
@@ -391,9 +397,15 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
} else if (memcmp(command, "set ", 4) == 0) {
const char* config = &command[4];
if (memcmp(config, "af ", 3) == 0) {
_prefs->airtime_factor = atof(&config[3]);
int val = atoi(&config[3]);
if (val <= 0 || val >= 100) {
_prefs->airtime_factor = 0.0f;
} else {
_prefs->airtime_factor = (float)val;
}
savePrefs();
strcpy(reply, "OK");
int dc = (_prefs->airtime_factor == 0.0f) ? 100 : (int)_prefs->airtime_factor;
snprintf(reply, CLI_REPLY_SIZE, "Duty Cycle set: %d%%", dc);
} else if (memcmp(config, "int.thresh ", 11) == 0) {
_prefs->interference_threshold = atoi(&config[11]);
savePrefs();
@@ -532,10 +544,16 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch
savePrefs();
strcpy(reply, "OK");
} else if (memcmp(config, "tx ", 3) == 0) {
_prefs->tx_power_dbm = atoi(&config[3]);
int val = atoi(&config[3]);
#ifdef CONFIG_ZEPHCORE_MAX_TX_POWER_DBM
if (val > CONFIG_ZEPHCORE_MAX_TX_POWER_DBM) {
val = CONFIG_ZEPHCORE_MAX_TX_POWER_DBM;
}
#endif
_prefs->tx_power_dbm = (uint8_t)val;
savePrefs();
_callbacks->setTxPower(_prefs->tx_power_dbm);
strcpy(reply, "OK");
snprintf(reply, CLI_REPLY_SIZE, "OK - tx power=%u dBm", (uint32_t)_prefs->tx_power_dbm);
} else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) {
_prefs->freq = atof(&config[5]);
savePrefs();
+4
View File
@@ -90,7 +90,11 @@ static inline void initNodePrefs(NodePrefs* prefs) {
prefs->bw = 62.5f; // LoRaConfig::BANDWIDTH
prefs->sf = 8; // LoRaConfig::SPREADING_FACTOR
prefs->cr = 8; // CR 4/8 (MeshCore uses 5-8 for CR 4/5 through 4/8)
#ifdef CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM
prefs->tx_power_dbm = CONFIG_ZEPHCORE_DEFAULT_TX_POWER_DBM;
#else
prefs->tx_power_dbm = 22; // LoRaConfig::TX_POWER_DBM
#endif
prefs->disable_fwd = 0;
prefs->advert_interval = 60; // 2 minutes (value / 2)
prefs->flood_advert_interval = 12; // 12 hours