Files
Tom 7fe3176a40 Radiolib recording hal tests (#11997)
* test: exercise RadioLib's drivers through a recording HAL, pinned to RadioLib 7.8.0

test_radiolib_drivers drives the RadioLib calls Meshtastic's radio interfaces
make against RecordingHal, which logs every SPI transaction and answers with a
success status, a few scripted replies (the packet type the LoRa setters check)
and, for SX127x, a register file. One set per chip family - SX126x, SX127x,
SX128x, LR11x0, LR2021 - each ending in a list of the reply-dependent tests
still to write. SX126x and SX128x get the SPI framing their begin() would set.

RadioLib is pinned to 7.8.0 to show the failure: the LR2021 DC-DC workaround
(jgromes/RadioLib#1864) passes sizeof(uint32_t) as a word count, and under
[env:coverage] ASan aborts the LR2021 set with a stack-buffer-overflow in
readRegMem32. The other four sets pass.

* test: pin RadioLib to the DC-DC word-count fix

NomDeTom/radiolib@3509dbc8e (branch lr2021-dcdc-regmem32-len, on RadioLib
master after 7.8.0) passes 1 as the word count at the three DC-DC workaround
call sites. The overrun is gone and the LR2021 set runs to completion.

test_lr2021_dcdc_freq_lf_write_sends_one_word still fails, on a second RadioLib
bug: LRxxxx::writeCommon() sends 4 + 4*len bytes whatever the address width, so
every LR2021 WriteRegMem32 (24-bit address) carries one uninitialised trailing
byte - 10 bytes where 9 are meant.

* test: keep RecordingHal reachable across a failed assertion

A failed TEST_ASSERT longjmps out of the test, skipping destructors, so each
test's local RecordingHal leaked its transaction log. LeakSanitizer then
reported it at exit, and under [env:coverage] a plain assertion failure came
out as an ERRORED suite (run 36412456860: 26 Tests 1 Failures, then a 384-byte
leak from RecordingHal::spiTransfer). One static HAL, reset at the start of
each test, stays reachable, so a failure reports as FAILED.

* test: run the RadioLib driver suite against develop's RadioLib pin

Revert the pin to develop's 510e00cfb (RadioLib 7.7.1). That RadioLib predates
the LR2021 DC-DC workaround, so its three tests would only fail on their own
premise there. They now register only when LR2021 has the public
setRegulatorDCDC() that jgromes/RadioLib#1864 added with the workaround: any
RadioLib carrying it runs them, and none is left ignored.

Against 7.8.0 the suite shows the DC-DC overrun (ASan, run 36412379592). Against
the DC-DC fix (NomDeTom/radiolib@3509dbc8e) it shows a second bug: every LR2021
WriteRegMem32 sends one byte too many, since LRxxxx::writeCommon() still sizes
the frame for a 4-byte address after jgromes/RadioLib@e3af85867 made it 3 on
the LR2021 (run 36412456860). Neither is reachable at this pin.

* test: pin the coding-rate byte the radio interfaces send

LR11x0Interface, LR20x0Interface and SX128xInterface all call
setCodingRate(cr, cr != 7), so 4/5 goes out with the long interleaver.
The modulation tests used the driver default (short), and only counted
frames. Pass the flag the firmware passes, and add a test per chip that
reads the coding-rate field back from the last modulation-params frame:
5 for 4/5 long, 3 for 4/7 short (RadioLib 7.7.1's encoding).

Also correct test_main.cpp: at the 7.7.1 pin the LR2021 DC-DC tests are
not registered, so the set does not fail; the 7.8.0 overrun is now
stated as conditional on a RadioLib that carries it.
2026-09-30 12:09:08 +00:00

47 lines
2.1 KiB
C++

// Unit tests for the RadioLib driver calls Meshtastic's radio interfaces make, one set per chip
// family: SX126x (sx126x_tests.h), SX127x (sx127x_tests.h), SX128x (sx128x_tests.h), LR11x0
// (lr11x0_tests.h) and LR2021 (lr2021_tests.h), against the RadioLib pinned in platformio.ini.
//
// No chip is needed. RecordingHal (RecordingHal.h) logs every SPI transaction and answers with a
// status byte every status-byte family reads as success, plus the few scripted replies the setters
// check before acting (the packet type); for SX127x it keeps a register file instead. That reaches
// every setter and mode command the interfaces use, and the tests pin what reaches the chip: the
// opcode, the frame length, and where the value is fixed, the payload.
//
// The regressions guarded are driver changes that send the wrong bytes, or read or write past a
// buffer, on paths no hardware-free test reached before. Under [env:coverage] (-fsanitize=address)
// an out-of-bounds access aborts the program at the call. The first such bug is jgromes/RadioLib#1864:
// the LR2021 DC-DC workaround passes sizeof(uint32_t) as a word count, overrunning the stack on
// every setRxPath() and LoRa modulation change. The pin here, 7.7.1, predates that workaround, so
// the LR2021 DC-DC tests register only on a RadioLib that has it (see lr2021_tests.h). On one that
// also carries the overrun (7.8.0) they abort, so the LR2021 set runs last and the rest report first.
//
// Anything that decodes a chip reply (begin(), readData(), getRSSI(), updateFirmware()) needs replies
// scripted per opcode; each family's header lists those under "Grows here".
#include "TestUtil.h"
#include <RadioLib.h>
#include <unity.h>
#include "lr11x0_tests.h"
#include "lr2021_tests.h"
#include "sx126x_tests.h"
#include "sx127x_tests.h"
#include "sx128x_tests.h"
void setUp(void) {}
void tearDown(void) {}
void setup()
{
initializeTestEnvironment();
UNITY_BEGIN();
runSx126xTests();
runSx127xTests();
runSx128xTests();
runLr11x0Tests();
runLr2021Tests(); // last: its DC-DC tests abort under ASan on a RadioLib with the #1864 overrun
exit(UNITY_END());
}
void loop() {}