diff --git a/src/helpers/radiolib/DacPaSX1276Wrapper.h b/src/helpers/radiolib/DacPaSX1276Wrapper.h index bf8cea06..95832979 100644 --- a/src/helpers/radiolib/DacPaSX1276Wrapper.h +++ b/src/helpers/radiolib/DacPaSX1276Wrapper.h @@ -23,10 +23,28 @@ // static const DacPaLevel LEVELS[] = { {10, 30}, {17, 50}, {30, 130} }; // DacPaSX1276Wrapper radio_driver(radio, board, PIN_APC, LEVELS, 3); // -// Entries must be ordered by ascending dBm. The default drive level of +2 dBm -// is the SX1276's floor on PA_BOOST (RegPaConfig OutputPower = 0), which suits -// an amplifier expecting a small constant input; pass drive_dbm to override it -// for a PA that wants more. +// Entries must be ordered by ascending dBm. Nothing is assumed about the +// control codes themselves, so a board whose gain input runs backwards (a +// falling code for rising power) needs no special handling. +// +// The default drive level of +2 dBm is the SX1276's floor on PA_BOOST +// (RegPaConfig OutputPower = 0), which suits an amplifier expecting a small +// constant input; pass drive_dbm to override it for a PA that wants more. +// +// Not every board holds the radio still. Where the amplifier is driven +// somewhere other than its floor, the radio's own output moves with each step +// as well, and the board supplies a second table of radio output levels +// alongside the first. Pass it as radio_dbm and the fixed drive level is not +// used at all: +// +// static const DacPaLevel LEVELS[] = { {20, 165}, {24, 155}, {27, 142} }; +// static const int8_t RADIO_DBM[] = { 2, 6, 9 }; +// DacPaSX1276Wrapper radio_driver(radio, board, PIN_APC, LEVELS, 3, +// DAC_PA_TABLE_MAX, RADIO_DBM); +// +// radio_dbm must have one entry per level. Its values go to the SX1276 on the +// PA_BOOST path; a board wired to RFO_HF instead would need RadioLib's useRfo +// argument plumbed through, which this class does not do yet. // // The gain control is written through writeGainControl(), which uses the // ESP32's DAC by default. A board driving its PA from a PWM pin or an external @@ -69,10 +87,11 @@ public: uint8_t ctrl_pin, const DacPaLevel* levels, uint8_t num_levels, int8_t max_dbm = DAC_PA_TABLE_MAX, + const int8_t* radio_dbm = NULL, int8_t drive_dbm = DAC_PA_DEFAULT_DRIVE_DBM) : CustomSX1276Wrapper(radio, board), _ctrl_pin(ctrl_pin), _levels(levels), _num_levels(num_levels), - _drive_dbm(drive_dbm) { + _radio_dbm(radio_dbm), _drive_dbm(drive_dbm) { _min_dbm = levels[0].dbm; _max_dbm = levels[num_levels - 1].dbm; if (max_dbm < _max_dbm) _max_dbm = max_dbm; @@ -87,8 +106,13 @@ public: // Park the radio at its drive level and set the amplifier to dbm. Call once, // after the radio has started. A startup level outside the supported range // is brought into it rather than left unset. + // + // Boards carrying a radio_dbm table have no fixed drive level to park at; + // applyCachedTxPower() sets the radio for each step instead. void beginPowerControl(int8_t dbm) { - ((CustomSX1276 *)_radio)->setOutputPower(_drive_dbm); + if (_radio_dbm == NULL) { + ((CustomSX1276 *)_radio)->setOutputPower(_drive_dbm); + } if (dbm < _min_dbm) dbm = _min_dbm; if (dbm > _max_dbm) dbm = _max_dbm; applyCachedTxPower(dbm); @@ -111,23 +135,33 @@ protected: if (dbm < _min_dbm || dbm > _max_dbm) { return RADIOLIB_ERR_INVALID_OUTPUT_POWER; } - writeGainControl(codeForDbm(dbm)); + const uint8_t idx = indexForDbm(dbm); + if (_radio_dbm != NULL) { + // Move the radio first: on the way up this is the smaller of the two + // steps, so the amplifier is never asked to pass a level the radio has + // already exceeded. + const int16_t status = + ((CustomSX1276 *)_radio)->setOutputPower(_radio_dbm[idx]); + if (status != RADIOLIB_ERR_NONE) return status; + } + writeGainControl(_levels[idx].dac); return RADIOLIB_ERR_NONE; } private: // Highest level that does not exceed dbm. Callers have already range-checked. - uint8_t codeForDbm(int8_t dbm) const { - uint8_t code = _levels[0].dac; + uint8_t indexForDbm(int8_t dbm) const { + uint8_t idx = 0; for (uint8_t i = 0; i < _num_levels; i++) { - if (_levels[i].dbm <= dbm) code = _levels[i].dac; + if (_levels[i].dbm <= dbm) idx = i; } - return code; + return idx; } uint8_t _ctrl_pin; const DacPaLevel* _levels; uint8_t _num_levels; + const int8_t* _radio_dbm; int8_t _drive_dbm; int8_t _min_dbm; int8_t _max_dbm;