Fix bug in QT scope
The UE copies scope data not in a single buffer to avoid overwiring in case of multiple slots processing in parallel. But the scope upates data from single buffer thats assigned during selection. A getPlotValue() method is created to update the data pointer on every timerEvent.
This commit is contained in:
@@ -317,6 +317,34 @@ void CIRPlot::timerEvent(QTimerEvent *event)
|
||||
this->series->replace(points);
|
||||
}
|
||||
|
||||
void CIRPlotUE::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (!this->isVisible())
|
||||
return;
|
||||
|
||||
scopeGraphData_t *data = this->valueProvider->getPlotValue();
|
||||
if (data) {
|
||||
this->data = (complex16 *)(data + 1);
|
||||
this->len = data->lineSz;
|
||||
QVector<QPointF> points(this->len);
|
||||
float maxY = this->axisY->max();
|
||||
|
||||
for (int i = 0; i < this->len / 2; i++) {
|
||||
float value = SquaredNorm(this->data[i + this->len / 2]);
|
||||
points[i] = QPointF(i - this->len / 2, value);
|
||||
maxY = std::max(maxY, value);
|
||||
}
|
||||
for (int i = 0; i < this->len / 2; i++) {
|
||||
float value = SquaredNorm(this->data[i]);
|
||||
points[i + this->len / 2] = QPointF(i, value);
|
||||
maxY = std::max(maxY, value);
|
||||
}
|
||||
|
||||
this->axisY->setMax(maxY);
|
||||
this->series->replace(points);
|
||||
}
|
||||
}
|
||||
|
||||
LLRPlot::LLRPlot(int16_t *data, int len) : data(data), len(len)
|
||||
{
|
||||
this->legend()->hide();
|
||||
@@ -361,6 +389,28 @@ void LLRPlot::timerEvent(QTimerEvent *event)
|
||||
this->series->replace(points);
|
||||
}
|
||||
|
||||
void LLRPlotUE::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (!this->isVisible())
|
||||
return;
|
||||
|
||||
scopeGraphData_t *data = this->valueProvider->getPlotValue();
|
||||
if (data) {
|
||||
this->data = (int16_t *)(data + 1);
|
||||
this->len = data->lineSz;
|
||||
QVector<QPointF> points(this->len);
|
||||
int maxY = this->axisY->max();
|
||||
|
||||
for (int i = 0; i < this->len; i++) {
|
||||
points[i] = QPointF(i, this->data[i]);
|
||||
maxY = std::max(maxY, abs(this->data[i]));
|
||||
}
|
||||
|
||||
this->axisY->setRange(-maxY, maxY);
|
||||
this->series->replace(points);
|
||||
}
|
||||
}
|
||||
|
||||
IQPlot::IQPlot(complex16 *data, int len) : data(data), len(len)
|
||||
{
|
||||
this->legend()->hide();
|
||||
@@ -407,6 +457,32 @@ void IQPlot::timerEvent(QTimerEvent *event)
|
||||
this->series->replace(points);
|
||||
}
|
||||
|
||||
void IQPlotUE::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (!this->isVisible())
|
||||
return;
|
||||
|
||||
scopeGraphData_t *data = this->valueProvider->getPlotValue();
|
||||
if (data) {
|
||||
this->data = (complex16 *)(data + 1);
|
||||
this->len = data->lineSz;
|
||||
QVector<QPointF> points(this->len);
|
||||
int maxX = this->axisX->max();
|
||||
int maxY = this->axisY->max();
|
||||
|
||||
for (int i = 0; i < this->len; i++) {
|
||||
points[i] = QPointF(this->data[i].r, this->data[i].i);
|
||||
|
||||
maxX = std::max(maxX, abs(this->data[i].r));
|
||||
maxY = std::max(maxY, abs(this->data[i].i));
|
||||
}
|
||||
|
||||
this->axisX->setRange(-maxX, maxX);
|
||||
this->axisY->setRange(-maxY, maxY);
|
||||
this->series->replace(points);
|
||||
}
|
||||
}
|
||||
|
||||
KPIPlot::KPIPlot(ValueProvider *valueProvider, float *limits) : valueProvider(valueProvider), limits(limits)
|
||||
{
|
||||
this->series = new QLineSeries();
|
||||
@@ -815,11 +891,42 @@ float PainterWidgetUE::getValue()
|
||||
case PlotTypeUE::timingAdvance:
|
||||
return (float)this->ue->timing_advance;
|
||||
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
scopeGraphData_t *PainterWidgetUE::getPlotValue()
|
||||
{
|
||||
scopeData_t *scope = (scopeData_t *)this->ue->scopeData;
|
||||
scopeGraphData_t **data = (scopeGraphData_t **)scope->liveData;
|
||||
switch (this->plotType) {
|
||||
case PlotTypeUE::CIR:
|
||||
return data[pbchDlChEstimateTime];
|
||||
|
||||
case PlotTypeUE::pbchLLR:
|
||||
return data[pbchLlr];
|
||||
case PlotTypeUE::pbchIQ:
|
||||
return data[pbchRxdataF_comp];
|
||||
|
||||
case PlotTypeUE::pdcchLLR:
|
||||
return data[pdcchLlr];
|
||||
|
||||
case PlotTypeUE::pdcchIQ:
|
||||
return data[pdcchRxdataF_comp];
|
||||
|
||||
case PlotTypeUE::pdschLLR:
|
||||
return data[pdschLlr];
|
||||
|
||||
case PlotTypeUE::pdschIQ:
|
||||
return data[pdschRxdataF_comp];
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* @UE Class: this function is called when a resize event is detected, then the widget will be adjusted accordignly. */
|
||||
void PainterWidgetUE::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
@@ -890,7 +997,7 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new LLRPlot((int16_t *)(data[pbchLlr] + 1), data[pbchLlr]->lineSz);
|
||||
newChart = new LLRPlotUE((int16_t *)(data[pbchLlr] + 1), data[pbchLlr]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::pbchIQ: {
|
||||
@@ -900,7 +1007,7 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new IQPlot((complex16 *)(data[pbchRxdataF_comp] + 1), data[pbchRxdataF_comp]->lineSz);
|
||||
newChart = new IQPlotUE((complex16 *)(data[pbchRxdataF_comp] + 1), data[pbchRxdataF_comp]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::pdcchLLR: {
|
||||
@@ -910,7 +1017,7 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new LLRPlot((int16_t *)(data[pdcchLlr] + 1), data[pdcchLlr]->lineSz);
|
||||
newChart = new LLRPlotUE((int16_t *)(data[pdcchLlr] + 1), data[pdcchLlr]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::pdcchIQ: {
|
||||
@@ -920,7 +1027,7 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new IQPlot((complex16 *)(data[pdcchRxdataF_comp] + 1), data[pdcchRxdataF_comp]->lineSz);
|
||||
newChart = new IQPlotUE((complex16 *)(data[pdcchRxdataF_comp] + 1), data[pdcchRxdataF_comp]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::pdschLLR: {
|
||||
@@ -930,7 +1037,7 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new LLRPlot((int16_t *)(data[pdschLlr] + 1), data[pdschLlr]->lineSz);
|
||||
newChart = new LLRPlotUE((int16_t *)(data[pdschLlr] + 1), data[pdschLlr]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
case PlotTypeUE::pdschIQ: {
|
||||
@@ -940,7 +1047,7 @@ void PainterWidgetUE::makeConnections(int type)
|
||||
this->comboBox->setCurrentIndex(static_cast<int>(PlotTypeUE::empty));
|
||||
break;
|
||||
}
|
||||
newChart = new IQPlot((complex16 *)(data[pdschRxdataF_comp] + 1), data[pdschRxdataF_comp]->lineSz);
|
||||
newChart = new IQPlotUE((complex16 *)(data[pdschRxdataF_comp] + 1), data[pdschRxdataF_comp]->lineSz, this);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,6 +91,14 @@ class ValueProvider {
|
||||
virtual float getValue() = 0;
|
||||
};
|
||||
|
||||
class ValueProviderUE : public ValueProvider {
|
||||
public:
|
||||
/// This pure virtual function is meant to provide the graph values to be plotted
|
||||
virtual scopeGraphData_t *getPlotValue() {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/// An editable GUI field for a dialog box to set certain KPI configurations
|
||||
class ConfigBoxFloat : public QLineEdit {
|
||||
Q_OBJECT
|
||||
@@ -206,7 +214,6 @@ class CIRPlot : public QChart {
|
||||
/// \param event Pointer to the timer event
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
/// Pointer to the CIR data
|
||||
complex16 *data;
|
||||
|
||||
@@ -223,6 +230,21 @@ class CIRPlot : public QChart {
|
||||
QValueAxis *axisY;
|
||||
};
|
||||
|
||||
class CIRPlotUE : public CIRPlot {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CIRPlotUE(complex16 *data, int len, ValueProviderUE *valueProvider) : CIRPlot(data, len), valueProvider(valueProvider) {}
|
||||
|
||||
protected:
|
||||
/// This function is triggered when the own timer expires. It updates the plotted CIR
|
||||
/// \param event Pointer to the timer event
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
ValueProviderUE *valueProvider;
|
||||
};
|
||||
|
||||
/// Chart class for plotting LLRs
|
||||
class LLRPlot : public QChart {
|
||||
Q_OBJECT
|
||||
@@ -238,7 +260,6 @@ class LLRPlot : public QChart {
|
||||
/// \param event Pointer to the timer event
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
/// Pointer to the LLR data
|
||||
int16_t *data;
|
||||
|
||||
@@ -255,6 +276,21 @@ class LLRPlot : public QChart {
|
||||
QValueAxis *axisY;
|
||||
};
|
||||
|
||||
class LLRPlotUE : public LLRPlot {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
LLRPlotUE(int16_t *data, int len, ValueProviderUE *valueProvider) : LLRPlot(data, len), valueProvider(valueProvider) {}
|
||||
|
||||
protected:
|
||||
/// This function is triggered when the own timer expires. It updates the plotted I/Q constellation diagram
|
||||
/// \param event Pointer to the timer event
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
ValueProviderUE *valueProvider;
|
||||
};
|
||||
|
||||
/// Chart class for plotting the I/Q constellation diagram
|
||||
class IQPlot : public QChart {
|
||||
Q_OBJECT
|
||||
@@ -270,7 +306,6 @@ class IQPlot : public QChart {
|
||||
/// \param event Pointer to the timer event
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
/// Pointer to the I/Q data
|
||||
complex16 *data;
|
||||
|
||||
@@ -287,6 +322,22 @@ class IQPlot : public QChart {
|
||||
QValueAxis *axisY;
|
||||
};
|
||||
|
||||
class IQPlotUE : public IQPlot {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
IQPlotUE(complex16 *data, int len, ValueProviderUE *valueProvider) : IQPlot(data, len), valueProvider(valueProvider) {}
|
||||
|
||||
protected:
|
||||
/// This function is triggered when the own timer expires. It updates the plotted I/Q constellation diagram
|
||||
/// \param event Pointer to the timer event
|
||||
virtual void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
/// Pointer to an instance of a class that implements the ValueProvider interface
|
||||
ValueProviderUE *valueProvider;
|
||||
};
|
||||
|
||||
/// Generic class for plotting KPI values with min., max. and average bars
|
||||
class KPIPlot : public QChart {
|
||||
Q_OBJECT
|
||||
@@ -422,7 +473,7 @@ class PainterWidgetGnb : public QWidget, public ValueProvider {
|
||||
};
|
||||
|
||||
/// Widget showing one selectable UE KPI
|
||||
class PainterWidgetUE : public QWidget, public ValueProvider {
|
||||
class PainterWidgetUE : public QWidget, public ValueProviderUE {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
@@ -435,6 +486,8 @@ class PainterWidgetUE : public QWidget, public ValueProvider {
|
||||
/// This function provides the current KPI value to be plotted
|
||||
virtual float getValue() override;
|
||||
|
||||
virtual scopeGraphData_t *getPlotValue() override;
|
||||
|
||||
protected:
|
||||
/// This function is called to change the widget size
|
||||
/// \param event Pointer to the resize event
|
||||
|
||||
Reference in New Issue
Block a user