Files
MeshCore/tools/hil/profile_switch_experiments.h
T
mikecarper bd30388436 Speed up SX1262 profile switching and verify radio lab behavior
Keep TCXO warm during owned dual-profile retunes, batch modulation setup, and enable guarded fast RX with buffered 8 MHz SPI on XIAO S3 WIO and Indicator LoRa. Preserve lifecycle invalidation, packet guards, rollback, and existing scheduling budgets.

Add reliable sequence-scoped USB lab transport, native regression coverage, bounded channel and preamble diagnostics, and byte-exact measurement records including failed experiments and qualification limits.
2026-09-14 01:22:09 -07:00

87 lines
3.3 KiB
C++

#pragma once
// HIL-only experiments. Never included by a production target. These rely on
// an explicitly identified RX-to-RX hop, not a general cached radio state.
#include <helpers/radiolib/CustomSX1262.h>
class ExperimentalSX1262 : public CustomSX1262 {
public:
enum : uint32_t {
NoRxStandby = 1, NoIrqRewrite = 2, NoBufferRewrite = 4,
NoPacketRewrite = 8, NoModemQuery = 16, DeferPreamble = 32,
NoWakeNop = 64, ManualRxControl = 128,
};
uint32_t experiment = 0;
bool productionPath = true;
bool inHop = false, resumeRx = false, haveStandby = false;
bool packetWritten = false, preamblePending = false, rxPrimed = false;
using CustomSX1262::CustomSX1262;
void beginHop(bool rx) {
inHop = true; resumeRx = rx; haveStandby = packetWritten = preamblePending = false;
}
void endHop() { inHop = resumeRx = haveStandby = false; }
int16_t standby() override {
if (productionPath) return CustomSX1262::standby();
const bool knownAwake = inHop && resumeRx && (experiment & NoWakeNop);
const int16_t rc = SX1262::standby(standbyXOSC ? RADIOLIB_SX126X_STANDBY_XOSC
: RADIOLIB_SX126X_STANDBY_RC, !knownAwake);
if (inHop && rc == RADIOLIB_ERR_NONE) haveStandby = true;
return rc;
}
int16_t setPreambleLength(size_t symbols) override {
if (productionPath) return CustomSX1262::setPreambleLength(symbols);
if (inHop && resumeRx && haveStandby && (experiment & DeferPreamble)) {
preambleLengthLoRa = symbols;
preamblePending = true;
return RADIOLIB_ERR_NONE;
}
const int16_t rc = SX1262::setPreambleLength(symbols);
if (inHop && rc == RADIOLIB_ERR_NONE) packetWritten = true;
return rc;
}
int16_t startReceive() override {
if (productionPath) return CustomSX1262::startReceive();
if (!experiment || !inHop || !resumeRx || !haveStandby || !rxPrimed) {
const int16_t rc = CustomSX1262::startReceive();
rxPrimed = rc == RADIOLIB_ERR_NONE;
return rc;
}
// Same sequence and error checks as pinned RadioLib's stageMode(RX),
// selectively omitting only the particular operation under test.
int16_t rc;
if (!(experiment & NoRxStandby)) {
rc = standby();
RADIOLIB_ASSERT(rc);
}
if (!(experiment & NoIrqRewrite)) {
rc = setDioIrqParams(getIrqMapped(RADIOLIB_IRQ_RX_DEFAULT_FLAGS
| (1UL << RADIOLIB_IRQ_PREAMBLE_DETECTED)),
getIrqMapped(RADIOLIB_IRQ_RX_DEFAULT_MASK));
RADIOLIB_ASSERT(rc);
}
if (!(experiment & NoBufferRewrite)) {
rc = setBufferBaseAddress();
RADIOLIB_ASSERT(rc);
}
rc = clearIrqStatus(); // never omit clearing consumed/stale IRQ flags
RADIOLIB_ASSERT(rc);
if (!(experiment & NoModemQuery)
&& getPacketType() != RADIOLIB_SX126X_PACKET_TYPE_LORA) {
return RADIOLIB_ERR_WRONG_MODEM;
}
if (!(experiment & NoPacketRewrite) || !packetWritten || preamblePending) {
rc = setPacketParams(preambleLengthLoRa, crcTypeLoRa, implicitLen, headerType, invertIQEnabled);
RADIOLIB_ASSERT(rc);
}
rxTimeout = RADIOLIB_SX126X_RX_TIMEOUT_INF;
getMod()->setRfSwitchState(Module::MODE_RX);
rc = setRx(rxTimeout); // retains all RadioLib BUSY polling/error handling
stagedMode = RADIOLIB_RADIO_MODE_NONE;
if (rc != RADIOLIB_ERR_NONE) rxPrimed = false;
return rc;
}
};