mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-23 18:02:29 +00:00
Restore SX1276 CW support and calibrated power sweeps
Retain the original carrier feature from PR #11 with zero-deviation FSK, board PA calibration, and LoRa restoration. Re-key after power changes without extending the timeout, and restore prior power after a failed sweep. Cover native and SX1276 transitions, failure recovery, external PA and RFO mapping; verify Linkflow repeater and Heltec V2 USB Companion builds.
This commit is contained in:
1 parent
9de1373bd9
commit
27e4a0d0db
6 files changed
+226
-14
No files matched your search
@@ -2,7 +2,7 @@
|
||||
|
||||
`cw` and `cw2` transmit a continuous, unmodulated carrier at the selected
|
||||
profile's frequency and the configured TX power. They are available in the
|
||||
shared ASCII CLI on SX1262-family and LR1110 builds, including repeaters,
|
||||
shared ASCII CLI on SX1276-family, SX1262-family, and LR1110 builds, including repeaters,
|
||||
Companions, room servers, and sensors that use that CLI.
|
||||
|
||||
| Command | Action |
|
||||
@@ -32,6 +32,12 @@ or a busy radio. Profile retuning waits until the carrier stops; replacement
|
||||
or expiry of the active second profile stops its carrier. Nothing about CW
|
||||
is saved across reboot.
|
||||
|
||||
The normal `set tx <dBm>` command also works during CW for meter sweeps. It
|
||||
keeps the board's power limits and PA calibration, resumes the carrier after
|
||||
changing power, and does not extend the CW timeout. TX power retains its usual
|
||||
saved behavior. SX1276 temporarily uses FSK with zero frequency deviation,
|
||||
then rebuilds the LoRa configuration before resuming reception.
|
||||
|
||||
Use the local USB or BLE console for immediate replies and manual stopping.
|
||||
An on-air CLI reply must wait until the carrier ends because LoRa packets
|
||||
cannot transmit during the test.
|
||||
|
||||
@@ -46,6 +46,30 @@ no outbound packet pending. The observer has no autonomous transmission.
|
||||
`src/Mesh.cpp` and test-file contents; the actual implementation uses
|
||||
`ota_context_if_active()`. This is separate from the CW changes.
|
||||
|
||||
## SX1276 follow-up
|
||||
|
||||
The SX1276 carrier feature from [PR #11](https://github.com/mikecarper/MeshCore/pull/11)
|
||||
is included alongside SX1262 and LR1110 support. It switches to FSK with zero
|
||||
deviation, applies the board's calibrated TX power, and rebuilds the runtime
|
||||
LoRa configuration when stopped. External-PA settings pass through the same
|
||||
DAC/drive-power mapping used for packets, including RFO selection.
|
||||
|
||||
The normal TX power command can adjust a running carrier for meter sweeps.
|
||||
RadioLib's SX1276 power setter enters standby, so the carrier is restarted
|
||||
afterward without extending the deadline. Failed power changes stop the
|
||||
carrier and restore the previous cached power.
|
||||
|
||||
Follow-up checks use base `9dd9881d520b4b791600a00fff1f8e1436921054` plus the
|
||||
SX1276 changes. Production-method regression tests cover both profiles,
|
||||
zero deviation, external-PA calibration, RFO, power sweeps, timeout, failed
|
||||
FSK entry, failed restoration, retry guards, and return to LoRa. The native
|
||||
CW paths and existing radio/profile/sleep/PA checks pass as well.
|
||||
Both `GEPRC_Linkflow_900_repeater` (external PA) and
|
||||
`Heltec_v2_companion_radio_usb` firmware builds pass, including size checks.
|
||||
|
||||
SX1276 RF output has not been measured in this follow-up. The physical RF
|
||||
results above apply to SX1262 and LR1110.
|
||||
|
||||
## Bench qualifications
|
||||
|
||||
The first CW2 request arrived before radio2's existing delayed activation.
|
||||
|
||||
@@ -10,8 +10,12 @@
|
||||
class CustomSX1276Wrapper : public RadioLibWrapper {
|
||||
public:
|
||||
CustomSX1276Wrapper(CustomSX1276& radio, mesh::MainBoard& board) : RadioLibWrapper(radio, board) { }
|
||||
bool supportsCarrierWave() const override { return supportsRadioDeepInit(); }
|
||||
|
||||
void powerOff() { _radio->standby(); _radio->sleep(); }
|
||||
void powerOff() {
|
||||
if (isCarrierWaveActive()) setCarrierWave(0, 0);
|
||||
_radio->standby(); _radio->sleep();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool applyParams(float freq, float bw, uint8_t sf, uint8_t cr) override {
|
||||
@@ -24,6 +28,7 @@ protected:
|
||||
|
||||
public:
|
||||
bool setCodingRate(uint8_t cr) override {
|
||||
if (isCarrierWaveActive()) return false;
|
||||
return ((CustomSX1276 *)_radio)->setCodingRate(cr) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
|
||||
@@ -40,6 +45,28 @@ public:
|
||||
uint8_t getSpreadingFactor() const override { return ((CustomSX1276 *)_radio)->spreadingFactor; }
|
||||
|
||||
protected:
|
||||
int16_t enterCarrierWave() override {
|
||||
auto* radio = static_cast<CustomSX1276*>(_radio);
|
||||
// Direct TX needs FSK. Zero deviation prevents a floating DIO2 data input
|
||||
// from moving the carrier. Start at the PA_BOOST floor, while still idle;
|
||||
// user-facing power may be an external PA level, not chip drive power.
|
||||
int16_t status = radio->beginFSK(_cur_freq, 4.8, 0.0, 125.0, 2, 16, false);
|
||||
if (status != RADIOLIB_ERR_NONE) return status;
|
||||
#ifdef SX127X_CURRENT_LIMIT
|
||||
status = radio->setCurrentLimit(SX127X_CURRENT_LIMIT);
|
||||
if (status != RADIOLIB_ERR_NONE) return status;
|
||||
#endif
|
||||
status = applyCachedTxPower(_dbm_valid ? _cur_dbm : LORA_TX_POWER);
|
||||
if (status != RADIOLIB_ERR_NONE) return status;
|
||||
return radio->transmitDirect();
|
||||
}
|
||||
|
||||
bool restoreCarrierWaveModem() override {
|
||||
// Restores LoRa, runtime profile/preamble, IRQ mapping and PA calibration.
|
||||
// Shared cleanup retains the stop/retry guard if any restoration fails.
|
||||
return restoreAfterDeepInit();
|
||||
}
|
||||
|
||||
int16_t performChannelScan() override {
|
||||
return ((CustomSX1276 *)_radio)->tryScanChannel(cadScanTimeoutMillis(), *_board);
|
||||
}
|
||||
|
||||
@@ -89,6 +89,23 @@ uint32_t RadioLibWrapper::getRngSeed() {
|
||||
}
|
||||
|
||||
bool RadioLibWrapper::setTxPower(int8_t dbm) {
|
||||
if (_cw_active) {
|
||||
if (_cw_stopping) return false;
|
||||
// Permit meter sweeps through the board's normal power/PA calibration.
|
||||
// SX127x's power setter enters standby, so re-key without resetting the
|
||||
// modem or extending the original CW deadline.
|
||||
if (applyCachedTxPower(dbm) != RADIOLIB_ERR_NONE) {
|
||||
stopCarrierWave();
|
||||
return false;
|
||||
}
|
||||
if (_radio->transmitDirect() != RADIOLIB_ERR_NONE) {
|
||||
stopCarrierWave();
|
||||
return false;
|
||||
}
|
||||
_cur_dbm = dbm;
|
||||
_dbm_valid = true;
|
||||
return true;
|
||||
}
|
||||
const uint8_t resume_rx = beginReconfigure();
|
||||
if (resume_rx > 1) return false;
|
||||
|
||||
@@ -707,7 +724,7 @@ mesh::RadioParamApplyResult RadioLibWrapper::setCarrierWave(uint8_t profile, uin
|
||||
_board->setRadioTestActive(true); // service the deadline even without USB
|
||||
_board->onBeforeTransmit();
|
||||
_cw_board_tx = true;
|
||||
if (_radio->transmitDirect() != RADIOLIB_ERR_NONE) {
|
||||
if (enterCarrierWave() != RADIOLIB_ERR_NONE) {
|
||||
stopCarrierWave(); // a failed SPI result does not prove TX stayed off
|
||||
return Result::FAILED;
|
||||
}
|
||||
@@ -717,11 +734,13 @@ mesh::RadioParamApplyResult RadioLibWrapper::setCarrierWave(uint8_t profile, uin
|
||||
|
||||
bool RadioLibWrapper::stopCarrierWave() {
|
||||
_cw_stopping = true;
|
||||
// finishTransmit clears radio IRQs and enters standby on both supported
|
||||
// families. Deassert external TX even if SPI fails, then try a radio reset.
|
||||
// Deassert external TX even if SPI fails. SX127x must also rebuild its LoRa
|
||||
// modem after FSK direct mode before normal packet work can resume.
|
||||
const int16_t status = _radio->finishTransmit();
|
||||
if (_cw_board_tx) { _board->onAfterTransmit(); _cw_board_tx = false; }
|
||||
if (status != RADIOLIB_ERR_NONE && !restoreAfterDeepInit()) {
|
||||
const bool restored = status == RADIOLIB_ERR_NONE
|
||||
? restoreCarrierWaveModem() : restoreAfterDeepInit();
|
||||
if (!restored) {
|
||||
_cw_retry_at = static_cast<uint32_t>(millis()) + 100;
|
||||
return false; // hold normal work until stopping the carrier is confirmed
|
||||
}
|
||||
|
||||
@@ -157,6 +157,12 @@ protected:
|
||||
return _radio->setOutputPower(dbm);
|
||||
}
|
||||
virtual bool applyRxBoostedGainMode(bool) { return false; }
|
||||
virtual int16_t enterCarrierWave() { return _radio->transmitDirect(); }
|
||||
// Native-CW radios keep their modem. Reapply cached power in case a meter
|
||||
// sweep failed halfway through; SX127x also rebuilds its LoRa configuration.
|
||||
virtual bool restoreCarrierWaveModem() {
|
||||
return !_dbm_valid || applyCachedTxPower(_cur_dbm) == RADIOLIB_ERR_NONE;
|
||||
}
|
||||
// Dual-profile scanning already suspends RXPS. Supported radios can also
|
||||
// retain their oscillator across the intervening standby/reconfigure steps.
|
||||
// Called only at the safe scan-mode entry/exit boundary, not during a packet.
|
||||
|
||||
+138
-8
@@ -18,6 +18,9 @@ HARNESS = r'''
|
||||
#define STATE_TX_WAIT 3
|
||||
#define STATE_INT_READY 16
|
||||
#define RADIOLIB_ERR_NONE 0
|
||||
#define RADIOLIB_ERR_INVALID_OUTPUT_POWER -1
|
||||
#define SX127X_CURRENT_LIMIT 120
|
||||
#define LORA_TX_POWER 17
|
||||
#define MESH_DEBUG_PRINTLN(...) ((void)0)
|
||||
static uint8_t state;
|
||||
static void setFlag() { state |= STATE_INT_READY; }
|
||||
@@ -28,17 +31,30 @@ struct Board {
|
||||
void onAfterTransmit() { ++after; }
|
||||
};
|
||||
struct Chip {
|
||||
int start_result=0, stop_result=0;
|
||||
unsigned starts=0, stops=0, standby_calls=0;
|
||||
bool carrier=false;
|
||||
int start_result=0, stop_result=0, fsk_result=0, power_result=0, limit_result=0;
|
||||
int power=17, initial_fsk_power=0, current_limit=60;
|
||||
unsigned starts=0, stops=0, standby_calls=0, fsk_starts=0;
|
||||
float frequency=0, deviation=5;
|
||||
bool carrier=false, fsk=false, ook=true, rfo=false;
|
||||
void (*callback)()=setFlag;
|
||||
int standby() { ++standby_calls; return 0; }
|
||||
int standby() { ++standby_calls; carrier=false; return 0; }
|
||||
int beginFSK(float freq, float, float dev, float, int8_t dbm, uint16_t, bool enable_ook) {
|
||||
++fsk_starts; fsk=true; carrier=false; frequency=freq; deviation=dev;
|
||||
initial_fsk_power=power=dbm; ook=enable_ook; current_limit=60;
|
||||
return fsk_result;
|
||||
}
|
||||
int setCurrentLimit(int value) { current_limit=value; return limit_result; }
|
||||
int setOutputPower(int8_t value, bool force_rfo=false) {
|
||||
standby(); if (power_result) return power_result;
|
||||
power=value; rfo=force_rfo; return 0;
|
||||
}
|
||||
int clearIrqFlags(uint32_t) { return 0; }
|
||||
void clearPacketReceivedAction() { callback=nullptr; }
|
||||
void setPacketReceivedAction(void (*fn)()) { callback=fn; }
|
||||
int transmitDirect() { carrier=true; ++starts; return start_result; }
|
||||
int finishTransmit() { ++stops; if (!stop_result) carrier=false; return stop_result; }
|
||||
};
|
||||
using CustomSX1276=Chip;
|
||||
struct RadioLibWrapper : mesh::Radio {
|
||||
Chip chip; Chip* _radio=&chip;
|
||||
Board board; Board* _board=&board;
|
||||
@@ -49,11 +65,14 @@ struct RadioLibWrapper : mesh::Radio {
|
||||
bool _params_valid=true, _rx_ps_armed=true, _rx_hold_continuous=false;
|
||||
bool _nf_calib_active=true, _profile_refresh_required=false;
|
||||
unsigned long _wd_observe_until=0;
|
||||
bool packet=false, busy=false, reset_ok=false, supported=true;
|
||||
bool packet=false, busy=false, reset_ok=false, supported=true, deep_supported=true;
|
||||
unsigned rtc_stops=0, tunes=0, rx_starts=0, calibrations=0, resets=0;
|
||||
unsigned fail_rx_starts=0;
|
||||
bool fail_tune=false;
|
||||
float frequency=909.5;
|
||||
float _cur_freq=909.5;
|
||||
int8_t _cur_dbm=17;
|
||||
bool _dbm_valid=true;
|
||||
RadioLibWrapper() {
|
||||
g_mock_millis=100; state=STATE_RX;
|
||||
_profiles.primary.freq=909.5;
|
||||
@@ -68,7 +87,11 @@ struct RadioLibWrapper : mesh::Radio {
|
||||
mesh::RadioParamApplyResult setCarrierWave(uint8_t,uint32_t) override;
|
||||
bool stopCarrierWave();
|
||||
bool serviceCarrierWave();
|
||||
bool setTxPower(int8_t dbm);
|
||||
@NATIVE_HOOKS@
|
||||
virtual bool supportsRadioDeepInit() const { return deep_supported; }
|
||||
uint8_t beginReconfigure();
|
||||
void endReconfigure(bool resume) { if (resume) startRecv(); }
|
||||
bool isChipBusy() { return busy; }
|
||||
bool isReceivingPacket() { return packet; }
|
||||
bool isInRecvMode() const override { return (state & ~STATE_INT_READY)==STATE_RX; }
|
||||
@@ -76,7 +99,7 @@ struct RadioLibWrapper : mesh::Radio {
|
||||
mesh::RadioParamApplyResult tuneProfile(uint8_t target) {
|
||||
++tunes;
|
||||
if (fail_tune) return mesh::RadioParamApplyResult::FAILED;
|
||||
_active_profile=target; frequency=_profiles.params(target).freq;
|
||||
_active_profile=target; frequency=_cur_freq=_profiles.params(target).freq;
|
||||
return mesh::RadioParamApplyResult::APPLIED;
|
||||
}
|
||||
void startRecv() override {
|
||||
@@ -86,7 +109,10 @@ struct RadioLibWrapper : mesh::Radio {
|
||||
}
|
||||
bool restoreAfterDeepInit() {
|
||||
++resets;
|
||||
if (reset_ok) { chip.carrier=false; chip.stop_result=0; }
|
||||
if (reset_ok) {
|
||||
chip.carrier=false; chip.fsk=false; chip.stop_result=0;
|
||||
return applyCachedTxPower(_cur_dbm)==0;
|
||||
}
|
||||
return reset_ok;
|
||||
}
|
||||
void recalibrateNoiseFloor() override { ++calibrations; }
|
||||
@@ -98,6 +124,21 @@ struct RadioLibWrapper : mesh::Radio {
|
||||
void onSendFinished() override {}
|
||||
};
|
||||
@METHODS@
|
||||
struct CustomSX1276Wrapper : RadioLibWrapper {
|
||||
CustomSX1276Wrapper() { reset_ok=true; }
|
||||
@SX1276_METHODS@
|
||||
};
|
||||
struct DacPaLevel { int8_t dbm; uint8_t dac; };
|
||||
struct DacCarrier : CustomSX1276Wrapper {
|
||||
int8_t _min_dbm=17, _max_dbm=30, _drive_dbm=2;
|
||||
DacPaLevel _levels[3]={{17,0},{24,50},{30,130}};
|
||||
uint8_t _num_levels=3;
|
||||
const int8_t* _radio_dbm=nullptr;
|
||||
bool _force_rfo=false;
|
||||
int gain=-1;
|
||||
void writeGainControl(uint8_t value) { gain=value; }
|
||||
@DAC_METHODS@
|
||||
};
|
||||
static void advance(uint32_t ms) { g_mock_millis+=ms; }
|
||||
int main() {
|
||||
using Result=mesh::RadioParamApplyResult;
|
||||
@@ -114,6 +155,12 @@ int main() {
|
||||
assert(w.frequency==909.5f && w.board.after==1 && !w.board.awake && w.chip.callback);
|
||||
assert(!w.serviceCarrierWave());
|
||||
}
|
||||
{
|
||||
RadioLibWrapper w; w.setCarrierWave(0,1250); advance(250);
|
||||
assert(w.setTxPower(10) && w.chip.carrier && w.chip.power==10);
|
||||
assert(w.carrierWaveRemainingMillis()==1000);
|
||||
assert(w.setCarrierWave(0,0)==Result::APPLIED);
|
||||
}
|
||||
// No mutation of packets already transmitting, completed RX, busy or receiving hardware.
|
||||
for (int reason : {0,1,2,3}) {
|
||||
RadioLibWrapper w;
|
||||
@@ -198,7 +245,78 @@ int main() {
|
||||
char small[8]; mesh::handleCarrierWaveCommand(&w,"cw on",small,sizeof(small));
|
||||
assert(small[7]==0);
|
||||
}
|
||||
puts("CW: transitions, timer rollover, profiles, RF hooks, failure recovery and CLI passed");
|
||||
// Execute SX1276's production FSK entry/LoRa restoration, including the
|
||||
// production external-PA power mapping. Native CW paths above stay covered.
|
||||
for (uint8_t profile : {0,1}) {
|
||||
CustomSX1276Wrapper w;
|
||||
w._cur_dbm=14;
|
||||
assert(w.supportsCarrierWave() && w.setCarrierWave(profile,1250)==Result::APPLIED);
|
||||
assert(w.chip.fsk && w.chip.deviation==0 && !w.chip.ook && w.chip.carrier);
|
||||
assert(w.chip.frequency==(profile ? 911.5f : 909.5f));
|
||||
assert(w.chip.initial_fsk_power==2 && w.chip.power==14 && w.chip.current_limit==120);
|
||||
advance(250);
|
||||
assert(w.setTxPower(10) && w.chip.carrier && w.chip.power==10);
|
||||
assert(w.chip.fsk_starts==1 && w.carrierWaveRemainingMillis()==1000);
|
||||
advance(1000); w.serviceCarrierWave();
|
||||
assert(!w._cw_active && !w.chip.fsk && w.isInRecvMode() && w.frequency==909.5f);
|
||||
assert(w.resets==1 && w.chip.power==10 && !w.board.awake && w.board.after==1);
|
||||
}
|
||||
{
|
||||
DacCarrier w; w._cur_dbm=30;
|
||||
assert(w.setCarrierWave(1,1000)==Result::APPLIED);
|
||||
assert(w.chip.initial_fsk_power==2 && w.chip.power==2 && w.gain==130 && w.chip.carrier);
|
||||
advance(200);
|
||||
assert(w.setTxPower(24) && w.chip.power==2 && w.gain==50 && w.chip.carrier);
|
||||
assert(w.carrierWaveRemainingMillis()==800 && w.chip.fsk_starts==1);
|
||||
assert(w.setCarrierWave(0,0)==Result::APPLIED);
|
||||
assert(w.chip.power==2 && w.gain==50 && !w.chip.fsk && w.resets==1);
|
||||
}
|
||||
{
|
||||
DacCarrier w; w._force_rfo=true; w._drive_dbm=-4;
|
||||
assert(w.setCarrierWave(0,100)==Result::APPLIED);
|
||||
assert(w.chip.rfo && w.chip.power==-4);
|
||||
assert(w.setCarrierWave(0,0)==Result::APPLIED && w.chip.rfo && w.chip.power==-4);
|
||||
}
|
||||
{
|
||||
CustomSX1276Wrapper w; w.deep_supported=false;
|
||||
assert(!w.supportsCarrierWave() && w.setCarrierWave(0,100)==Result::FAILED);
|
||||
assert(!w.chip.fsk_starts);
|
||||
}
|
||||
// Partial FSK entry and current-limit failures restore LoRa without keying.
|
||||
for (int reason : {0,1,2}) {
|
||||
CustomSX1276Wrapper w;
|
||||
if (reason==0) w.chip.fsk_result=-707;
|
||||
if (reason==1) w.chip.limit_result=-705;
|
||||
if (reason==2) w.chip.power_result=-705;
|
||||
assert(w.setCarrierWave(0,100)==Result::FAILED && !w.chip.starts && !w.chip.carrier);
|
||||
w.chip.power_result=0;
|
||||
if (w._cw_active) { advance(100); w.serviceCarrierWave(); }
|
||||
assert(!w._cw_active && !w.chip.fsk && w.isInRecvMode() && !w.board.awake);
|
||||
}
|
||||
{
|
||||
CustomSX1276Wrapper w; w.setCarrierWave(1,1000); w.reset_ok=false;
|
||||
assert(w.setCarrierWave(0,0)==Result::FAILED);
|
||||
assert(w._cw_active && w._cw_stopping && !w.chip.carrier && w.chip.fsk);
|
||||
assert(!w.setTxPower(10)); // recovery cannot accidentally re-key the PA
|
||||
w.reset_ok=true; advance(100); w.serviceCarrierWave();
|
||||
assert(!w._cw_active && !w.chip.fsk && w.isInRecvMode() && w.board.after==1);
|
||||
}
|
||||
for (int reason : {0,1}) {
|
||||
CustomSX1276Wrapper w; w.setCarrierWave(0,1000);
|
||||
if (reason==0) w.chip.power_result=-705;
|
||||
if (reason==1) w.chip.start_result=-705;
|
||||
assert(!w.setTxPower(10) && !w.chip.carrier);
|
||||
w.chip.power_result=0; advance(100); w.serviceCarrierWave();
|
||||
assert(!w._cw_active && !w.chip.fsk && w.isInRecvMode());
|
||||
assert(w._cur_dbm==17 && w.chip.power==17); // failed sweep retains old power
|
||||
}
|
||||
{
|
||||
RadioLibWrapper w; w.setCarrierWave(0,1000);
|
||||
w.chip.start_result=-705;
|
||||
assert(!w.setTxPower(10) && !w.chip.carrier && w.isInRecvMode());
|
||||
assert(w._cur_dbm==17 && w.chip.power==17);
|
||||
}
|
||||
puts("CW: native/SX1276 transitions, fractional CLI, PA sweeps, restoration and fault recovery passed");
|
||||
}
|
||||
'''
|
||||
|
||||
@@ -207,11 +325,23 @@ class CarrierWaveTest(unittest.TestCase):
|
||||
def test_production_transitions_and_commands(self):
|
||||
source = (ROOT/'src/helpers/radiolib/RadioLibWrappers.cpp').read_text()
|
||||
signatures = ('uint8_t RadioLibWrapper::beginReconfigure(',
|
||||
'bool RadioLibWrapper::setTxPower(',
|
||||
'mesh::RadioParamApplyResult RadioLibWrapper::setCarrierWave(',
|
||||
'uint32_t RadioLibWrapper::carrierWaveRemainingMillis(',
|
||||
'bool RadioLibWrapper::stopCarrierWave(',
|
||||
'bool RadioLibWrapper::serviceCarrierWave(')
|
||||
code = HARNESS.replace('@METHODS@', '\n'.join(method(source, s) for s in signatures))
|
||||
header = (ROOT/'src/helpers/radiolib/RadioLibWrappers.h').read_text()
|
||||
code = code.replace('@NATIVE_HOOKS@', '\n'.join(method(header, s) for s in (
|
||||
'virtual int16_t enterCarrierWave(', 'virtual bool restoreCarrierWaveModem(',
|
||||
'virtual int16_t applyCachedTxPower(')))
|
||||
sx1276 = (ROOT/'src/helpers/radiolib/CustomSX1276Wrapper.h').read_text()
|
||||
code = code.replace('@SX1276_METHODS@', '\n'.join(method(sx1276, s) for s in (
|
||||
'bool supportsCarrierWave(', 'int16_t enterCarrierWave(',
|
||||
'bool restoreCarrierWaveModem(')))
|
||||
dac = (ROOT/'src/helpers/radiolib/DacPaSX1276Wrapper.h').read_text()
|
||||
code = code.replace('@DAC_METHODS@', '\n'.join(method(dac, s) for s in (
|
||||
'int16_t applyCachedTxPower(', 'uint8_t indexForDbm(')))
|
||||
with tempfile.TemporaryDirectory() as folder:
|
||||
cpp = Path(folder)/'cw.cpp'; exe = Path(folder)/'cw.exe'
|
||||
cpp.write_text(code)
|
||||
|
||||
Reference in new issue
Block a user