595 lines
14 KiB
C++
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
|