mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-10-12 00:22:02 +00:00
feat(radio): honest TX power for GAT562 30S external PA
gat562_30s_mesh_kit has an always-on external PA rated at +30dBm, but the firmware wrote tx_power_dbm straight to the SX1262 register (capped at 22), so the app/CLI/UI never matched the real radiated power and couldn't ask for more than 22 even though the hardware supports it. Add a generic, macro-gated PA gain-curve resolution in RadioLibWrapper::setTxPower() (the single choke point every TX-power path already funnels through), reusable by any future board with a similar PA. For this board, reuse the vendor-measured 869MHz curve from the open upstream Meshtastic PR that added it for the same physical module (meshtastic/firmware#11212): pick the lowest SX1262 setting whose measured output reaches the requested dBm, clamped at the PA's saturation knee. Bump LORA_TX_POWER/MAX_LORA_TX_POWER to 30 for this variant only -- the other three GAT562 boards use the SX1262's own PA_BOOST (22dBm, no external PA) and are unaffected. Since a request below the PA's floor gain (14dBm) still radiates at that floor, also make CommonCLICallbacks::setTxPower() return what was actually applied, and have every setter (BLE CMD_SET_RADIO_TX_POWER, CLI "tx", simple_repeater/room_server/sensor) persist and report that value instead of the raw request -- so tx_power_dbm never silently disagrees with the physical output in either direction. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -706,9 +706,10 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
strcpy(reply, "OK");
|
||||
}
|
||||
} else if (memcmp(config, "tx ", 3) == 0) {
|
||||
_prefs->tx_power_dbm = atoi(&config[3]);
|
||||
// Store what the radio actually applied, not the raw request -- on a
|
||||
// board with an external-PA gain curve those can differ (see setTxPower()).
|
||||
_prefs->tx_power_dbm = _callbacks->setTxPower(atoi(&config[3]));
|
||||
savePrefs();
|
||||
_callbacks->setTxPower(_prefs->tx_power_dbm);
|
||||
strcpy(reply, "OK");
|
||||
} else if (sender_timestamp == 0 && memcmp(config, "freq ", 5) == 0) {
|
||||
_prefs->freq = atof(&config[5]);
|
||||
|
||||
@@ -207,7 +207,11 @@ public:
|
||||
virtual void setLoggingOn(bool enable) = 0;
|
||||
virtual void eraseLogFile() = 0;
|
||||
virtual void dumpLogFile() = 0;
|
||||
virtual void setTxPower(int8_t power_dbm) = 0;
|
||||
// Returns the dBm the radio actually applied -- on a board with an
|
||||
// external-PA gain curve this can differ from power_dbm (e.g. a request
|
||||
// below the PA's floor gain still radiates at that floor), so callers
|
||||
// should persist/report the return value, not the raw request.
|
||||
virtual int8_t setTxPower(int8_t power_dbm) = 0;
|
||||
virtual void formatNeighborsReply(char *reply) = 0;
|
||||
virtual void removeNeighbor(const uint8_t* pubkey, int key_len) {
|
||||
// no op by default
|
||||
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
((CustomSX1262 *)_radio)->setCodingRate(_wd_cr);
|
||||
updatePreamble(_wd_sf);
|
||||
}
|
||||
_radio->setOutputPower(getTxPower());
|
||||
setTxPower(getTxPower()); // re-run through the wrapper's own setter so any PA gain curve reapplies
|
||||
// Unconditional: std_init() may have just turned boosted gain back ON via
|
||||
// the board's SX126X_RX_BOOSTED_GAIN compile default, so the OFF case
|
||||
// needs reapplying just as much as ON.
|
||||
|
||||
@@ -52,8 +52,23 @@ uint32_t RadioLibWrapper::getRngSeed() {
|
||||
}
|
||||
|
||||
void RadioLibWrapper::setTxPower(int8_t dbm) {
|
||||
_tx_dbm = dbm;
|
||||
_tx_dbm = dbm; // logical/requested power -- what getTxPower(), the app and the CLI report
|
||||
#if defined(NUM_PA_POINTS) && defined(TX_GAIN_LORA)
|
||||
// Per-board external-PA gain curve (radio_dbm -> measured gain in dB, from
|
||||
// the vendor/GAT562-30S data cited in the upstream Meshtastic PR that added
|
||||
// it, meshtastic/firmware#11212). The PA is always-on (no enable pin), so
|
||||
// the SX1262 register alone decides real output; pick the lowest register
|
||||
// setting whose (setting + its measured gain) reaches the requested dBm,
|
||||
// clamping to the last entry once the PA saturates.
|
||||
static const int8_t pa_gain[NUM_PA_POINTS] = { TX_GAIN_LORA };
|
||||
int8_t radio_dbm = NUM_PA_POINTS - 1;
|
||||
for (int i = 0; i < NUM_PA_POINTS; i++) {
|
||||
if ((i + pa_gain[i]) >= dbm) { radio_dbm = i; break; }
|
||||
}
|
||||
_radio->setOutputPower(radio_dbm);
|
||||
#else
|
||||
_radio->setOutputPower(dbm);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RadioLibWrapper::idle() {
|
||||
|
||||
Reference in New Issue
Block a user