SXXXXXXX_PyBusMonitor1553/cpp/GrifoScope/GrifoXLruMonitor/xlruchartclass.cpp
2025-12-17 07:59:30 +01:00

595 lines
14 KiB
C++

#include "xlruchartclass.h"
#include <QHBoxLayout>
#include <QFont>
#include <QMetaEnum>
#include <QApplication>
//#include <QMetaEnum>
using namespace QtCharts;
XlruChartClass::XlruChartClass(QWidget *parent) :
QWidget(parent),
report(0)
#ifdef TELEMETRY
,telemetry(0)
#endif
{
init();
SensorsTable = NULL;
}
XlruChartClass::~XlruChartClass()
{
delete mainView;
//delete report;
}
void XlruChartClass::setTitle(QString aTitle)
{
title = aTitle;
}
QString XlruChartClass::getTitle()
{
return title;
}
void XlruChartClass::init()
{
ch = new QChart();
mainView = new QChartView();
ch=mainView->chart();
m_tooltip = 0;
mainView->setRubberBand( QChartView::HorizontalRubberBand );
ch->setMargins(QMargins(0, 0, 0, 0));
ch->setAnimationOptions(QChart::NoAnimation);
ch->setMinimumSize(CHART_DIMX_DEF, CHART_DIMY_DEF);
ch->setAcceptHoverEvents(true);
ch->setTitle(title);
QHBoxLayout *layout = new QHBoxLayout();
#ifdef TRACKING_VALUE
valueToScreen = new QLabel(this);
valueToScreen->setText("prova");
layout->addWidget(valueToScreen);
#endif
layout->addWidget(mainView);
setLayout(layout);
QFont font;
// Customize chart title
font.setPixelSize(FONT_DIM_DEF);
timeNow=QDateTime::currentDateTime();
timeNowMs=timeNow.toMSecsSinceEpoch();
timeStart=timeNow;
timeStartMs=timeNowMs;
commonX= new QDateTimeAxis;
commonX->setFormat("h:mm:ss");
commonX->setTickCount(0);
commonX->setGridLineVisible(false);
commonX->setMin(timeNow.addSecs(-60));
if (UPDATE_OPTIMIZED)
commonX->setMax(timeNow.addSecs(TIME_UPDATE_XMAX));
else
commonX->setMax(timeNow);
temperatureY=new QValueAxis;
temperatureY->setGridLineVisible(false);
temperatureY->setVisible(true);
temperatureY->setTitleText("Temp(C)");
temperatureY->setTitleFont(font);
temperatureY->setTitleVisible(true);
temperatureY->setRange(TEMP_DEF_MIN, TEMP_DEF_MAX);
currentY=new QValueAxis;
currentY->setGridLineVisible(false);
currentY->setVisible(true);
currentY->setTitleText("Curr(A)");
currentY->setTitleFont(font);
currentY->setTitleVisible(true);
currentY->setRange(CURR_DEF_MIN, CURR_DEF_MAX);
voltageY=new QValueAxis;
voltageY->setGridLineVisible(false);
voltageY->setVisible(true);
voltageY->setTitleText("Volt(V)");
voltageY->setTitleFont(font);
voltageY->setTitleVisible(true);
voltageY->setRange(VOLT_DEF_MIN, VOLT_DEF_MAX);
ch->addAxis(commonX, AXIS_ALIGNMENT_DATE);
mainView->setOptimizationFlag(QGraphicsView::DontSavePainterState, true);
mainView->setOptimizationFlag(QGraphicsView::DontAdjustForAntialiasing, true);
mainView->setRenderHint(QPainter::Antialiasing, false);
mainView->setRenderHint(QPainter::TextAntialiasing, false);
mainView->setRenderHint(QPainter::SmoothPixmapTransform, false);
mainView->setRubberBand( QChartView::HorizontalRubberBand );
mainView->chart()->setBackgroundRoundness(0);
mainView->chart()->setMargins(QMargins(0, 0, 0, 0));
mainView->chart()->legend()->setVisible(true);
mainView->chart()->legend()->setAlignment(Qt::AlignTop);
autopurge_enabled = Qt::Unchecked;
setPenDim(PEN_DIM_DEF);
report_enabled = REPORT_ENABLED_DEF;
}
int XlruChartClass::findSensor(QString _label)
{
int idx = 0;
foreach (Sensor *s, list_sensors)
{
if (s->label == _label)
return idx;
idx++;
}
return -1;
}
int XlruChartClass::findSensorName(QString _name)
{
int idx = 0;
foreach (Sensor *s, list_sensors)
{
if (s->name == _name)
return idx;
idx++;
}
return -1;
}
int XlruChartClass::addSensorFromConfig(sensor_config_t *sensor_config)
{
//int count_sensor = list_sensors.count();
int idx = findSensorName(sensor_config->name);
if (idx != -1)
{
//Already exist!!
return -1;
}
if ((report_enabled) && (report!=0))
report->addSensorCol(sensor_config->label_sensor);
Sensor *newSensor = new Sensor();
QLineSeries* s;
newSensor->view=mainView;
newSensor->name = sensor_config->name;
newSensor->label = sensor_config->label_sensor;
newSensor->type_serie = sensor_config->type;
newSensor->limit = sensor_config->limit;
newSensor->limitFlag = true;
newSensor->fpga_ch = sensor_config->fpga_ch;
switch (newSensor->type_serie)
{
case type_s_temperature:
newSensor->axis=temperatureY;
if (ch->axes().indexOf(temperatureY, 0)==-1)
ch->addAxis(temperatureY, AXIS_ALIGNMENT_TEMP);
s=addSeries(sensor_config->label_sensor, temperatureY);
break;
case type_s_current:
newSensor->axis=currentY;
if (ch->axes().indexOf(currentY, 0)==-1)
ch->addAxis(currentY, AXIS_ALIGNMENT_CURR);
s=addSeries(sensor_config->label_sensor, currentY);
break;
case type_s_voltage:
newSensor->axis=voltageY;
if (ch->axes().indexOf(voltageY, 0)==-1)
ch->addAxis(voltageY, AXIS_ALIGNMENT_CURR);
s=addSeries(sensor_config->label_sensor, voltageY);
break;
default:
break;
}
QPen pen = s->pen();
pen.setWidth(penDim);
s->setPen(pen);
s->setName(QString("%1(%2)").arg(sensor_config->label_sensor).arg(sensor_config->limit));
newSensor->series=s;
list_sensors.append(newSensor);
#ifdef USE_TABLE
//add sensor table
if (SensorsTable!=nullptr)
{
SensorsTable->addNewSensor(sensor_config->label_sensor);
}
#endif
return list_sensors.size();
}
QLineSeries* XlruChartClass::addSeries(QString _name, QValueAxis* _axis)
{
QLineSeries* new_series=new QLineSeries;
//list_series.append(new_series);
ch->addSeries(new_series);
ch->setAxisX(commonX, new_series);
ch->setAxisY(_axis, new_series);
new_series->setName(_name);
return new_series;
}
void XlruChartClass::addSample(QString name_sensor , float value)
{
int idx = findSensorName(name_sensor);
if (idx == -1)
{
//sensor not exists
return;
}
QLineSeries* s=list_sensors[idx]->series;
QString sensor_label = list_sensors[idx]->label;
if (s==0)
return;
#ifdef TELEMETRY
if (telemetry!=0)
telemetry->start("add to serie");
#endif
if (UPDATE_OPTIMIZED)
{
//controlla se manca meno di TIME_DELTA_XMAX secondi da xmax
qint64 axisXmaxNum= commonX->max().toMSecsSinceEpoch();
qint64 nowNum= timeNow.toMSecsSinceEpoch();
qint64 delta = axisXmaxNum - nowNum;
if (delta< TIME_DELTA_XMAX*1000) //10 seconds
{
QDateTime newmax = timeNow.addSecs(TIME_UPDATE_XMAX);
commonX->setMax(newmax);
}
}
lastSampleMs=timeNowMs;
s->append(timeNowMs, value);
#ifdef TELEMETRY
if (telemetry!=0)
telemetry->stop();
#endif
if ((report!=0) && (report_enabled))
{
#ifdef TELEMETRY
if (telemetry!=0)
telemetry->start("update report");
#endif
report->addValueCol(sensor_label , value);
#ifdef TELEMETRY
if (telemetry!=0)
telemetry->stop();
#endif
}
#ifdef TRACKING_VALUE
valueToScreen->setText(QString("%1 %2").arg(timeNowMs).arg(value));
#endif
#ifdef TELEMETRY
if (telemetry!=0)
telemetry->start("update axis");
#endif
Sensor *se = list_sensors[idx];
QtCharts::QValueAxis *a=se->axis;
if (a!=0)
{
if (a->min()>value)
{
a->setMin(value-1.0);
}
else if (a->max()<value)
{
a->setMax(value+1.0);
}
}
//if (!getRemoveLimit())
{
if ((se->limitFlag) && (value>=se->limit))
{
QApplication::beep();
switch (se->type_serie)
{
case type_s_temperature:
showWarning(QString("%1 -> Over-temperature (%2 celsius)").arg(s->name()).arg(value));
break;
case type_s_current:
showWarning(QString("%1 -> Over-current (%2 ampere)").arg(s->name()).arg(value));
break;
case type_s_voltage:
showWarning(QString("%1 -> Over-voltage (%2 volt)").arg(s->name()).arg(value));
break;
}
}
}
#ifdef USE_TABLE
//add sensor table
if (SensorsTable!=nullptr)
{
SensorsTable->update_sensor(sensor_label, value);
}
#endif
#ifdef TELEMETRY
if (telemetry!=0)
telemetry->stop();
#endif
}
void XlruChartClass::timerEvent()
{
timeNow=QDateTime::currentDateTime();
timeNowMs=timeNow.toMSecsSinceEpoch();
if ((timeNowMs-lastSampleMs)>1000*10) //Dead?
{
//p_.tgtAlive=false;
}
else
{
if (! UPDATE_OPTIMIZED)
commonX->setMax(timeNow);
switch(autopurge_enabled)
{
default:
case Qt::Unchecked:
break;
case Qt::PartiallyChecked:
{
qint64 delta=timeNowMs-timeStartMs;
if (delta>(1000*60*60)) //1h
{
timeStart=timeNow.addMSecs(-60*PURGE_PARTIAL_DEF*1000);
timeStartMs=timeStart.toMSecsSinceEpoch();
commonX->setMin(timeStart);
}
}
break;
case Qt::Checked:
{
//if (!p_.tgtAlive)
{
timeStart=timeNow.addMSecs(-60*PURGE_DEF*1000);
timeStartMs=timeStart.toMSecsSinceEpoch();
commonX->setMin(timeStart);
}
}
break;
}
}
}
void XlruChartClass::setReport(bool enabled)
{
report_enabled = enabled;
}
void XlruChartClass::connectMarkers()
{
// Connect all markers to handler
foreach (QLegendMarker* marker, ch->legend()->markers())
{
// Disconnect possible existing connection to avoid multiple connections
QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
QObject::connect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
}
}
void XlruChartClass::disconnectMarkers()
{
foreach (QLegendMarker* marker, ch->legend()->markers()) {
QObject::disconnect(marker, SIGNAL(clicked()), this, SLOT(handleMarkerClicked()));
}
}
void XlruChartClass::handleMarkerClicked()
{
QLegendMarker* marker = qobject_cast<QLegendMarker*> (sender());
Q_ASSERT(marker);
switch (marker->type())
{
case QLegendMarker::LegendMarkerTypeXY:
{
// Toggle visibility of series
marker->series()->setVisible(!marker->series()->isVisible());
// Turn legend marker back to visible, since hiding series also hides the marker
// and we don't want it to happen now.
marker->setVisible(true);
// Dim the marker, if series is not visible
qreal alpha = 1.0;
if (!marker->series()->isVisible())
{
alpha = 0.5;
}
QColor color;
QBrush brush = marker->labelBrush();
color = brush.color();
color.setAlphaF(alpha);
brush.setColor(color);
marker->setLabelBrush(brush);
brush = marker->brush();
color = brush.color();
color.setAlphaF(alpha);
brush.setColor(color);
marker->setBrush(brush);
QPen pen = marker->pen();
color = pen.color();
color.setAlphaF(alpha);
pen.setColor(color);
marker->setPen(pen);
break;
}
default:
{
qDebug() << "Unknown marker type";
break;
}
}
}
void XlruChartClass::connectTooltip()
{
// Connect all series to handler
foreach (Sensor *s, list_sensors)
{
connect(s->series, &QLineSeries::clicked, this, &XlruChartClass::keepCallout);
connect(s->series, &QLineSeries::hovered, this, &XlruChartClass::tooltip);
}
}
void XlruChartClass::keepCallout()
{
QAbstractSeries *series = qobject_cast<QAbstractSeries *>(sender());
m_callouts.append(m_tooltip);
m_tooltip = new Callout(ch, series);
m_tooltip->hide();
}
void XlruChartClass::tooltip(QPointF point, bool state)
{
QAbstractSeries *series = qobject_cast<QAbstractSeries *>(sender());
if (m_tooltip == 0)
{
m_tooltip = new Callout(ch, series);
}
if (state)
{
m_tooltip->setSeries(series);
//QPointF pointFound = ch->mapToValue(point, series);
qreal yVal = point.y();
m_tooltip->setText(QString().sprintf("%s\n %0.2f", series->name().toStdString().c_str(), yVal));
m_tooltip->setAnchor(point);
m_tooltip->updateGeometry();
m_tooltip->show();
}
else
{
m_tooltip->hide();
}
}
void XlruChartClass::showWarning(QString _mess)
{
alertBox.setText(_mess);
alertBox.setIcon(QMessageBox::Warning);
alertBox.setWindowTitle("WARNING");
alertBox.setWindowFlags(Qt::WindowStaysOnTopHint);
alertBox.setModal( false );
alertBox.show();
alertBox.raise();
}
void XlruChartClass::setPenDim(int _dim)
{
penDim = _dim;
}
void XlruChartClass::purge()
{
auto ts=timeNow.addSecs(-60*PURGE_DEF);
timeStart=ts;
timeStartMs=ts.toMSecsSinceEpoch();
commonX->setMin(ts);
}
void XlruChartClass::clear()
{
foreach (Sensor *s, list_sensors)
{
s->series->clear();
}
commonX->setMin(commonX->max().addSecs(-60));
}
void XlruChartClass::save_header_info()
{
if ((report!=0) && (report_enabled))
{
report->saveHeader();
}
}
void XlruChartClass::save_all_sample()
{
if ((report!=0) && (report_enabled))
{
report->saveValue();
}
}
void XlruChartClass::setRemoveLimit(bool new_value)
{
remove_limit = new_value;
}
bool XlruChartClass::getRemoveLimit()
{
return remove_limit;
}
#ifdef TELEMETRY
void XlruChartClass::setTelemetry(telemetryClass *_telemetry)
{
telemetry = _telemetry;
}
#endif