Hello!
I’m the developer of RFQuack, an RF-hacking library framework and hardware toolkit. The project is based on PlatformIO and I found a linking issue that results in the wrong method being called.
RFQuack depends on (a fork of) RadioLib, which is now 100% aligned with the upstream. RFQuack wraps some classes of RadioLib, adding some more methods and reusing (i.e., using
) some existing ones.
Full post with links to code lines (because new users of this community cannot post more than 2 links):
Situation
The desired chain of calls is as follows:
RFQRF69::begin()
→ RadioLibWrapper:begin()
→ RF69::begin()
→ RF69::setFrequency(float)
Background
The last step is because of this part in RFQRFM69.h
:
class RFQRF69 : public RadioLibWrapper<RF69> {
public:
using RF69::setPreambleLength;
using RF69::setOutputPower;
using RF69::setPromiscuousMode;
using RF69::variablePacketLengthMode;
using RF69::setCrcFiltering;
using RF69::setRxBandwidth;
using RF69::fixedPacketLengthMode;
using RF69::setFrequency; // <--- this
using RF69::setFrequencyDeviation;
using RF69::getFrequencyDeviation;
using RF69::setBitRate;
RFQRF69
implements RadioLibWrapper
but it uses the generic’s implementation of setFrequency(float)
. The reason for this is that I want RadioLibWrapper
to define the interface (minimum methods to be implemented), but leave the developer to either use the generic’s implementation or to override.
Problem
However, the linker confuses RF69::setFrequency(float)
with virtual RadioLibWrapper::setFrequency(float)
. So, the runtime call chain of calls is as follows:
RFQRF69::begin()
→ RadioLibWrapper:begin()
→ RF69::begin()
→ RadioLibWrapper::setFrequency(float)
Possible Explanation
I guess this is due to linking order as per how PlatformIO “decides” to order libraries.
To verify this, I changed RadioLibWrapper.h
as follows:
// virtual int16_t setFrequency(float freq) {
// Log.error(F("setFrequency was not implemented."));
// return ERR_COMMAND_NOT_IMPLEMENTED;
// }
And the correct method RF69::setFrequency(float)
is linked and resolved at runtime. Because the virtual
simply doesn’t exist, so the linker couldn’t get confused.
The Build Configuration
The build configuration is as follows.
[platformio]
default_envs = featheresp32
[env]
build_unflags = -fno-rtti
framework = arduino
# This installs all requirements from
# RFQuack's `library.json` (RadioLib is not there)
lib_deps =
file://.
# Add extra libs
lib_extra_dirs =
lib/RadioLib
custom_nanopb_protos =
+<src/rfquack.proto>
custom_nanopb_options =
--error-on-unmatched
extra_scripts =
pre:scripts/pio/main_cpp_j2.py
monitor_speed = 115200
[env:featheresp32]
platform = platformio/espressif32@^5.2.0
board = featheresp32
Reproduction
I understand it’s quite hard to reproduce this bug without proper hardware. However, it can compile anywhere pretty easily through PlatformIO:
git clone --recursive https://github.com/rfquack/RFQuack
cd RFQuack
pip install -r requirements.pip
vim build.env
make clean build