Commit d4780c69 authored by Bo Zhao's avatar Bo Zhao Committed by Marwan Hammouda

First implementation for KPI GUI with Qt5

- CMakeLists modification: add QtWidgets library, add new source files, MOC (Meta-Object Compiler) on the given source file
- build_oai modification
- Activate new GUI with Qt on the UE side
- 2 x 3 widget with I/Q sample for PDSCH
- Drop-down list implementation
- some minor bugfixes
parent a1de5e3d
...@@ -2484,6 +2484,9 @@ set (SIMUSRC ...@@ -2484,6 +2484,9 @@ set (SIMUSRC
########################## ##########################
add_library(SIMU SHARED ${SIMUSRC} ) add_library(SIMU SHARED ${SIMUSRC} )
# Find the QtWidgets library
find_package(Qt5 COMPONENTS Widgets REQUIRED)
add_library(SIMU_ETH add_library(SIMU_ETH
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/netlink_init.c
${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c ${OPENAIR1_DIR}/SIMULATION/ETH_TRANSPORT/multicast_link.c
...@@ -2522,6 +2525,10 @@ set(XFORMSINTERFACE_SOURCE ...@@ -2522,6 +2525,10 @@ set(XFORMSINTERFACE_SOURCE
) )
set(XFORMS_LIBRARIES "forms") set(XFORMS_LIBRARIES "forms")
set(QTSCOPE_SOURCE_NR
${OPENAIR1_DIR}/PHY/TOOLS/nr_phy_qt_scope.cpp
)
add_library(enbscope MODULE ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${XFORMS_ENB_SOURCE}) add_library(enbscope MODULE ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${XFORMS_ENB_SOURCE})
add_library(uescope MODULE ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${XFORMS_UE_SOURCE}) add_library(uescope MODULE ${XFORMS_SOURCE} ${XFORMS_SOURCE_SOFTMODEM} ${XFORMS_UE_SOURCE})
target_link_libraries(enbscope ${XFORMS_LIBRARIES}) target_link_libraries(enbscope ${XFORMS_LIBRARIES})
...@@ -2530,6 +2537,12 @@ target_link_libraries(uescope ${XFORMS_LIBRARIES}) ...@@ -2530,6 +2537,12 @@ target_link_libraries(uescope ${XFORMS_LIBRARIES})
add_library(nrscope MODULE ${XFORMS_SOURCE_NR}) add_library(nrscope MODULE ${XFORMS_SOURCE_NR})
target_link_libraries(nrscope ${XFORMS_LIBRARIES}) target_link_libraries(nrscope ${XFORMS_LIBRARIES})
# Creates rules for calling the Meta-Object Compiler (moc) on the given source files
qt5_wrap_cpp(QTSCOPE_SOURCE_NR ${OPENAIR1_DIR}/PHY/TOOLS/nr_phy_qt_scope.h)
add_library(nrqtscope MODULE ${QTSCOPE_SOURCE_NR})
# Use the Widgets module from Qt5.
target_link_libraries(nrqtscope Qt5::Widgets)
add_library(rfsimulator MODULE add_library(rfsimulator MODULE
${OPENAIR_DIR}/sdr/rfsimulator/simulator.c ${OPENAIR_DIR}/sdr/rfsimulator/simulator.c
......
...@@ -58,7 +58,7 @@ CMAKE_CMD="$CMAKE" ...@@ -58,7 +58,7 @@ CMAKE_CMD="$CMAKE"
NOAVX512="False" NOAVX512="False"
BUILD_ECLIPSE=0 BUILD_ECLIPSE=0
NR="False" NR="False"
OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope" OPTIONAL_LIBRARIES="telnetsrv enbscope uescope nrscope nrqtscope"
RU=0 RU=0
CMAKE_C_FLAGS=() CMAKE_C_FLAGS=()
CMAKE_CXX_FLAGS=() CMAKE_CXX_FLAGS=()
......
...@@ -516,7 +516,8 @@ int main( int argc, char **argv ) { ...@@ -516,7 +516,8 @@ int main( int argc, char **argv ) {
mlockall(MCL_CURRENT | MCL_FUTURE); mlockall(MCL_CURRENT | MCL_FUTURE);
if(IS_SOFTMODEM_DOSCOPE) { if(IS_SOFTMODEM_DOSCOPE) {
load_softscope("nr",PHY_vars_UE_g[0][0]); //load_softscope("nr",PHY_vars_UE_g[0][0]);
load_softscope("nrqt",PHY_vars_UE_g[0][0]);
} }
init_NR_UE_threads(1); init_NR_UE_threads(1);
......
#include <QApplication>
#include <QtWidgets>
#include <QPainter>
#include <QtGui>
#include "nr_phy_qt_scope.h"
typedef struct complex16 scopeSample_t;
KPIListSelect::KPIListSelect(QWidget *parent) : QComboBox(parent)
{
this->addItem("KPI 1");
this->addItem("KPI 2");
this->addItem("KPI 3");
this->addItem("KPI 4");
this->addItem("KPI 5");
this->addItem("KPI 6");
}
KPIListSelect::~KPIListSelect()
{
}
PainterWidget::PainterWidget(PHY_VARS_NR_UE *ue)
{
timer = new QTimer(this);
this->pix = new QPixmap(300,300);
this->pix->fill(QColor(240,240,240));
this->ue = ue;
connect(timer, &QTimer::timeout, this, &PainterWidget::paintPixmap);
timer->start(1000); // paintPixmap every 1000ms
// paint the frame
static const QPoint PlotFrame[4] = {
QPoint( 100, 100),
QPoint(-100, 100),
QPoint(-100, -100),
QPoint( 100, -100)
};
QColor FrameColor(0, 255, 120);
QPainter PixPainter(this->pix);
PixPainter.translate(this->pix->width()/2, this->pix->height()/2); // move the origin to the center of the Pixmap
PixPainter.setPen(FrameColor);
PixPainter.drawConvexPolygon(PlotFrame, 4);
}
void PainterWidget::paintPixmap()
{
// erase the previous paint
this->pix->fill(QColor(240,240,240));
static const QPoint PlotFrame[4] = {
QPoint( 100, 100),
QPoint(-100, 100),
QPoint(-100, -100),
QPoint( 100, -100)
};
QColor FrameColor(0, 255, 120);
QPainter PixPainter(this->pix);
PixPainter.translate(this->pix->width()/2, this->pix->height()/2); // move the origin to the center of the Pixmap
PixPainter.setPen(FrameColor);
PixPainter.drawConvexPolygon(PlotFrame, 4);
//paint the axis and I/Q samples
if (!this->ue->pdsch_vars[0][0]->rxdataF_comp0[0])
return;
NR_DL_FRAME_PARMS *frame_parms = &this->ue->frame_parms;
int sz=7*2*frame_parms->N_RB_DL*12; // size of the malloced buffer
float FIinit[sz] = { 0 }, FQinit[sz] = { 0 };
float *I = FIinit, *Q = FQinit;
for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
scopeSample_t *pdsch_comp = (scopeSample_t *) this->ue->pdsch_vars[thr][0]->rxdataF_comp0[0];
for (int s=0; s<sz; s++) {
I[s] += pdsch_comp[s].r;
Q[s] += pdsch_comp[s].i;
}
}
float maxX=0, maxY=0, minX=0, minY=0;
for (int k=0; k<sz; k++) {
maxX=std::max(maxX,I[k]);
minX=std::min(minX,I[k]);
maxY=std::max(maxY,Q[k]);
minY=std::min(minY,Q[k]);
}
QColor IQColor(105,105,105);
PixPainter.setPen(IQColor);
float maxXAbs = std::max(abs(maxX),abs(minX));
float maxYAbs = std::max(abs(maxY),abs(minY));
int Ipaint, Qpaint;
for (int k=0; k<sz; k++) { //scale the I/Q samples!
Ipaint = I[k]/maxXAbs*50;
Qpaint = Q[k]/maxYAbs*50;
PixPainter.drawEllipse( QPoint(Ipaint,Qpaint), 2, 2 );
//PixPainter.drawPoint(Ipaint, Qpaint);
}
update(); //call paintEvent()
}
void PainterWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawPixmap( (this->width()-this->pix->width())/2,
(this->height()-this->pix->height())/2, *this->pix); // paint pixmap on widget
}
AccumWidget::AccumWidget(PHY_VARS_NR_UE *ue)
{
timer = new QTimer(this);
this->pix = new QPixmap(300,300);
this->pix->fill(QColor(240,240,240));
this->ue = ue;
connect(timer, &QTimer::timeout, this, &AccumWidget::paintPixmap);
timer->start(1000); // paintPixmap every 1000ms
// paint the frame
static const QPoint PlotFrame[4] = {
QPoint( 100, 100),
QPoint(-100, 100),
QPoint(-100, -100),
QPoint( 100, -100)
};
QColor FrameColor(0, 255, 120);
QPainter PixPainter(this->pix);
PixPainter.translate(this->pix->width()/2, this->pix->height()/2); // move the origin to the center of the Pixmap
PixPainter.setPen(FrameColor);
PixPainter.drawConvexPolygon(PlotFrame, 4);
}
void AccumWidget::paintPixmap()
{
// paint on pixmap
QPainter PixPainter(this->pix);
PixPainter.translate(this->pix->width()/2, this->pix->height()/2); // move the origin to the center of the Pixmap
//paint the axis and I/Q samples
if (!this->ue->pdsch_vars[0][0]->rxdataF_comp0[0])
return;
NR_DL_FRAME_PARMS *frame_parms = &this->ue->frame_parms;
int sz=7*2*frame_parms->N_RB_DL*12; // size of the malloced buffer
float FIinit[sz] = { 0 }, FQinit[sz] = { 0 };
float *I = FIinit, *Q = FQinit;
for (int thr=0 ; thr < RX_NB_TH_MAX ; thr ++ ) {
scopeSample_t *pdsch_comp = (scopeSample_t *) this->ue->pdsch_vars[thr][0]->rxdataF_comp0[0];
for (int s=0; s<sz; s++) {
I[s] += pdsch_comp[s].r;
Q[s] += pdsch_comp[s].i;
}
}
float maxX=0, maxY=0, minX=0, minY=0;
for (int k=0; k<sz; k++) {
maxX=std::max(maxX,I[k]);
minX=std::min(minX,I[k]);
maxY=std::max(maxY,Q[k]);
minY=std::min(minY,Q[k]);
}
QColor IQColor(105,105,105);
PixPainter.setPen(IQColor);
float maxXAbs = std::max(abs(maxX),abs(minX));
float maxYAbs = std::max(abs(maxY),abs(minY));
int Ipaint, Qpaint;
for (int k=0; k<sz; k++) { //scale the I/Q samples!
Ipaint = I[k]/maxXAbs*50;
Qpaint = Q[k]/maxYAbs*50;
PixPainter.drawEllipse( QPoint(Ipaint,Qpaint), 2, 2 );
//PixPainter.drawPoint(Ipaint, Qpaint);
}
update(); //call paintEvent()
}
void AccumWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.drawPixmap( (this->width()-this->pix->width())/2,
(this->height()-this->pix->height())/2, *this->pix); // paint pixmap on widget
}
void *nrUEQtscopeThread(void *arg)
{
PHY_VARS_NR_UE *ue=(PHY_VARS_NR_UE *)arg;
int argc = 1;
char *argv[] = { (char*)"nrqt_scope"};
QApplication a(argc, argv);
// Create a main window (widget)
QWidget window;
window.resize(600, 800);
// Window title
window.setWindowTitle("UE scope");
// create the popup lists
KPIListSelect * combo1 = new KPIListSelect();
combo1->setCurrentIndex(0);
KPIListSelect * combo2 = new KPIListSelect();
combo2->setCurrentIndex(1);
KPIListSelect * combo3 = new KPIListSelect();
combo3->setCurrentIndex(2);
KPIListSelect * combo4 = new KPIListSelect();
combo4->setCurrentIndex(3);
KPIListSelect * combo5 = new KPIListSelect();
combo5->setCurrentIndex(4);
KPIListSelect * combo6 = new KPIListSelect();
combo6->setCurrentIndex(5);
// clock example
PainterWidget pwidget(ue);
//PainterExample clock;
AccumWidget mypixmap(ue);
// Main layout
QHBoxLayout *mainLayout = new QHBoxLayout;
// left and right layouts
QVBoxLayout *LeftLayout = new QVBoxLayout;
QVBoxLayout *RightLayout = new QVBoxLayout;
LeftLayout->addWidget(combo1);
LeftLayout->addWidget(&pwidget,20);
//LeftLayout->addStretch(); // space for later plots
LeftLayout->addWidget(combo2);
//LeftLayout->addWidget(&clock,10);
LeftLayout->addStretch(); // space for later plots
LeftLayout->addWidget(combo3);
LeftLayout->addWidget(&mypixmap,20);
//LeftLayout->addStretch(); // space for later plots
RightLayout->addWidget(combo4);
RightLayout->addStretch(); // space for later plots
RightLayout->addWidget(combo5);
RightLayout->addStretch(); // space for later plots
RightLayout->addWidget(combo6);
RightLayout->addStretch(); // space for later plots
// add the left and right layouts to the main layout
mainLayout->addLayout(LeftLayout);
mainLayout->addLayout(RightLayout);
// set the layout of the main window
window.setLayout(mainLayout);
// display the main window
window.show();
a.exec();
return NULL;
}
void nrUEinitQtScope(PHY_VARS_NR_UE *ue) {
pthread_t qtscope_thread;
threadCreate(&qtscope_thread, nrUEQtscopeThread, ue, (char*)"qtscope", -1, sched_get_priority_min(SCHED_RR));
}
extern "C" void nrqtscope_autoinit(void *dataptr) {
//AssertFatal( (IS_SOFTMODEM_GNB_BIT||IS_SOFTMODEM_5GUE_BIT),"Scope cannot find NRUE or GNB context");
/*if (IS_SOFTMODEM_GNB_BIT)
gNBinitScope(dataptr);
else
nrUEinitScope(dataptr);*/
nrUEinitQtScope((PHY_VARS_NR_UE *)dataptr);
}
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/* Header file generated by Bo Zhao (Fraunhofer IIS) on Wed. Dec. 08, 2021*/
#ifndef QT_SCOPE_MAINWINDOW_H
#define QT_SCOPE_MAINWINDOW_H
#include <QWidget>
#include <QComboBox>
#include <QMessageBox>
extern "C" {
#include <common/utils/system.h>
#include "PHY/defs_gNB.h"
#include "PHY/defs_nr_UE.h"
}
// drop-down list
class KPIListSelect : public QComboBox
{
Q_OBJECT
public:
explicit KPIListSelect(QWidget *parent = 0);
~KPIListSelect();
private:
};
// Paint first on a pixmap, then on the widget. Previous paint is erased
class PainterWidget : public QWidget
{
Q_OBJECT
public:
PainterWidget(PHY_VARS_NR_UE *ue);
QPixmap *pix;
QTimer *timer;
protected:
void paintEvent(QPaintEvent *event);
public slots:
void paintPixmap();
private:
PHY_VARS_NR_UE *ue;
};
// Accumulated painting including all previous data, all painted first on a pixmap, then on the widget
class AccumWidget : public QWidget
{
Q_OBJECT
public:
AccumWidget(PHY_VARS_NR_UE *ue);
QPixmap *pix;
QTimer *timer;
protected:
void paintEvent(QPaintEvent *event);
public slots:
void paintPixmap();
private:
PHY_VARS_NR_UE *ue;
};
#endif // QT_SCOPE_MAINWINDOW_H
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include "CODING/nrPolar_tools/nr_polar_pbch_defs.h" #include "CODING/nrPolar_tools/nr_polar_pbch_defs.h"
#define _GNU_SOURCE #define _GNU_SOURCE 1
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <malloc.h> #include <malloc.h>
......
...@@ -139,7 +139,7 @@ typedef struct TDD_UL_DL_configCommon_s { ...@@ -139,7 +139,7 @@ typedef struct TDD_UL_DL_configCommon_s {
struct TDD_UL_DL_configCommon_s *p_next; struct TDD_UL_DL_configCommon_s *p_next;
} TDD_UL_DL_configCommon_t; } TDD_UL_DL_configCommon_t;
typedef struct { typedef struct TDD_UL_DL_SlotConfig_s {
/// \ Identifies a slot within a dl-UL-TransmissionPeriodicity (given in tdd-UL-DL-configurationCommon) /// \ Identifies a slot within a dl-UL-TransmissionPeriodicity (given in tdd-UL-DL-configurationCommon)
uint16_t slotIndex; uint16_t slotIndex;
/// \ The direction (downlink or uplink) for the symbols in this slot. "allDownlink" indicates that all symbols in this slot are used /// \ The direction (downlink or uplink) for the symbols in this slot. "allDownlink" indicates that all symbols in this slot are used
...@@ -154,7 +154,7 @@ typedef struct { ...@@ -154,7 +154,7 @@ typedef struct {
/// Corresponds to L1 parameter 'number-of-UL-symbols-dedicated' (see 38.211, section FFS_Section) /// Corresponds to L1 parameter 'number-of-UL-symbols-dedicated' (see 38.211, section FFS_Section)
uint16_t nrofUplinkSymbols; uint16_t nrofUplinkSymbols;
/// \ for setting a sequence /// \ for setting a sequence
struct TDD_UL_DL_SlotConfig_t *p_next_TDD_UL_DL_SlotConfig; struct TDD_UL_DL_SlotConfig_s *p_next_TDD_UL_DL_SlotConfig;
} TDD_UL_DL_SlotConfig_t; } TDD_UL_DL_SlotConfig_t;
/*********************************************************************** /***********************************************************************
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment