I'm working on a project that uses an X440 radio from Ettus Research, which relies on UHD under the hood for its API. My application has three main components:
C++ files that handle all of the UHD/USRP calls and the high-speed interfaces between the radio and the stream endpoints.
A Python script that uses NiceGUI to send commands to the C++ application to control the behavior of the USRP.
A Python script that uses PyQt to display a basic spectrum analyzer view of a portion of the samples received from the radio. These samples are streamed over ZMQ at a low enough rate to avoid overflow.
All of these scripts are running on a headless RHEL9 machine, which I access via SSH.
I'm experiencing an issue between parts 1 and 3 when I try to use the C++ files with the spectrum analyzer GUI.
If I start the spectrum analyzer Python script before calling the uhd::usrp::multi_usrp::make() function in my C++ application, the spectrum analyzer works as expected. The X-forwarded window pops up, and I can interact with it normally. Additioanlly, the spectrum analyzer continues to work after I run uhd::usrp::multi_usrp::make().
However, if I run the spectrum analyzer Python script after calling uhd::usrp::multi_usrp::make(), the GUI goes through the setup steps but never displays. Furthermore, I can't stop the script with CTRL-C in the console. The only way to get the script to respond is to kill the C++ application. Once the C++ application is killed, the spectrum analyzer GUI pops up correctly.
Because of the high data rate from the X440, UHD is using DPDK under the hood. I am not sure if that's relevant, but I wanted to mention it.
What could be causing this? I've tried debugging on the Python side, but I suspect it's getting hung at the system level, so Python debugging hasn't been effective.
Minimal GUI Code that reproduces the issue:
from pyqtgraph.Qt import QtWidgets, QtCore
class myGui(QtWidgets.QWidget):
def __init__(self):
super().__init__()
# Layout
layout = QtWidgets.QVBoxLayout(self)
ctrl_layout = QtWidgets.QHBoxLayout()
layout.addLayout(ctrl_layout)
print("Done here") # This line prints but then the app never shows if
# started after the C++ applications
def main():
print("main")
app = QtWidgets.QApplication([])
gui = myGui()
gui.resize(1200, 900)
gui.show()
app.exec()
if __name__ == "__main__":
main()
Minimal C++ code that will cause the hang if the GUI code is started after the USRP is made:
#include
#include
#include
#include
#include
#include
#include
#include
int UHD_SAFE_MAIN(int argc, char* argv[]) {
// minimal config for demonstration
uhd::usrp::multi_usrp::sptr usrp_;
std::cout << "Before usrp, waiting 20 seconds" << std::endl; //GUI wont hang here
std::this_thread::sleep_for(std::chrono::seconds(20));
std::cout << "Making USRP" << std::endl;
usrp_ = uhd::usrp::multi_usrp::make("addr=192.168.10.2, second_addr=192.168.20.2,"
"mgmt_addr=192.168.200.2,use_dpdk=1, master_clock_rate=500e6,"
"converter_clock_rate=4e9");
std::cout << "Finished making USRP, waiting 20 seconds" << std::endl; //GUI now hangs
std::this_thread::sleep_for(std::chrono::seconds(20));
return 0;
}