Commit f26fec83726394bb3f3fa46452f00dc1d6bb07d1

Authored by David Graeff
Committed by David Gräff
1 parent 9c6b32e7

Remove private fields of MainWindow that are not used. Adapt MainWindow and DsoWidget to changes.

openhantek/src/dsowidget.cpp
@@ -10,22 +10,24 @@ @@ -10,22 +10,24 @@
10 10
11 #include "dsowidget.h" 11 #include "dsowidget.h"
12 12
13 -#include "exporter.h"  
14 -#include "glgenerator.h" 13 +#include "post/graphgenerator.h"
  14 +#include "post/ppresult.h"
  15 +
  16 +#include "utils/dsoStrings.h"
  17 +#include "utils/printutils.h"
  18 +
15 #include "glscope.h" 19 #include "glscope.h"
16 #include "scopesettings.h" 20 #include "scopesettings.h"
  21 +#include "viewconstants.h"
17 #include "viewsettings.h" 22 #include "viewsettings.h"
18 -#include "utils/dsoStrings.h"  
19 -#include "utils/printutils.h"  
20 #include "widgets/levelslider.h" 23 #include "widgets/levelslider.h"
21 -#include "viewconstants.h"  
22 -#include "analyse/dataanalyzerresult.h"  
23 24
24 static int zoomScopeRow = 0; 25 static int zoomScopeRow = 0;
25 26
26 -DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::ControlSpecification *spec, QWidget *parent, Qt::WindowFlags flags)  
27 - : QWidget(parent, flags), scope(scope), view(view), spec(spec), generator(new GlGenerator()),  
28 - mainScope(GlScope::createNormal(scope, view, generator)), zoomScope(GlScope::createZoomed(scope, view, generator)) { 27 +DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::ControlSpecification *spec,
  28 + QWidget *parent, Qt::WindowFlags flags)
  29 + : QWidget(parent, flags), scope(scope), view(view), spec(spec), mainScope(GlScope::createNormal(scope, view)),
  30 + zoomScope(GlScope::createZoomed(scope, view)) {
29 31
30 // Palette for this widget 32 // Palette for this widget
31 QPalette palette; 33 QPalette palette;
@@ -37,6 +39,7 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso:: @@ -37,6 +39,7 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::
37 39
38 connect(mainScope, &GlScope::markerMoved, [this] (int marker, double position) { 40 connect(mainScope, &GlScope::markerMoved, [this] (int marker, double position) {
39 double step = this->mainSliders.markerSlider->step(marker); 41 double step = this->mainSliders.markerSlider->step(marker);
  42 +
40 this->scope->horizontal.marker[marker] = 43 this->scope->horizontal.marker[marker] =
41 this->mainSliders.markerSlider->setValue(marker, std::round(position / step) * step); 44 this->mainSliders.markerSlider->setValue(marker, std::round(position / step) * step);
42 }); 45 });
@@ -62,6 +65,7 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso:: @@ -62,6 +65,7 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::
62 swTriggerStatus->setText(tr("TR")); 65 swTriggerStatus->setText(tr("TR"));
63 swTriggerStatus->setAlignment(Qt::AlignCenter); 66 swTriggerStatus->setAlignment(Qt::AlignCenter);
64 swTriggerStatus->setAutoFillBackground(true); 67 swTriggerStatus->setAutoFillBackground(true);
  68 + swTriggerStatus->setVisible(false);
65 settingsLayout = new QHBoxLayout(); 69 settingsLayout = new QHBoxLayout();
66 settingsLayout->addWidget(swTriggerStatus); 70 settingsLayout->addWidget(swTriggerStatus);
67 settingsLayout->addWidget(settingsTriggerLabel); 71 settingsLayout->addWidget(settingsTriggerLabel);
@@ -259,14 +263,7 @@ void DsoWidget::setupSliders(DsoWidget::Sliders &sliders) { @@ -259,14 +263,7 @@ void DsoWidget::setupSliders(DsoWidget::Sliders &sliders) {
259 } 263 }
260 } 264 }
261 265
262 -void DsoWidget::showNewData(std::unique_ptr<DataAnalyzerResult> data) {  
263 - if (!data) return;  
264 - this->data = std::move(data);  
265 - emit doShowNewData();  
266 -}  
267 -  
268 -void DsoWidget::setExporterForNextFrame(std::unique_ptr<Exporter> exporter)  
269 -{ 266 +void DsoWidget::setExporterForNextFrame(std::unique_ptr<Exporter> exporter) {
270 this->exportNextFrame = std::move(exporter); 267 this->exportNextFrame = std::move(exporter);
271 } 268 }
272 269
@@ -317,9 +314,12 @@ void DsoWidget::updateMarkerDetails() { @@ -317,9 +314,12 @@ void DsoWidget::updateMarkerDetails() {
317 markerFrequencybaseLabel->setText( 314 markerFrequencybaseLabel->setText(
318 valueToString(divs * scope->horizontal.frequencybase / DIVS_TIME, UNIT_HERTZ, 4) + tr("/div")); 315 valueToString(divs * scope->horizontal.frequencybase / DIVS_TIME, UNIT_HERTZ, 4) + tr("/div"));
319 } 316 }
320 - markerInfoLabel->setText(infoLabelPrefix.append(": %1 %2")  
321 - .arg(valueToString(0.5 + scope->horizontal.marker[0] / DIVS_TIME - scope->trigger.position, UNIT_SECONDS, 4))  
322 - .arg(valueToString(0.5 + scope->horizontal.marker[1] / DIVS_TIME - scope->trigger.position, UNIT_SECONDS, 4))); 317 + markerInfoLabel->setText(
  318 + infoLabelPrefix.append(": %1 %2")
  319 + .arg(
  320 + valueToString(0.5 + scope->horizontal.marker[0] / DIVS_TIME - scope->trigger.position, UNIT_SECONDS, 4))
  321 + .arg(valueToString(0.5 + scope->horizontal.marker[1] / DIVS_TIME - scope->trigger.position, UNIT_SECONDS,
  322 + 4)));
323 323
324 markerTimeLabel->setText(valueToString(time, UNIT_SECONDS, 4)); 324 markerTimeLabel->setText(valueToString(time, UNIT_SECONDS, 4));
325 markerFrequencyLabel->setText(valueToString(1.0 / time, UNIT_HERTZ, 4)); 325 markerFrequencyLabel->setText(valueToString(1.0 / time, UNIT_HERTZ, 4));
@@ -330,8 +330,8 @@ void DsoWidget::updateSpectrumDetails(ChannelID channel) { @@ -330,8 +330,8 @@ void DsoWidget::updateSpectrumDetails(ChannelID channel) {
330 setMeasurementVisible(channel); 330 setMeasurementVisible(channel);
331 331
332 if (scope->spectrum[channel].used) 332 if (scope->spectrum[channel].used)
333 - measurementMagnitudeLabel[channel]->setText(  
334 - valueToString(scope->spectrum[channel].magnitude, UNIT_DECIBEL, 3) + tr("/div")); 333 + measurementMagnitudeLabel[channel]->setText(valueToString(scope->spectrum[channel].magnitude, UNIT_DECIBEL, 3) +
  334 + tr("/div"));
335 else 335 else
336 measurementMagnitudeLabel[channel]->setText(QString()); 336 measurementMagnitudeLabel[channel]->setText(QString());
337 } 337 }
@@ -346,8 +346,7 @@ void DsoWidget::updateTriggerDetails() { @@ -346,8 +346,7 @@ void DsoWidget::updateTriggerDetails() {
346 QString pretriggerString = tr("%L1%").arg((int)(scope->trigger.position * 100 + 0.5)); 346 QString pretriggerString = tr("%L1%").arg((int)(scope->trigger.position * 100 + 0.5));
347 settingsTriggerLabel->setText(tr("%1 %2 %3 %4") 347 settingsTriggerLabel->setText(tr("%1 %2 %3 %4")
348 .arg(scope->voltage[scope->trigger.source].name, 348 .arg(scope->voltage[scope->trigger.source].name,
349 - Dso::slopeString(scope->trigger.slope), levelString,  
350 - pretriggerString)); 349 + Dso::slopeString(scope->trigger.slope), levelString, pretriggerString));
351 350
352 /// \todo This won't work for special trigger sources 351 /// \todo This won't work for special trigger sources
353 } 352 }
@@ -359,8 +358,7 @@ void DsoWidget::updateVoltageDetails(ChannelID channel) { @@ -359,8 +358,7 @@ void DsoWidget::updateVoltageDetails(ChannelID channel) {
359 setMeasurementVisible(channel); 358 setMeasurementVisible(channel);
360 359
361 if (scope->voltage[channel].used) 360 if (scope->voltage[channel].used)
362 - measurementGainLabel[channel]->setText(valueToString(scope->gain(channel), UNIT_VOLTS, 3) +  
363 - tr("/div")); 361 + measurementGainLabel[channel]->setText(valueToString(scope->gain(channel), UNIT_VOLTS, 3) + tr("/div"));
364 else 362 else
365 measurementGainLabel[channel]->setText(QString()); 363 measurementGainLabel[channel]->setText(QString());
366 } 364 }
@@ -435,13 +433,12 @@ void DsoWidget::updateTriggerSource() { @@ -435,13 +433,12 @@ void DsoWidget::updateTriggerSource() {
435 void DsoWidget::updateVoltageCoupling(ChannelID channel) { 433 void DsoWidget::updateVoltageCoupling(ChannelID channel) {
436 if (channel >= (unsigned int)scope->voltage.size()) return; 434 if (channel >= (unsigned int)scope->voltage.size()) return;
437 435
438 - measurementMiscLabel[channel]->setText(Dso::couplingString(scope->coupling(channel,spec))); 436 + measurementMiscLabel[channel]->setText(Dso::couplingString(scope->coupling(channel, spec)));
439 } 437 }
440 438
441 /// \brief Handles modeChanged signal from the voltage dock. 439 /// \brief Handles modeChanged signal from the voltage dock.
442 void DsoWidget::updateMathMode() { 440 void DsoWidget::updateMathMode() {
443 - measurementMiscLabel[spec->channels]->setText(  
444 - Dso::mathModeString(scope->voltage[spec->channels].math)); 441 + measurementMiscLabel[spec->channels]->setText(Dso::mathModeString(scope->voltage[spec->channels].math));
445 } 442 }
446 443
447 /// \brief Handles gainChanged signal from the voltage dock. 444 /// \brief Handles gainChanged signal from the voltage dock.
@@ -505,26 +502,32 @@ void DsoWidget::updateZoom(bool enabled) { @@ -505,26 +502,32 @@ void DsoWidget::updateZoom(bool enabled) {
505 } 502 }
506 503
507 /// \brief Prints analyzed data. 504 /// \brief Prints analyzed data.
508 -void DsoWidget::doShowNewData() { 505 +void DsoWidget::showNew(std::shared_ptr<PPresult> data) {
509 if (exportNextFrame) { 506 if (exportNextFrame) {
510 exportNextFrame->exportSamples(data.get()); 507 exportNextFrame->exportSamples(data.get());
511 exportNextFrame.reset(nullptr); 508 exportNextFrame.reset(nullptr);
512 } 509 }
513 510
514 - bool triggered = generator->generateGraphs(data.get(), view->digitalPhosphorDraws(), scope, spec);  
515 -  
516 - QPalette triggerLabelPalette = palette();  
517 - triggerLabelPalette.setColor(QPalette::WindowText, Qt::black);  
518 - triggerLabelPalette.setColor(QPalette::Background, triggered ? Qt::green : Qt::red);  
519 - swTriggerStatus->setPalette(triggerLabelPalette); 511 + mainScope->showData(data.get());
  512 + mainScope->update();
  513 + zoomScope->showData(data.get());
  514 + zoomScope->update();
  515 +
  516 + if (spec->isSoftwareTriggerDevice) {
  517 + QPalette triggerLabelPalette = palette();
  518 + triggerLabelPalette.setColor(QPalette::WindowText, Qt::black);
  519 + triggerLabelPalette.setColor(QPalette::Background, data->softwareTriggerTriggered ? Qt::green : Qt::red);
  520 + swTriggerStatus->setPalette(triggerLabelPalette);
  521 + swTriggerStatus->setVisible(true);
  522 + }
520 523
521 - updateRecordLength(data.get()->getMaxSamples()); 524 + updateRecordLength(data.get()->sampleCount());
522 525
523 for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) { 526 for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {
524 if (scope->voltage[channel].used && data.get()->data(channel)) { 527 if (scope->voltage[channel].used && data.get()->data(channel)) {
525 // Amplitude string representation (4 significant digits) 528 // Amplitude string representation (4 significant digits)
526 measurementAmplitudeLabel[channel]->setText( 529 measurementAmplitudeLabel[channel]->setText(
527 - valueToString(data.get()->data(channel)->amplitude, UNIT_VOLTS, 4)); 530 + valueToString(data.get()->data(channel)->computeAmplitude(), UNIT_VOLTS, 4));
528 // Frequency string representation (5 significant digits) 531 // Frequency string representation (5 significant digits)
529 measurementFrequencyLabel[channel]->setText( 532 measurementFrequencyLabel[channel]->setText(
530 valueToString(data.get()->data(channel)->frequency, UNIT_HERTZ, 5)); 533 valueToString(data.get()->data(channel)->frequency, UNIT_HERTZ, 5));
openhantek/src/dsowidget.h
@@ -8,16 +8,15 @@ @@ -8,16 +8,15 @@
8 #include <QGridLayout> 8 #include <QGridLayout>
9 #include <memory> 9 #include <memory>
10 10
11 -#include "exporter.h" 11 +#include "exporting/exporter.h"
12 #include "glscope.h" 12 #include "glscope.h"
13 #include "levelslider.h" 13 #include "levelslider.h"
14 #include "hantekdso/controlspecification.h" 14 #include "hantekdso/controlspecification.h"
15 15
16 -class DataAnalyzer; 16 +class SpectrumGenerator;
17 struct DsoSettingsScope; 17 struct DsoSettingsScope;
18 struct DsoSettingsView; 18 struct DsoSettingsView;
19 19
20 -/// \class DsoWidget  
21 /// \brief The widget for the oszilloscope-screen 20 /// \brief The widget for the oszilloscope-screen
22 /// This widget contains the scopes and all level sliders. 21 /// This widget contains the scopes and all level sliders.
23 class DsoWidget : public QWidget { 22 class DsoWidget : public QWidget {
@@ -37,9 +36,11 @@ class DsoWidget : public QWidget { @@ -37,9 +36,11 @@ class DsoWidget : public QWidget {
37 /// \param parent The parent widget. 36 /// \param parent The parent widget.
38 /// \param flags Flags for the window manager. 37 /// \param flags Flags for the window manager.
39 DsoWidget(DsoSettingsScope* scope, DsoSettingsView* view, const Dso::ControlSpecification* spec, QWidget *parent = 0, Qt::WindowFlags flags = 0); 38 DsoWidget(DsoSettingsScope* scope, DsoSettingsView* view, const Dso::ControlSpecification* spec, QWidget *parent = 0, Qt::WindowFlags flags = 0);
40 - void showNewData(std::unique_ptr<DataAnalyzerResult> data);  
41 void setExporterForNextFrame(std::unique_ptr<Exporter> exporter); 39 void setExporterForNextFrame(std::unique_ptr<Exporter> exporter);
42 40
  41 + // Data arrived
  42 + void showNew(std::shared_ptr<PPresult> data);
  43 +
43 protected: 44 protected:
44 void setupSliders(Sliders &sliders); 45 void setupSliders(Sliders &sliders);
45 void adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel); 46 void adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel);
@@ -83,11 +84,10 @@ class DsoWidget : public QWidget { @@ -83,11 +84,10 @@ class DsoWidget : public QWidget {
83 DsoSettingsView* view; 84 DsoSettingsView* view;
84 const Dso::ControlSpecification* spec; 85 const Dso::ControlSpecification* spec;
85 86
86 - GlGenerator *generator; ///< The generator for the OpenGL vertex arrays  
87 GlScope *mainScope; ///< The main scope screen 87 GlScope *mainScope; ///< The main scope screen
88 GlScope *zoomScope; ///< The optional magnified scope screen 88 GlScope *zoomScope; ///< The optional magnified scope screen
89 std::unique_ptr<Exporter> exportNextFrame; 89 std::unique_ptr<Exporter> exportNextFrame;
90 - std::unique_ptr<DataAnalyzerResult> data; 90 + std::shared_ptr<PPresult> data;
91 91
92 public slots: 92 public slots:
93 // Horizontal axis 93 // Horizontal axis
@@ -117,9 +117,6 @@ class DsoWidget : public QWidget { @@ -117,9 +117,6 @@ class DsoWidget : public QWidget {
117 // Scope control 117 // Scope control
118 void updateZoom(bool enabled); 118 void updateZoom(bool enabled);
119 119
120 - // Data analyzer  
121 - void doShowNewData();  
122 -  
123 private slots: 120 private slots:
124 // Sliders 121 // Sliders
125 void updateOffset(ChannelID channel, double value); 122 void updateOffset(ChannelID channel, double value);
openhantek/src/glgenerator.cpp deleted
1 -// SPDX-License-Identifier: GPL-2.0+  
2 -  
3 -#include <QMutex>  
4 -#include <QDebug>  
5 -  
6 -#include "glgenerator.h"  
7 -#include "utils/printutils.h"  
8 -#include "settings.h"  
9 -#include "analyse/dataanalyzerresult.h"  
10 -#include "viewconstants.h"  
11 -#include "hantekdso/softwaretrigger.h"  
12 -#include "hantekdso/controlspecification.h"  
13 -  
14 -static const SampleValues& useSamplesOf(Dso::ChannelMode mode, ChannelID channel, const DataAnalyzerResult *result, const DsoSettingsScope *scope) {  
15 - static SampleValues emptyDefault;  
16 - if (mode == Dso::ChannelMode::Voltage) {  
17 - if (!scope->voltage[channel].used || !result->data(channel)) return emptyDefault;  
18 - return result->data(channel)->voltage;  
19 - } else {  
20 - if (!scope->spectrum[channel].used || !result->data(channel)) return emptyDefault;  
21 - return result->data(channel)->spectrum;  
22 - }  
23 -}  
24 -  
25 -GlGenerator::GlGenerator() {  
26 - // Grid  
27 - const int DIVS_TIME_S2 = (int)DIVS_TIME - 2;  
28 - const int DIVS_VOLTAGE_S2 = (int)DIVS_VOLTAGE - 2;  
29 - const int vaGrid0Size = (int) ((DIVS_TIME * DIVS_SUB - 2) * DIVS_VOLTAGE_S2 +  
30 - (DIVS_VOLTAGE * DIVS_SUB - 2) * DIVS_TIME_S2 -  
31 - (DIVS_TIME_S2 * DIVS_VOLTAGE_S2)) * 2;  
32 -  
33 - vaGrid[0].resize(vaGrid0Size);  
34 - std::vector<GLfloat>::iterator glIterator = vaGrid[0].begin();  
35 - // Draw vertical lines  
36 - for (int div = 1; div < DIVS_TIME / 2; ++div) {  
37 - for (int dot = 1; dot < DIVS_VOLTAGE / 2 * DIVS_SUB; ++dot) {  
38 - float dotPosition = (float)dot / DIVS_SUB;  
39 - *(glIterator++) = -div;  
40 - *(glIterator++) = -dotPosition;  
41 - *(glIterator++) = -div;  
42 - *(glIterator++) = dotPosition;  
43 - *(glIterator++) = div;  
44 - *(glIterator++) = -dotPosition;  
45 - *(glIterator++) = div;  
46 - *(glIterator++) = dotPosition;  
47 - }  
48 - }  
49 - // Draw horizontal lines  
50 - for (int div = 1; div < DIVS_VOLTAGE / 2; ++div) {  
51 - for (int dot = 1; dot < DIVS_TIME / 2 * DIVS_SUB; ++dot) {  
52 - if (dot % DIVS_SUB == 0) continue; // Already done by vertical lines  
53 - float dotPosition = (float)dot / DIVS_SUB;  
54 - *(glIterator++) = -dotPosition;  
55 - *(glIterator++) = -div;  
56 - *(glIterator++) = dotPosition;  
57 - *(glIterator++) = -div;  
58 - *(glIterator++) = -dotPosition;  
59 - *(glIterator++) = div;  
60 - *(glIterator++) = dotPosition;  
61 - *(glIterator++) = div;  
62 - }  
63 - }  
64 -  
65 - // Axes  
66 - vaGrid[1].resize((int)(2 + (DIVS_TIME * DIVS_SUB - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2)) * 4);  
67 - glIterator = vaGrid[1].begin();  
68 - // Horizontal axis  
69 - *(glIterator++) = -DIVS_TIME / 2;  
70 - *(glIterator++) = 0;  
71 - *(glIterator++) = DIVS_TIME / 2;  
72 - *(glIterator++) = 0;  
73 - // Vertical axis  
74 - *(glIterator++) = 0;  
75 - *(glIterator++) = -DIVS_VOLTAGE / 2;  
76 - *(glIterator++) = 0;  
77 - *(glIterator++) = DIVS_VOLTAGE / 2;  
78 - // Subdiv lines on horizontal axis  
79 - for (int line = 1; line < DIVS_TIME / 2 * DIVS_SUB; ++line) {  
80 - float linePosition = (float)line / DIVS_SUB;  
81 - *(glIterator++) = linePosition;  
82 - *(glIterator++) = -0.05f;  
83 - *(glIterator++) = linePosition;  
84 - *(glIterator++) = 0.05f;  
85 - *(glIterator++) = -linePosition;  
86 - *(glIterator++) = -0.05f;  
87 - *(glIterator++) = -linePosition;  
88 - *(glIterator++) = 0.05f;  
89 - }  
90 - // Subdiv lines on vertical axis  
91 - for (int line = 1; line < DIVS_VOLTAGE / 2 * DIVS_SUB; ++line) {  
92 - float linePosition = (float)line / DIVS_SUB;  
93 - *(glIterator++) = -0.05f;  
94 - *(glIterator++) = linePosition;  
95 - *(glIterator++) = 0.05f;  
96 - *(glIterator++) = linePosition;  
97 - *(glIterator++) = -0.05f;  
98 - *(glIterator++) = -linePosition;  
99 - *(glIterator++) = 0.05f;  
100 - *(glIterator++) = -linePosition;  
101 - }  
102 -  
103 - // Border  
104 - vaGrid[2].resize(4 * 2);  
105 - glIterator = vaGrid[2].begin();  
106 - *(glIterator++) = -DIVS_TIME / 2;  
107 - *(glIterator++) = -DIVS_VOLTAGE / 2;  
108 - *(glIterator++) = DIVS_TIME / 2;  
109 - *(glIterator++) = -DIVS_VOLTAGE / 2;  
110 - *(glIterator++) = DIVS_TIME / 2;  
111 - *(glIterator++) = DIVS_VOLTAGE / 2;  
112 - *(glIterator++) = -DIVS_TIME / 2;  
113 - *(glIterator++) = DIVS_VOLTAGE / 2;  
114 -}  
115 -  
116 -const std::vector<GLfloat> &GlGenerator::channel(Dso::ChannelMode mode, ChannelID channel, unsigned index) const {  
117 - return vaChannel[(unsigned)mode][channel][index];  
118 -}  
119 -  
120 -const std::vector<GLfloat> &GlGenerator::grid(int a) const { return vaGrid[a]; }  
121 -  
122 -bool GlGenerator::isReady() const { return ready; }  
123 -  
124 -bool GlGenerator::generateGraphs(const DataAnalyzerResult *result, unsigned digitalPhosphorDepth,  
125 - const DsoSettingsScope *scope, const Dso::ControlSpecification* spec) {  
126 -  
127 - // Handle all digital phosphor related list manipulations  
128 - for (Dso::ChannelMode mode: Dso::ChannelModeEnum) {  
129 - DrawLinesWithHistoryPerChannel& d = vaChannel[(unsigned)mode];  
130 - // Resize to the number of channels  
131 - d.resize(scope->voltage.size());  
132 -  
133 - for (ChannelID channel = 0; channel < vaChannel[(unsigned)mode].size(); ++channel) {  
134 - DrawLinesWithHistory& drawLinesHistory = d[channel];  
135 - // Move the last list element to the front  
136 - if (digitalPhosphorDepth > 1 && drawLinesHistory.size())  
137 - drawLinesHistory.push_front(drawLinesHistory.back());  
138 -  
139 - // Resize lists for vector array to fit the digital phosphor depth  
140 - drawLinesHistory.resize(digitalPhosphorDepth);  
141 - }  
142 - }  
143 -  
144 - ready = true;  
145 -  
146 - unsigned preTrigSamples=0;  
147 - unsigned postTrigSamples=0;  
148 - unsigned swTriggerStart=0;  
149 - bool triggered = false;  
150 -  
151 - switch (scope->horizontal.format) {  
152 - case Dso::GraphFormat::TY:  
153 - // check trigger point for software trigger  
154 - if (spec->isSoftwareTriggerDevice && scope->trigger.source < spec->channels)  
155 - std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = SoftwareTrigger::compute(result, scope);  
156 - triggered = postTrigSamples > preTrigSamples;  
157 -  
158 - // Add graphs for channels  
159 - for (Dso::ChannelMode mode: Dso::ChannelModeEnum) {  
160 - DrawLinesWithHistoryPerChannel& dPerChannel = vaChannel[(unsigned)mode];  
161 - for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {  
162 - DrawLinesWithHistory& withHistory = dPerChannel[channel];  
163 - const SampleValues& samples = useSamplesOf(mode, channel, result, scope);  
164 -  
165 - // Check if this channel is used and available at the data analyzer  
166 - if (samples.sample.empty()) {  
167 - // Delete all vector arrays  
168 - for (unsigned index = 0; index < digitalPhosphorDepth; ++index)  
169 - withHistory[index].clear();  
170 - continue;  
171 - }  
172 - // Check if the sample count has changed  
173 - size_t sampleCount = samples.sample.size();  
174 - if (sampleCount>500000) {  
175 - qWarning() << "Sample count too high!";  
176 - throw new std::runtime_error("Sample count too high!");  
177 - }  
178 - if (mode == Dso::ChannelMode::Voltage)  
179 - sampleCount -= (swTriggerStart - preTrigSamples);  
180 - size_t neededSize = sampleCount * 2;  
181 -  
182 -#if 0  
183 - for(unsigned int index = 0; index < digitalPhosphorDepth; ++index) {  
184 - if(vaChannel[mode][channel][index].size() != neededSize)  
185 - vaChannel[mode][channel][index].clear(); // Something was changed, drop old traces  
186 - }  
187 -#endif  
188 -  
189 - // Set size directly to avoid reallocations  
190 - withHistory.front().resize(neededSize);  
191 -  
192 - // Iterator to data for direct access  
193 - DrawLines::iterator glIterator = withHistory.front().begin();  
194 -  
195 - // What's the horizontal distance between sampling points?  
196 - float horizontalFactor;  
197 - if (mode == Dso::ChannelMode::Voltage)  
198 - horizontalFactor = (float)(samples.interval / scope->horizontal.timebase);  
199 - else  
200 - horizontalFactor = (float)(samples.interval / scope->horizontal.frequencybase);  
201 -  
202 - // Fill vector array  
203 - if (mode == Dso::ChannelMode::Voltage) {  
204 - std::vector<double>::const_iterator dataIterator = samples.sample.begin();  
205 - const float gain = (float) scope->gain(channel);  
206 - const float offset = (float) scope->voltage[channel].offset;  
207 - const float invert = scope->voltage[channel].inverted ? -1.0f : 1.0f;  
208 -  
209 - std::advance(dataIterator, swTriggerStart - preTrigSamples);  
210 -  
211 - for (unsigned int position = 0; position < sampleCount; ++position) {  
212 - *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2;  
213 - *(glIterator++) = (float)*(dataIterator++) / gain * invert + offset;  
214 - }  
215 - } else {  
216 - std::vector<double>::const_iterator dataIterator = samples.sample.begin();  
217 - const float magnitude = (float)scope->spectrum[channel].magnitude;  
218 - const float offset = (float)scope->spectrum[channel].offset;  
219 -  
220 - for (unsigned int position = 0; position < sampleCount; ++position) {  
221 - *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2;  
222 - *(glIterator++) = (float)*(dataIterator++) / magnitude + offset;  
223 - }  
224 - }  
225 - }  
226 - }  
227 - break;  
228 -  
229 - case Dso::GraphFormat::XY:  
230 - triggered = true;  
231 - for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {  
232 - // For even channel numbers check if this channel is used and this and the  
233 - // following channel are available at the data analyzer  
234 - if (channel % 2 == 0 && channel + 1 < scope->voltage.size() && scope->voltage[channel].used &&  
235 - result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) &&  
236 - !result->data(channel + 1)->voltage.sample.empty()) {  
237 - // Check if the sample count has changed  
238 - const size_t sampleCount = std::min(result->data(channel)->voltage.sample.size(),  
239 - result->data(channel + 1)->voltage.sample.size());  
240 - const size_t neededSize = sampleCount * 2;  
241 - DrawLinesWithHistory& withHistory = vaChannel[(unsigned)Dso::ChannelMode::Voltage][(size_t)channel];  
242 - for (unsigned index = 0; index < digitalPhosphorDepth; ++index) {  
243 - if (withHistory[index].size() != neededSize)  
244 - withHistory[index].clear(); // Something was changed, drop old traces  
245 - }  
246 -  
247 - // Set size directly to avoid reallocations  
248 - DrawLines& drawLines = withHistory.front();  
249 - drawLines.resize(neededSize);  
250 -  
251 - // Iterator to data for direct access  
252 - std::vector<GLfloat>::iterator glIterator = drawLines.begin();  
253 -  
254 - // Fill vector array  
255 - unsigned int xChannel = channel;  
256 - unsigned int yChannel = channel + 1;  
257 - std::vector<double>::const_iterator xIterator = result->data(xChannel)->voltage.sample.begin();  
258 - std::vector<double>::const_iterator yIterator = result->data(yChannel)->voltage.sample.begin();  
259 - const double xGain = scope->gain(xChannel);  
260 - const double yGain = scope->gain(yChannel);  
261 - const double xOffset = scope->voltage[xChannel].offset;  
262 - const double yOffset = scope->voltage[yChannel].offset;  
263 - const double xInvert = scope->voltage[xChannel].inverted ? -1.0 : 1.0;  
264 - const double yInvert = scope->voltage[yChannel].inverted ? -1.0 : 1.0;  
265 -  
266 - for (unsigned int position = 0; position < sampleCount; ++position) {  
267 - *(glIterator++) = (GLfloat)( *(xIterator++) / xGain * xInvert + xOffset);  
268 - *(glIterator++) = (GLfloat)( *(yIterator++) / yGain * yInvert + yOffset);  
269 - }  
270 - } else {  
271 - // Delete all vector arrays  
272 - for (unsigned index = 0; index < digitalPhosphorDepth; ++index)  
273 - vaChannel[(unsigned)Dso::ChannelMode::Voltage][channel][index].clear();  
274 - }  
275 -  
276 - // Delete all spectrum graphs  
277 - for (unsigned index = 0; index < digitalPhosphorDepth; ++index)  
278 - vaChannel[(unsigned)Dso::ChannelMode::Spectrum][channel][index].clear();  
279 - }  
280 - break;  
281 - }  
282 -  
283 - emit graphsGenerated();  
284 -  
285 - return triggered;  
286 -}  
openhantek/src/glgenerator.h deleted
1 -// SPDX-License-Identifier: GPL-2.0+  
2 -  
3 -#pragma once  
4 -  
5 -#include <deque>  
6 -  
7 -#include <QGLFunctions>  
8 -#include <QObject>  
9 -  
10 -#include "hantekdso/enums.h"  
11 -#include "hantekprotocol/definitions.h"  
12 -  
13 -struct DsoSettingsScope;  
14 -class DataAnalyzerResult;  
15 -namespace Dso {  
16 -struct ControlSpecification;  
17 -}  
18 -  
19 -////////////////////////////////////////////////////////////////////////////////  
20 -/// \class GlGenerator  
21 -/// \brief Generates the vertex arrays for the GlScope classes.  
22 -class GlGenerator : public QObject {  
23 - Q_OBJECT  
24 -  
25 - public:  
26 - /// \brief Initializes the scope widget.  
27 - /// \param settings The target settings object.  
28 - /// \param parent The parent widget.  
29 -  
30 - GlGenerator();  
31 - bool generateGraphs(const DataAnalyzerResult *result, unsigned digitalPhosphorDepth, const DsoSettingsScope *scope,  
32 - const Dso::ControlSpecification *spec);  
33 - const std::vector<GLfloat> &channel(Dso::ChannelMode mode, ChannelID channel, unsigned index) const;  
34 -  
35 - const std::vector<GLfloat> &grid(int a) const;  
36 - bool isReady() const;  
37 -  
38 - private:  
39 - typedef std::vector<GLfloat> DrawLines;  
40 - typedef std::deque<DrawLines> DrawLinesWithHistory;  
41 - typedef std::vector<DrawLinesWithHistory> DrawLinesWithHistoryPerChannel;  
42 - DrawLinesWithHistoryPerChannel vaChannel[Dso::ChannelModes];  
43 - std::vector<GLfloat> vaGrid[3];  
44 - bool ready = false;  
45 - signals:  
46 - void graphsGenerated(); ///< The graphs are ready to be drawn  
47 -};  
openhantek/src/glscope.cpp
1 // SPDX-License-Identifier: GPL-2.0+ 1 // SPDX-License-Identifier: GPL-2.0+
2 2
3 #include <cmath> 3 #include <cmath>
  4 +#include <iostream>
4 5
5 #include <QColor> 6 #include <QColor>
  7 +#include <QDebug>
  8 +#include <QMatrix4x4>
6 #include <QMouseEvent> 9 #include <QMouseEvent>
  10 +#include <QOpenGLShaderProgram>
7 11
  12 +#include <QOpenGLFunctions_3_3_Core>
8 #include <QOpenGLFunctions_ES2> 13 #include <QOpenGLFunctions_ES2>
9 -#include <QOpenGLFunctions_3_2_Core>  
10 -#include <QOpenGLFunctions_1_3>  
11 14
12 #include "glscope.h" 15 #include "glscope.h"
13 16
14 -#include "glgenerator.h" 17 +#include "post/graphgenerator.h"
  18 +#include "post/ppresult.h"
15 #include "scopesettings.h" 19 #include "scopesettings.h"
16 -#include "viewsettings.h"  
17 #include "viewconstants.h" 20 #include "viewconstants.h"
  21 +#include "viewsettings.h"
18 22
19 -GlScope *GlScope::createNormal(DsoSettingsScope *scope, DsoSettingsView *view, const GlGenerator *generator, QWidget *parent)  
20 -{  
21 - GlScope* s = new GlScope(scope, view, generator, parent); 23 +// typedef QOpenGLFunctions_ES2 OPENGL_VER;
  24 +typedef QOpenGLFunctions_3_3_Core OPENGL_VER;
  25 +
  26 +GlScope *GlScope::createNormal(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent) {
  27 + GlScope *s = new GlScope(scope, view, parent);
22 s->zoomed = false; 28 s->zoomed = false;
23 return s; 29 return s;
24 } 30 }
25 31
26 -GlScope *GlScope::createZoomed(DsoSettingsScope *scope, DsoSettingsView *view, const GlGenerator *generator, QWidget *parent)  
27 -{  
28 - GlScope* s = new GlScope(scope, view, generator, parent); 32 +GlScope *GlScope::createZoomed(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent) {
  33 + GlScope *s = new GlScope(scope, view, parent);
29 s->zoomed = true; 34 s->zoomed = true;
30 return s; 35 return s;
31 } 36 }
32 37
33 -GlScope::GlScope(DsoSettingsScope *scope, DsoSettingsView *view, const GlGenerator *generator, QWidget *parent)  
34 - : QOpenGLWidget(parent), scope(scope), view(view), generator(generator) {  
35 - connect(generator, &GlGenerator::graphsGenerated, [this]() { update(); });  
36 -}  
37 -  
38 -void GlScope::initializeGL() {  
39 - // TODO: Migrate to OpenGL ES2  
40 - // QOpenGLFunctions_ES2 *localFunctions = context()->versionFunctions<QOpenGLFunctions_ES2>();  
41 - // QOpenGLFunctions_3_2_Core *localFunctions = context()->versionFunctions<QOpenGLFunctions_3_2_Core>();  
42 - QOpenGLFunctions_1_3 *localFunctions = context()->versionFunctions<QOpenGLFunctions_1_3>();  
43 -  
44 - localFunctions->glDisable(GL_DEPTH_TEST);  
45 - localFunctions->glEnable(GL_BLEND);  
46 - localFunctions->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  
47 -  
48 - localFunctions->glPointSize(1);  
49 -  
50 - QColor bg = view->screen.background;  
51 - localFunctions->glClearColor((GLfloat)bg.redF(), (GLfloat)bg.greenF(), (GLfloat)bg.blueF(), (GLfloat)bg.alphaF());  
52 -  
53 - localFunctions->glShadeModel(GL_SMOOTH /*GL_FLAT*/);  
54 - localFunctions->glLineStipple(1, 0x3333);  
55 -  
56 - localFunctions->glEnableClientState(GL_VERTEX_ARRAY);  
57 -}  
58 -  
59 -void GlScope::paintGL() {  
60 - // TODO: Migrate to OpenGL ES2  
61 - // QOpenGLFunctions_ES2 *localFunctions = context()->versionFunctions<QOpenGLFunctions_ES2>();  
62 - // QOpenGLFunctions_3_2_Core *localFunctions = context()->versionFunctions<QOpenGLFunctions_3_2_Core>();  
63 - QOpenGLFunctions_1_3 *localFunctions = context()->versionFunctions<QOpenGLFunctions_1_3>();  
64 -  
65 - // Clear OpenGL buffer and configure settings  
66 - localFunctions->glClear(GL_COLOR_BUFFER_BIT);  
67 - localFunctions->glLineWidth(1);  
68 -  
69 - if (generator->isReady()) { drawGraph(view->digitalPhosphorDraws()); }  
70 -  
71 - if (!this->zoomed) {  
72 - // Draw vertical lines at marker positions  
73 - localFunctions->glEnable(GL_LINE_STIPPLE);  
74 - QColor trColor = view->screen.markers;  
75 - localFunctions->glColor4f((GLfloat)trColor.redF(), (GLfloat)trColor.greenF(), (GLfloat)trColor.blueF(), (GLfloat)trColor.alphaF());  
76 -  
77 - for (int marker = 0; marker < MARKER_COUNT; ++marker) {  
78 - if (!scope->horizontal.marker_visible[marker]) continue;  
79 - if (vaMarker[marker].size() != 4) {  
80 - vaMarker[marker].resize(2 * 2);  
81 - vaMarker[marker][1] = -DIVS_VOLTAGE;  
82 - vaMarker[marker][3] = DIVS_VOLTAGE;  
83 - }  
84 -  
85 - vaMarker[marker][0] = (GLfloat)scope->horizontal.marker[marker];  
86 - vaMarker[marker][2] = (GLfloat)scope->horizontal.marker[marker];  
87 -  
88 - localFunctions->glLineWidth((marker == selectedMarker) ? 3 : 1);  
89 - localFunctions->glVertexPointer(2, GL_FLOAT, 0, &vaMarker[marker].front());  
90 - localFunctions->glDrawArrays(GL_LINES, 0, (GLsizei)vaMarker[marker].size() / 2);  
91 - }  
92 -  
93 - localFunctions->glDisable(GL_LINE_STIPPLE);  
94 - }  
95 -  
96 - // Draw grid  
97 - this->drawGrid(); 38 +GlScope::GlScope(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent)
  39 + : QOpenGLWidget(parent), scope(scope), view(view) {
  40 + vaMarker.resize(MARKER_COUNT);
98 } 41 }
99 42
100 -void GlScope::resizeGL(int width, int height) {  
101 - glViewport(0, 0, (GLint)width, (GLint)height);  
102 -  
103 - glMatrixMode(GL_PROJECTION);  
104 -  
105 - // Set axes to div-scale and apply correction for exact pixelization  
106 - glLoadIdentity();  
107 - GLdouble pixelizationWidthCorrection = (width > 0) ? (GLdouble)width / (width - 1) : 1;  
108 - GLdouble pixelizationHeightCorrection = (height > 0) ? (GLdouble)height / (height - 1) : 1;  
109 - glOrtho(-(DIVS_TIME / 2.0) * pixelizationWidthCorrection, (DIVS_TIME / 2.0) * pixelizationWidthCorrection,  
110 - -(DIVS_VOLTAGE / 2.0) * pixelizationHeightCorrection, (DIVS_VOLTAGE / 2.0) * pixelizationHeightCorrection, -1.0,  
111 - 1.0);  
112 -  
113 - glMatrixMode(GL_MODELVIEW);  
114 -} 43 +GlScope::~GlScope() {}
115 44
116 void GlScope::mousePressEvent(QMouseEvent *event) { 45 void GlScope::mousePressEvent(QMouseEvent *event) {
117 if (!zoomed && event->button() == Qt::LeftButton) { 46 if (!zoomed && event->button() == Qt::LeftButton) {
@@ -126,9 +55,7 @@ void GlScope::mousePressEvent(QMouseEvent *event) { @@ -126,9 +55,7 @@ void GlScope::mousePressEvent(QMouseEvent *event) {
126 selectedMarker = marker; 55 selectedMarker = marker;
127 } 56 }
128 } 57 }
129 - if (selectedMarker != NO_MARKER) {  
130 - emit markerMoved(selectedMarker, position);  
131 - } 58 + if (selectedMarker != NO_MARKER) { emit markerMoved(selectedMarker, position); }
132 } 59 }
133 event->accept(); 60 event->accept();
134 } 61 }
@@ -139,12 +66,11 @@ void GlScope::mouseMoveEvent(QMouseEvent *event) { @@ -139,12 +66,11 @@ void GlScope::mouseMoveEvent(QMouseEvent *event) {
139 if (selectedMarker == NO_MARKER) { 66 if (selectedMarker == NO_MARKER) {
140 // User started draging outside the snap area of any marker: 67 // User started draging outside the snap area of any marker:
141 // move all markers to current position and select last marker in the array. 68 // move all markers to current position and select last marker in the array.
142 - for (int marker = 0; marker < MARKER_COUNT; ++marker) { 69 + for (unsigned marker = 0; marker < MARKER_COUNT; ++marker) {
143 emit markerMoved(marker, position); 70 emit markerMoved(marker, position);
144 selectedMarker = marker; 71 selectedMarker = marker;
145 } 72 }
146 - }  
147 - else if (selectedMarker < MARKER_COUNT) { 73 + } else if (selectedMarker < MARKER_COUNT) {
148 emit markerMoved(selectedMarker, position); 74 emit markerMoved(selectedMarker, position);
149 } 75 }
150 } 76 }
@@ -154,106 +80,339 @@ void GlScope::mouseMoveEvent(QMouseEvent *event) { @@ -154,106 +80,339 @@ void GlScope::mouseMoveEvent(QMouseEvent *event) {
154 void GlScope::mouseReleaseEvent(QMouseEvent *event) { 80 void GlScope::mouseReleaseEvent(QMouseEvent *event) {
155 if (!zoomed && event->button() == Qt::LeftButton) { 81 if (!zoomed && event->button() == Qt::LeftButton) {
156 double position = (double)(event->x() - width() / 2) * DIVS_TIME / (double)width(); 82 double position = (double)(event->x() - width() / 2) * DIVS_TIME / (double)width();
157 - if (selectedMarker != NO_MARKER && selectedMarker < MARKER_COUNT) {  
158 - emit markerMoved(selectedMarker, position);  
159 - } 83 + if (selectedMarker < MARKER_COUNT) { emit markerMoved(selectedMarker, position); }
160 selectedMarker = NO_MARKER; 84 selectedMarker = NO_MARKER;
161 } 85 }
162 event->accept(); 86 event->accept();
163 } 87 }
164 88
165 -void GlScope::drawGrid() {  
166 - glDisable(GL_POINT_SMOOTH);  
167 - glDisable(GL_LINE_SMOOTH); 89 +void GlScope::initializeGL() {
  90 + auto *gl = context()->versionFunctions<OPENGL_VER>();
  91 +
  92 + m_program = std::unique_ptr<QOpenGLShaderProgram>(new QOpenGLShaderProgram(context()));
  93 +
  94 + const char *vshaderES = R"(
  95 + #version 330
  96 + attribute highp vec3 vertex;
  97 + uniform mat4 matrix;
  98 + void main()
  99 + {
  100 + gl_Position = matrix * vec4(vertex, 1.0);
  101 + gl_PointSize = 1.0;
  102 + }
  103 + )";
  104 +
  105 + const char *vshaderCore = R"(
  106 + #version 330
  107 + in highp vec3 vertex;
  108 + uniform mat4 matrix;
  109 + void main()
  110 + {
  111 + gl_Position = matrix * vec4(vertex, 1.0);
  112 + gl_PointSize = 1.0;
  113 + }
  114 + )";
  115 + const char *fshaderCore = R"(
  116 + #version 330
  117 + uniform highp vec4 colour;
  118 + void main() { gl_FragColor = colour; }
  119 + )";
  120 +
  121 + qDebug() << "compile shaders";
  122 + // Compile vertex shader
  123 + bool coreShaders = QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile;
  124 + if (!m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, coreShaders ? vshaderCore : vshaderES) ||
  125 + !m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fshaderCore)) {
  126 + qWarning() << "Failed to compile OpenGL shader programs.\n" << m_program->log();
  127 + return;
  128 + }
168 129
169 - QColor color;  
170 - // Grid  
171 - color = view->screen.grid;  
172 - glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF());  
173 - glVertexPointer(2, GL_FLOAT, 0, &generator->grid(0).front());  
174 - glDrawArrays(GL_POINTS, 0, (GLsizei) generator->grid(0).size() / 2);  
175 - // Axes  
176 - color = view->screen.axes;  
177 - glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF());  
178 - glVertexPointer(2, GL_FLOAT, 0, &generator->grid(1).front());  
179 - glDrawArrays(GL_LINES, 0, (GLsizei) generator->grid(1).size() / 2);  
180 - // Border  
181 - color = view->screen.border;  
182 - glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF());  
183 - glVertexPointer(2, GL_FLOAT, 0, &generator->grid(2).front());  
184 - glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) generator->grid(2).size() / 2); 130 + // Link shader pipeline
  131 + if (!m_program->link() || !m_program->bind()) {
  132 + qWarning() << "Failed to link/bind OpenGL shader programs";
  133 + return;
  134 + }
  135 +
  136 + vertexLocation = m_program->attributeLocation("vertex");
  137 + matrixLocation = m_program->uniformLocation("matrix");
  138 + colorLocation = m_program->uniformLocation("colour");
  139 +
  140 + if (vertexLocation == -1 || colorLocation == -1 || matrixLocation == -1) {
  141 + qWarning() << "Failed to locate shader variable";
  142 + return;
  143 + }
  144 +
  145 + m_program->bind();
  146 +
  147 + gl->glDisable(GL_DEPTH_TEST);
  148 + gl->glEnable(GL_BLEND);
  149 + // Enable depth buffer
  150 + gl->glEnable(GL_DEPTH_TEST);
  151 +
  152 + // Enable back face culling
  153 + gl->glEnable(GL_CULL_FACE);
  154 + gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  155 +
  156 + gl->glPointSize(1);
  157 +
  158 + QColor bg = view->screen.background;
  159 + gl->glClearColor((GLfloat)bg.redF(), (GLfloat)bg.greenF(), (GLfloat)bg.blueF(), (GLfloat)bg.alphaF());
  160 +
  161 + generateGrid();
  162 +
  163 + {
  164 + m_vaoMarker.create();
  165 + QOpenGLVertexArrayObject::Binder b(&m_vaoMarker);
  166 + m_marker.create();
  167 + m_marker.bind();
  168 + m_marker.setUsagePattern(QOpenGLBuffer::StaticDraw);
  169 + m_marker.allocate(4 * sizeof(QVector3D));
  170 + m_program->enableAttributeArray(vertexLocation);
  171 + m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0);
  172 + }
  173 +
  174 + m_program->release();
185 } 175 }
186 176
187 -void GlScope::drawGraphDepth(Dso::ChannelMode mode, ChannelID channel, unsigned index) {  
188 - if (generator->channel(mode, channel, index).empty()) return;  
189 - QColor trColor;  
190 - if (mode == Dso::ChannelMode::Voltage)  
191 - trColor = view->screen.voltage[channel].darker(fadingFactor[index]);  
192 - else  
193 - trColor = view->screen.spectrum[channel].darker(fadingFactor[index]);  
194 - glColor4f((GLfloat)trColor.redF(), (GLfloat)trColor.greenF(), (GLfloat)trColor.blueF(), (GLfloat)trColor.alphaF());  
195 - glVertexPointer(2, GL_FLOAT, 0, &generator->channel(mode, channel, index).front());  
196 - glDrawArrays((view->interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0,  
197 - (GLsizei)generator->channel(mode, channel, index).size() / 2); 177 +void GlScope::showData(PPresult *data) {
  178 + if (!m_program || !m_program->isLinked()) return;
  179 + makeCurrent();
  180 + m_GraphHistory.resize(view->digitalPhosphorDraws());
  181 + m_GraphHistory[currentGraphInHistory].writeData(data, m_program.get(), vertexLocation);
  182 + currentGraphInHistory = (currentGraphInHistory + 1) % m_GraphHistory.size();
  183 + doneCurrent();
198 } 184 }
199 185
200 -void GlScope::drawGraph(unsigned digitalPhosphorDepth) { 186 +void GlScope::paintGL() {
  187 + if (!m_program->isLinked()) return;
  188 +
  189 + auto *gl = context()->versionFunctions<OPENGL_VER>();
  190 +
  191 + // Clear OpenGL buffer and configure settings
  192 + // TODO Don't clear if view->digitalPhosphorDraws()>1
  193 + gl->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  194 + gl->glLineWidth(1);
  195 +
  196 + m_program->bind();
  197 +
201 if (view->antialiasing) { 198 if (view->antialiasing) {
202 - glEnable(GL_POINT_SMOOTH);  
203 - glEnable(GL_LINE_SMOOTH);  
204 - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 199 + gl->glEnable(GL_POINT_SMOOTH);
  200 + gl->glEnable(GL_LINE_SMOOTH);
  201 + gl->glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
205 } 202 }
206 203
207 // Apply zoom settings via matrix transformation 204 // Apply zoom settings via matrix transformation
208 - if (this->zoomed) {  
209 - glPushMatrix();  
210 - glScalef(DIVS_TIME / (GLfloat)fabs(scope->horizontal.marker[1] - scope->horizontal.marker[0]), 1.0f,  
211 - 1.0f);  
212 - glTranslatef((GLfloat)-(scope->horizontal.marker[0] + scope->horizontal.marker[1]) / 2, 0.0f, 0.0f); 205 + if (zoomed) {
  206 + QMatrix4x4 m;
  207 + m.scale(QVector3D(DIVS_TIME / (GLfloat)fabs(scope->horizontal.marker[1] - scope->horizontal.marker[0]), 1.0f,
  208 + 1.0f));
  209 + m.translate((GLfloat) - (scope->horizontal.marker[0] + scope->horizontal.marker[1]) / 2, 0.0f, 0.0f);
  210 + m_program->setUniformValue(matrixLocation, pmvMatrix * m);
213 } 211 }
214 212
215 - // Values we need for the fading of the digital phosphor  
216 - if (fadingFactor.size() != digitalPhosphorDepth) {  
217 - fadingFactor.resize(digitalPhosphorDepth);  
218 - fadingFactor[0] = 100;  
219 - double fadingRatio = pow(10.0, 2.0 / digitalPhosphorDepth);  
220 - for (size_t index = 1; index < (size_t)digitalPhosphorDepth; ++index)  
221 - fadingFactor[index] = int(fadingFactor[index - 1] * fadingRatio); 213 + for (unsigned historyIndex = 0; historyIndex < m_GraphHistory.size(); ++historyIndex) {
  214 + unsigned graphID = (historyIndex + currentGraphInHistory) % m_GraphHistory.size();
  215 + Graph &graph = m_GraphHistory[graphID];
  216 + for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {
  217 + drawSpectrumChannelGraph(channel, graph, (int)historyIndex);
  218 + drawVoltageChannelGraph(channel, graph, (int)historyIndex);
  219 + }
222 } 220 }
223 221
224 - switch (scope->horizontal.format) {  
225 - case Dso::GraphFormat::TY:  
226 - // Real and virtual channels  
227 - for (Dso::ChannelMode mode: Dso::ChannelModeEnum) {  
228 - for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {  
229 - if (!channelUsed(mode, channel)) continue;  
230 -  
231 - // Draw graph for all available depths  
232 - for (unsigned index = digitalPhosphorDepth; index > 0; index--) {  
233 - drawGraphDepth(mode, channel, index-1);  
234 - }  
235 - } 222 + gl->glDisable(GL_POINT_SMOOTH);
  223 + gl->glDisable(GL_LINE_SMOOTH);
  224 +
  225 + if (zoomed) { m_program->setUniformValue(matrixLocation, pmvMatrix); }
  226 +
  227 + if (!this->zoomed) drawMarkers();
  228 +
  229 + drawGrid();
  230 + m_program->release();
  231 +}
  232 +
  233 +void GlScope::resizeGL(int width, int height) {
  234 + auto *gl = context()->versionFunctions<OPENGL_VER>();
  235 + gl->glViewport(0, 0, (GLint)width, (GLint)height);
  236 +
  237 + // Set axes to div-scale and apply correction for exact pixelization
  238 + float pixelizationWidthCorrection = (float)width / (width - 1);
  239 + float pixelizationHeightCorrection = (float)height / (height - 1);
  240 +
  241 + pmvMatrix.setToIdentity();
  242 + pmvMatrix.ortho(-(DIVS_TIME / 2.0f) * pixelizationWidthCorrection, (DIVS_TIME / 2.0f) * pixelizationWidthCorrection,
  243 + -(DIVS_VOLTAGE / 2.0f) * pixelizationHeightCorrection,
  244 + (DIVS_VOLTAGE / 2.0f) * pixelizationHeightCorrection, -1.0f, 1.0f);
  245 +
  246 + m_program->bind();
  247 + m_program->setUniformValue(matrixLocation, pmvMatrix);
  248 + m_program->release();
  249 +}
  250 +
  251 +void GlScope::drawGrid() {
  252 + auto *gl = context()->versionFunctions<OPENGL_VER>();
  253 + gl->glDisable(GL_POINT_SMOOTH);
  254 + gl->glDisable(GL_LINE_SMOOTH);
  255 + gl->glLineWidth(1);
  256 +
  257 + // Grid
  258 + m_vaoGrid[0].bind();
  259 + m_program->setUniformValue(colorLocation, view->screen.grid);
  260 + gl->glDrawArrays(GL_POINTS, 0, gridDrawCounts[0]);
  261 + m_vaoGrid[0].release();
  262 +
  263 + // Axes
  264 + m_vaoGrid[1].bind();
  265 + m_program->setUniformValue(colorLocation, view->screen.axes);
  266 + gl->glDrawArrays(GL_LINES, 0, gridDrawCounts[1]);
  267 + m_vaoGrid[1].release();
  268 +
  269 + // Border
  270 + m_vaoGrid[2].bind();
  271 + m_program->setUniformValue(colorLocation, view->screen.border);
  272 + gl->glDrawArrays(GL_LINE_LOOP, 0, gridDrawCounts[2]);
  273 + m_vaoGrid[2].release();
  274 +}
  275 +
  276 +void GlScope::generateGrid() {
  277 + gridDrawCounts[0] = 0;
  278 + gridDrawCounts[1] = 0;
  279 + gridDrawCounts[2] = 0;
  280 +
  281 + m_grid.create();
  282 + m_grid.bind();
  283 + m_grid.setUsagePattern(QOpenGLBuffer::StaticDraw);
  284 +
  285 + std::vector<QVector3D> vaGrid;
  286 +
  287 + { // Bind draw vertical lines
  288 + m_vaoGrid[0].create();
  289 + QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[0]);
  290 + m_grid.bind();
  291 + m_program->enableAttributeArray(vertexLocation);
  292 + m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, 0, 3, 0);
  293 + }
  294 +
  295 + // Draw vertical lines
  296 + for (int div = 1; div < DIVS_TIME / 2; ++div) {
  297 + for (int dot = 1; dot < DIVS_VOLTAGE / 2 * DIVS_SUB; ++dot) {
  298 + float dotPosition = (float)dot / DIVS_SUB;
  299 + gridDrawCounts[0] += 4;
  300 + vaGrid.push_back(QVector3D(-div, -dotPosition, 0));
  301 + vaGrid.push_back(QVector3D(-div, dotPosition, 0));
  302 + vaGrid.push_back(QVector3D(div, -dotPosition, 0));
  303 + vaGrid.push_back(QVector3D(div, dotPosition, 0));
236 } 304 }
237 - break;  
238 - case Dso::GraphFormat::XY:  
239 - const Dso::ChannelMode mode = Dso::ChannelMode::Voltage;  
240 - // Real and virtual channels  
241 - for (ChannelID channel = 0; channel < scope->voltage.size() - 1; channel += 2) {  
242 - if (!channelUsed(mode, channel)) continue;  
243 - for (unsigned index = digitalPhosphorDepth; index > 0; index--) {  
244 - drawGraphDepth(mode, channel, index-1);  
245 - } 305 + }
  306 + // Draw horizontal lines
  307 + for (int div = 1; div < DIVS_VOLTAGE / 2; ++div) {
  308 + for (int dot = 1; dot < DIVS_TIME / 2 * DIVS_SUB; ++dot) {
  309 + if (dot % DIVS_SUB == 0) continue; // Already done by vertical lines
  310 + float dotPosition = (float)dot / DIVS_SUB;
  311 + gridDrawCounts[0] += 4;
  312 + vaGrid.push_back(QVector3D(-dotPosition, -div, 0));
  313 + vaGrid.push_back(QVector3D(dotPosition, -div, 0));
  314 + vaGrid.push_back(QVector3D(-dotPosition, div, 0));
  315 + vaGrid.push_back(QVector3D(dotPosition, div, 0));
246 } 316 }
247 - break;  
248 } 317 }
249 318
250 - glDisable(GL_POINT_SMOOTH);  
251 - glDisable(GL_LINE_SMOOTH); 319 + { // Bind draw axes
  320 + m_vaoGrid[1].create();
  321 + QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[1]);
  322 + m_grid.bind();
  323 + m_program->enableAttributeArray(vertexLocation);
  324 + m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, int(vaGrid.size() * sizeof(QVector3D)), 3);
  325 + }
252 326
253 - if (zoomed) glPopMatrix(); 327 + // Axes
  328 + // Horizontal axis
  329 + gridDrawCounts[1] += 4;
  330 + vaGrid.push_back(QVector3D(-DIVS_TIME / 2, 0, 0));
  331 + vaGrid.push_back(QVector3D(DIVS_TIME / 2, 0, 0));
  332 + // Vertical axis
  333 + vaGrid.push_back(QVector3D(0, -DIVS_VOLTAGE / 2, 0));
  334 + vaGrid.push_back(QVector3D(0, DIVS_VOLTAGE / 2, 0));
  335 + // Subdiv lines on horizontal axis
  336 + for (int line = 1; line < DIVS_TIME / 2 * DIVS_SUB; ++line) {
  337 + float linePosition = (float)line / DIVS_SUB;
  338 + gridDrawCounts[1] += 4;
  339 + vaGrid.push_back(QVector3D(linePosition, -0.05f, 0));
  340 + vaGrid.push_back(QVector3D(linePosition, 0.05f, 0));
  341 + vaGrid.push_back(QVector3D(-linePosition, -0.05f, 0));
  342 + vaGrid.push_back(QVector3D(-linePosition, 0.05f, 0));
  343 + }
  344 + // Subdiv lines on vertical axis
  345 + for (int line = 1; line < DIVS_VOLTAGE / 2 * DIVS_SUB; ++line) {
  346 + float linePosition = (float)line / DIVS_SUB;
  347 + gridDrawCounts[1] += 4;
  348 + vaGrid.push_back(QVector3D(-0.05f, linePosition, 0));
  349 + vaGrid.push_back(QVector3D(0.05f, linePosition, 0));
  350 + vaGrid.push_back(QVector3D(-0.05f, -linePosition, 0));
  351 + vaGrid.push_back(QVector3D(0.05f, -linePosition, 0));
  352 + }
  353 +
  354 + {
  355 + m_vaoGrid[2].create();
  356 + QOpenGLVertexArrayObject::Binder b(&m_vaoGrid[2]);
  357 + m_grid.bind();
  358 + m_program->enableAttributeArray(vertexLocation);
  359 + m_program->setAttributeBuffer(vertexLocation, GL_FLOAT, int(vaGrid.size() * sizeof(QVector3D)), 3);
  360 + }
  361 +
  362 + // Border
  363 + gridDrawCounts[2] += 4;
  364 + vaGrid.push_back(QVector3D(-DIVS_TIME / 2, -DIVS_VOLTAGE / 2, 0));
  365 + vaGrid.push_back(QVector3D(DIVS_TIME / 2, -DIVS_VOLTAGE / 2, 0));
  366 + vaGrid.push_back(QVector3D(DIVS_TIME / 2, DIVS_VOLTAGE / 2, 0));
  367 + vaGrid.push_back(QVector3D(-DIVS_TIME / 2, DIVS_VOLTAGE / 2, 0));
  368 +
  369 + m_grid.allocate(&vaGrid[0], int(vaGrid.size() * sizeof(QVector3D)));
  370 + m_grid.release();
254 } 371 }
255 372
256 -bool GlScope::channelUsed(Dso::ChannelMode mode, ChannelID channel) {  
257 - return (mode == Dso::ChannelMode::Voltage) ? scope->voltage[channel].used  
258 - : scope->spectrum[channel].used; 373 +void GlScope::drawMarkers() {
  374 + auto *gl = context()->versionFunctions<OPENGL_VER>();
  375 + QColor trColor = view->screen.markers;
  376 + m_program->setUniformValue(colorLocation, trColor);
  377 +
  378 + m_vaoMarker.bind();
  379 +
  380 + for (unsigned marker = 0; marker < MARKER_COUNT; ++marker) {
  381 + if (!scope->horizontal.marker_visible[marker]) continue;
  382 + vaMarker[marker] = {QVector3D((GLfloat)scope->horizontal.marker[marker], -DIVS_VOLTAGE, 0.0f),
  383 + QVector3D((GLfloat)scope->horizontal.marker[marker], DIVS_VOLTAGE, 0.0f)};
  384 +
  385 + m_marker.bind();
  386 + auto ptr = m_marker.mapRange(0, sizeof(Line), QOpenGLBuffer::RangeInvalidateBuffer | QOpenGLBuffer::RangeWrite);
  387 + memcpy(ptr, &vaMarker[marker], sizeof(Line));
  388 + m_marker.unmap();
  389 +
  390 + gl->glLineWidth((marker == selectedMarker) ? 3 : 1);
  391 + gl->glDrawArrays(GL_LINES, 0, (GLsizei)2);
  392 + }
  393 +
  394 + m_vaoMarker.release();
  395 +}
  396 +
  397 +void GlScope::drawVoltageChannelGraph(ChannelID channel, Graph &graph, int historyIndex) {
  398 + if (!scope->voltage[channel].used) return;
  399 +
  400 + m_program->setUniformValue(colorLocation, view->screen.voltage[channel].darker(100 + 10 * historyIndex));
  401 +
  402 + Graph::VaoCount &v = graph.vaoVoltage[channel];
  403 +
  404 + QOpenGLVertexArrayObject::Binder b(v.first);
  405 + const GLenum dMode = (view->interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP;
  406 + context()->versionFunctions<OPENGL_VER>()->glDrawArrays(dMode, 0, v.second);
  407 +}
  408 +
  409 +void GlScope::drawSpectrumChannelGraph(ChannelID channel, Graph &graph, int historyIndex) {
  410 + if (!scope->spectrum[channel].used) return;
  411 +
  412 + m_program->setUniformValue(colorLocation, view->screen.spectrum[channel].darker(100 + 10 * historyIndex));
  413 + Graph::VaoCount &v = graph.vaoSpectrum[channel];
  414 +
  415 + QOpenGLVertexArrayObject::Binder b(v.first);
  416 + const GLenum dMode = (view->interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP;
  417 + context()->versionFunctions<OPENGL_VER>()->glDrawArrays(dMode, 0, v.second);
259 } 418 }
openhantek/src/glscope.h
@@ -2,36 +2,50 @@ @@ -2,36 +2,50 @@
2 2
3 #pragma once 3 #pragma once
4 4
5 -#include <QMetaObject>  
6 -#include <QtGlobal>  
7 -#include <array> 5 +#include <memory>
8 6
  7 +#include <QtGlobal>
  8 +#include <QOpenGLBuffer>
  9 +#include <QOpenGLFunctions>
  10 +#include <QOpenGLShaderProgram>
  11 +#include <QOpenGLVertexArrayObject>
9 #include <QOpenGLWidget> 12 #include <QOpenGLWidget>
  13 +
  14 +#include "glscopegraph.h"
10 #include "hantekdso/enums.h" 15 #include "hantekdso/enums.h"
11 -#include "hantekprotocol/definitions.h" 16 +#include "hantekprotocol/types.h"
12 17
13 -class GlGenerator;  
14 -struct DsoSettingsScope;  
15 struct DsoSettingsView; 18 struct DsoSettingsView;
  19 +struct DsoSettingsScope;
  20 +class PPresult;
16 21
17 /// \brief OpenGL accelerated widget that displays the oscilloscope screen. 22 /// \brief OpenGL accelerated widget that displays the oscilloscope screen.
18 class GlScope : public QOpenGLWidget { 23 class GlScope : public QOpenGLWidget {
19 Q_OBJECT 24 Q_OBJECT
20 25
21 public: 26 public:
22 - static GlScope* createNormal(DsoSettingsScope *scope, DsoSettingsView *view, const GlGenerator *generator, QWidget *parent = 0);  
23 - static GlScope* createZoomed(DsoSettingsScope *scope, DsoSettingsView *view, const GlGenerator *generator, QWidget *parent = 0); 27 + static GlScope *createNormal(DsoSettingsScope *scope, DsoSettingsView *view,
  28 + QWidget *parent = 0);
  29 + static GlScope *createZoomed(DsoSettingsScope *scope, DsoSettingsView *view,
  30 + QWidget *parent = 0);
  31 +
  32 + /**
  33 + * Show new post processed data
  34 + * @param data
  35 + */
  36 + void showData(PPresult* data);
24 37
25 protected: 38 protected:
26 /// \brief Initializes the scope widget. 39 /// \brief Initializes the scope widget.
27 /// \param settings The settings that should be used. 40 /// \param settings The settings that should be used.
28 /// \param parent The parent widget. 41 /// \param parent The parent widget.
29 - GlScope(DsoSettingsScope *scope, DsoSettingsView *view, const GlGenerator *generator, QWidget *parent = 0); 42 + GlScope(DsoSettingsScope *scope, DsoSettingsView *view, QWidget *parent = 0);
  43 + virtual ~GlScope();
30 44
31 /// \brief Initializes OpenGL output. 45 /// \brief Initializes OpenGL output.
32 void initializeGL() override; 46 void initializeGL() override;
33 47
34 - /// \brief Draw the graphs and the grid. 48 + /// \brief Draw the graphs, marker and the grid.
35 void paintGL() override; 49 void paintGL() override;
36 50
37 /// \brief Resize the widget. 51 /// \brief Resize the widget.
@@ -45,28 +59,47 @@ class GlScope : public QOpenGLWidget { @@ -45,28 +59,47 @@ class GlScope : public QOpenGLWidget {
45 59
46 /// \brief Draw the grid. 60 /// \brief Draw the grid.
47 void drawGrid(); 61 void drawGrid();
  62 + /// Draw vertical lines at marker positions
  63 + void drawMarkers();
48 64
49 - void drawGraphDepth(Dso::ChannelMode mode, ChannelID channel, unsigned index);  
50 - void drawGraph(unsigned digitalPhosphorDepth);  
51 -  
52 - /**  
53 - * @brief Return true if the given channel with the given mode is used  
54 - * @param mode The channel mode (spectrum/voltage)  
55 - * @param channel The channel  
56 - */  
57 - bool channelUsed(Dso::ChannelMode mode, ChannelID channel);  
58 - 65 + void drawVoltageChannelGraph(ChannelID channel, Graph &graph, int historyIndex);
  66 + void drawSpectrumChannelGraph(ChannelID channel, Graph &graph, int historyIndex);
59 signals: 67 signals:
60 - void markerMoved(int marker, double position); 68 + void markerMoved(unsigned marker, double position);
61 69
62 private: 70 private:
63 - const int NO_MARKER = -1; 71 + // User settings
64 DsoSettingsScope *scope; 72 DsoSettingsScope *scope;
65 DsoSettingsView *view; 73 DsoSettingsView *view;
66 - const GlGenerator *generator;  
67 - std::vector<int> fadingFactor;  
68 -  
69 - std::vector<GLfloat> vaMarker[2];  
70 bool zoomed = false; 74 bool zoomed = false;
71 - int selectedMarker = NO_MARKER; 75 +
  76 + // Marker
  77 + const unsigned NO_MARKER = UINT_MAX;
  78 + #pragma pack(push, 1)
  79 + struct Line {
  80 + QVector3D x;
  81 + QVector3D y;
  82 + };
  83 + #pragma pack(pop)
  84 + std::vector<Line> vaMarker;
  85 + unsigned selectedMarker = NO_MARKER;
  86 + QOpenGLBuffer m_marker;
  87 + QOpenGLVertexArrayObject m_vaoMarker;
  88 +
  89 + // Grid
  90 + QOpenGLBuffer m_grid;
  91 + QOpenGLVertexArrayObject m_vaoGrid[3];
  92 + GLsizei gridDrawCounts[3];
  93 + void generateGrid();
  94 +
  95 + // Graphs
  96 + std::vector<Graph> m_GraphHistory;
  97 + unsigned currentGraphInHistory = 0;
  98 +
  99 + // OpenGL shader, matrix, var-locations
  100 + std::unique_ptr<QOpenGLShaderProgram> m_program;
  101 + QMatrix4x4 pmvMatrix; ///< projection, view matrix
  102 + int colorLocation;
  103 + int vertexLocation;
  104 + int matrixLocation;
72 }; 105 };
openhantek/src/glscopegraph.cpp 0 → 100644
  1 +#include "glscopegraph.h"
  2 +#include <QDebug>
  3 +
  4 +Graph::Graph() : buffer(QOpenGLBuffer::VertexBuffer) {
  5 + buffer.create();
  6 + buffer.setUsagePattern(QOpenGLBuffer::DynamicDraw);
  7 +}
  8 +
  9 +void Graph::writeData(PPresult *data, QOpenGLShaderProgram *program, int vertexLocation) {
  10 + // Determine memory
  11 + int neededMemory = 0;
  12 + for (ChannelGraph &cg : data->vaChannelVoltage) neededMemory += cg.size() * sizeof(QVector3D);
  13 + for (ChannelGraph &cg : data->vaChannelSpectrum) neededMemory += cg.size() * sizeof(QVector3D);
  14 +
  15 + buffer.bind();
  16 +
  17 + // Allocate space if necessary
  18 + if (neededMemory > allocatedMem) {
  19 + buffer.allocate(neededMemory);
  20 + allocatedMem = neededMemory;
  21 + }
  22 +
  23 + qDebug() << data->data(0)->frequency;
  24 +
  25 + // Write data to buffer
  26 + int offset = 0;
  27 + vaoVoltage.resize(data->vaChannelVoltage.size());
  28 + vaoSpectrum.resize(data->vaChannelSpectrum.size());
  29 + for (ChannelID channel = 0; channel < vaoVoltage.size(); ++channel) {
  30 + VaoCount &v = vaoVoltage[channel];
  31 + VaoCount &s = vaoSpectrum[channel];
  32 + int dataSize;
  33 +
  34 + // Voltage channel
  35 + if (!v.first) v.first = new QOpenGLVertexArrayObject;
  36 + ChannelGraph &gVoltage = data->vaChannelVoltage[channel];
  37 + v.first->bind();
  38 + dataSize = int(gVoltage.size() * sizeof(QVector3D));
  39 + buffer.write(offset, gVoltage.data(), dataSize);
  40 + program->enableAttributeArray(vertexLocation);
  41 + program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, 0);
  42 + v.first->release();
  43 + v.second = (int)gVoltage.size();
  44 + offset += dataSize;
  45 +
  46 + // Spectrum channel
  47 + if (!s.first) s.first = new QOpenGLVertexArrayObject;
  48 + ChannelGraph &gSpectrum = data->vaChannelSpectrum[channel];
  49 + s.first->bind();
  50 + dataSize = int(gSpectrum.size() * sizeof(QVector3D));
  51 + buffer.write(offset, gSpectrum.data(), dataSize);
  52 + program->enableAttributeArray(vertexLocation);
  53 + program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, 0);
  54 + s.first->release();
  55 + s.second = (int)gSpectrum.size();
  56 + offset += dataSize;
  57 + }
  58 +
  59 + buffer.release();
  60 +}
  61 +
  62 +Graph::~Graph() {
  63 + for (auto &vao : vaoVoltage) {
  64 + vao.first->destroy();
  65 + delete vao.first;
  66 + }
  67 + for (auto &vao : vaoSpectrum) {
  68 + vao.first->destroy();
  69 + delete vao.first;
  70 + }
  71 + if (buffer.isCreated()) { buffer.destroy(); }
  72 +}
openhantek/src/glscopegraph.h 0 → 100644
  1 +#pragma once
  2 +
  3 +#include <memory>
  4 +
  5 +#include <QOpenGLBuffer>
  6 +#include <QOpenGLFunctions>
  7 +#include <QOpenGLShaderProgram>
  8 +#include <QOpenGLVertexArrayObject>
  9 +#include <QOpenGLWidget>
  10 +#include <QtGlobal>
  11 +
  12 +#include "post/ppresult.h"
  13 +
  14 +struct Graph {
  15 + Graph();
  16 + ~Graph();
  17 + void writeData(PPresult *data, QOpenGLShaderProgram* program, int vertexLocation);
  18 + typedef std::pair<QOpenGLVertexArrayObject*, GLsizei> VaoCount;
  19 +
  20 + public:
  21 + int allocatedMem = 0;
  22 + QOpenGLBuffer buffer;
  23 + std::vector<VaoCount> vaoVoltage;
  24 + std::vector<VaoCount> vaoSpectrum;
  25 +};
openhantek/src/main.cpp
1 // SPDX-License-Identifier: GPL-2.0+ 1 // SPDX-License-Identifier: GPL-2.0+
2 2
3 -#include <QDebug>  
4 #include <QApplication> 3 #include <QApplication>
  4 +#include <QDebug>
5 #include <QLibraryInfo> 5 #include <QLibraryInfo>
6 #include <QLocale> 6 #include <QLocale>
7 -#include <QTranslator>  
8 #include <QSurfaceFormat> 7 #include <QSurfaceFormat>
  8 +#include <QTranslator>
9 9
10 #include <iostream> 10 #include <iostream>
11 -#include <memory>  
12 #include <libusb-1.0/libusb.h> 11 #include <libusb-1.0/libusb.h>
  12 +#include <memory>
  13 +
  14 +#include "post/graphgenerator.h"
  15 +#include "post/mathchannelgenerator.h"
  16 +#include "post/postprocessing.h"
  17 +#include "post/spectrumgenerator.h"
13 18
14 -#include "analyse/dataanalyzer.h" 19 +#include "dsomodel.h"
15 #include "hantekdsocontrol.h" 20 #include "hantekdsocontrol.h"
16 #include "mainwindow.h" 21 #include "mainwindow.h"
  22 +#include "selectdevice/selectsupporteddevice.h"
17 #include "settings.h" 23 #include "settings.h"
18 #include "usb/usbdevice.h" 24 #include "usb/usbdevice.h"
19 -#include "dsomodel.h"  
20 -#include "selectdevice/selectsupporteddevice.h"  
21 #include "viewconstants.h" 25 #include "viewconstants.h"
22 26
23 #ifndef VERSION 27 #ifndef VERSION
@@ -26,12 +30,12 @@ @@ -26,12 +30,12 @@
26 30
27 using namespace Hantek; 31 using namespace Hantek;
28 32
29 -  
30 /// \brief Initialize the device with the current settings. 33 /// \brief Initialize the device with the current settings.
31 -void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope, const Dso::ControlSpecification* spec) { 34 +void applySettingsToDevice(HantekDsoControl *dsoControl, DsoSettingsScope *scope,
  35 + const Dso::ControlSpecification *spec) {
32 bool mathUsed = scope->anyUsed(spec->channels); 36 bool mathUsed = scope->anyUsed(spec->channels);
33 for (ChannelID channel = 0; channel < spec->channels; ++channel) { 37 for (ChannelID channel = 0; channel < spec->channels; ++channel) {
34 - dsoControl->setCoupling(channel, scope->coupling(channel,spec)); 38 + dsoControl->setCoupling(channel, scope->coupling(channel, spec));
35 dsoControl->setGain(channel, scope->gain(channel) * DIVS_VOLTAGE); 39 dsoControl->setGain(channel, scope->gain(channel) * DIVS_VOLTAGE);
36 dsoControl->setOffset(channel, (scope->voltage[channel].offset / DIVS_VOLTAGE) + 0.5); 40 dsoControl->setOffset(channel, (scope->voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
37 dsoControl->setTriggerLevel(channel, scope->voltage[channel].trigger); 41 dsoControl->setTriggerLevel(channel, scope->voltage[channel].trigger);
@@ -47,9 +51,9 @@ void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope @@ -47,9 +51,9 @@ void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope
47 dsoControl->setRecordLength(scope->horizontal.recordLength); 51 dsoControl->setRecordLength(scope->horizontal.recordLength);
48 else { 52 else {
49 auto recLenVec = dsoControl->getAvailableRecordLengths(); 53 auto recLenVec = dsoControl->getAvailableRecordLengths();
50 - ptrdiff_t index = std::distance(  
51 - recLenVec.begin(), std::find(recLenVec.begin(), recLenVec.end(), scope->horizontal.recordLength));  
52 - dsoControl->setRecordLength(index < 0 ? 1 : index); 54 + ptrdiff_t index = std::distance(recLenVec.begin(),
  55 + std::find(recLenVec.begin(), recLenVec.end(), scope->horizontal.recordLength));
  56 + dsoControl->setRecordLength(index < 0 ? 1 : (unsigned)index);
53 } 57 }
54 dsoControl->setTriggerMode(scope->trigger.mode); 58 dsoControl->setTriggerMode(scope->trigger.mode);
55 dsoControl->setPretriggerPosition(scope->trigger.position * scope->horizontal.timebase * DIVS_TIME); 59 dsoControl->setPretriggerPosition(scope->trigger.position * scope->horizontal.timebase * DIVS_TIME);
@@ -57,7 +61,6 @@ void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope @@ -57,7 +61,6 @@ void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope
57 dsoControl->setTriggerSource(scope->trigger.special, scope->trigger.source); 61 dsoControl->setTriggerSource(scope->trigger.special, scope->trigger.source);
58 } 62 }
59 63
60 -  
61 /// \brief Initialize resources and translations and show the main window. 64 /// \brief Initialize resources and translations and show the main window.
62 int main(int argc, char *argv[]) { 65 int main(int argc, char *argv[]) {
63 //////// Set application information //////// 66 //////// Set application information ////////
@@ -69,6 +72,7 @@ int main(int argc, char *argv[]) { @@ -69,6 +72,7 @@ int main(int argc, char *argv[]) {
69 QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true); 72 QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
70 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); 73 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
71 74
  75 + // Prefer full desktop OpenGL without fixed pipeline
72 QSurfaceFormat format; 76 QSurfaceFormat format;
73 format.setProfile(QSurfaceFormat::CoreProfile); 77 format.setProfile(QSurfaceFormat::CoreProfile);
74 QSurfaceFormat::setDefaultFormat(format); 78 QSurfaceFormat::setDefaultFormat(format);
@@ -111,27 +115,36 @@ int main(int argc, char *argv[]) { @@ -111,27 +115,36 @@ int main(int argc, char *argv[]) {
111 QObject::connect(device.get(), &USBDevice::deviceDisconnected, QCoreApplication::instance(), 115 QObject::connect(device.get(), &USBDevice::deviceDisconnected, QCoreApplication::instance(),
112 &QCoreApplication::quit); 116 &QCoreApplication::quit);
113 117
114 - //////// Create data analyser object ////////  
115 - QThread dataAnalyzerThread;  
116 - dataAnalyzerThread.setObjectName("dataAnalyzerThread");  
117 - DataAnalyzer dataAnalyser;  
118 - dataAnalyser.setSourceData(&dsoControl.getLastSamples());  
119 - dataAnalyser.moveToThread(&dataAnalyzerThread);  
120 - QObject::connect(&dsoControl, &HantekDsoControl::samplesAvailable, &dataAnalyser, &DataAnalyzer::samplesAvailable);  
121 -  
122 //////// Create settings object //////// 118 //////// Create settings object ////////
123 - DsoSettings settings(&device->getModel()->specification);  
124 - dataAnalyser.applySettings(&settings); 119 + auto settings = std::unique_ptr<DsoSettings>(new DsoSettings(&device->getModel()->specification));
  120 +
  121 + //////// Create post processing objects ////////
  122 + QThread postProcessingThread;
  123 + postProcessingThread.setObjectName("postProcessingThread");
  124 + PostProcessing postProcessing(settings->scope.countChannels());
  125 +
  126 + SpectrumGenerator spectrumGenerator(&settings->scope);
  127 + MathChannelGenerator mathchannelGenerator(&settings->scope, device->getModel()->specification.channels);
  128 + GraphGenerator graphGenerator(&settings->scope, device->getModel()->specification.isSoftwareTriggerDevice);
  129 +
  130 + postProcessing.registerProcessor(&mathchannelGenerator);
  131 + postProcessing.registerProcessor(&spectrumGenerator);
  132 + postProcessing.registerProcessor(&graphGenerator);
  133 +
  134 + postProcessing.moveToThread(&postProcessingThread);
  135 + QObject::connect(&dsoControl, &HantekDsoControl::samplesAvailable, &postProcessing, &PostProcessing::input);
125 136
126 //////// Create main window //////// 137 //////// Create main window ////////
127 - MainWindow *openHantekMainWindow = new MainWindow(&dsoControl, &dataAnalyser, &settings);  
128 - openHantekMainWindow->show(); 138 + MainWindow openHantekMainWindow(&dsoControl, settings.get());
  139 + QObject::connect(&postProcessing, &PostProcessing::processingFinished, &openHantekMainWindow,
  140 + &MainWindow::showNewData);
  141 + openHantekMainWindow.show();
129 142
130 - applySettingsToDevice(&dsoControl,&settings.scope,&device->getModel()->specification); 143 + applySettingsToDevice(&dsoControl, &settings->scope, &device->getModel()->specification);
131 144
132 //////// Start DSO thread and go into GUI main loop 145 //////// Start DSO thread and go into GUI main loop
133 dsoControl.startSampling(); 146 dsoControl.startSampling();
134 - dataAnalyzerThread.start(); 147 + postProcessingThread.start();
135 dsoControlThread.start(); 148 dsoControlThread.start();
136 int res = openHantekApplication.exec(); 149 int res = openHantekApplication.exec();
137 150
@@ -139,7 +152,7 @@ int main(int argc, char *argv[]) { @@ -139,7 +152,7 @@ int main(int argc, char *argv[]) {
139 dsoControlThread.quit(); 152 dsoControlThread.quit();
140 dsoControlThread.wait(10000); 153 dsoControlThread.wait(10000);
141 154
142 - dataAnalyzerThread.quit();  
143 - dataAnalyzerThread.wait(10000); 155 + postProcessingThread.quit();
  156 + postProcessingThread.wait(10000);
144 return res; 157 return res;
145 } 158 }
openhantek/src/mainwindow.cpp
@@ -6,15 +6,13 @@ @@ -6,15 +6,13 @@
6 #include "TriggerDock.h" 6 #include "TriggerDock.h"
7 #include "VoltageDock.h" 7 #include "VoltageDock.h"
8 #include "dockwindows.h" 8 #include "dockwindows.h"
9 -#include "exporter.h"  
10 9
11 #include "configdialog.h" 10 #include "configdialog.h"
12 -#include "analyse/dataanalyzer.h"  
13 #include "dockwindows.h" 11 #include "dockwindows.h"
  12 +#include "dsomodel.h"
14 #include "dsowidget.h" 13 #include "dsowidget.h"
15 #include "hantekdsocontrol.h" 14 #include "hantekdsocontrol.h"
16 #include "usb/usbdevice.h" 15 #include "usb/usbdevice.h"
17 -#include "dsomodel.h"  
18 #include "viewconstants.h" 16 #include "viewconstants.h"
19 17
20 #include "settings.h" 18 #include "settings.h"
@@ -23,12 +21,10 @@ @@ -23,12 +21,10 @@
23 #include <QLineEdit> 21 #include <QLineEdit>
24 #include <QMessageBox> 22 #include <QMessageBox>
25 23
26 -MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, DsoSettings *settings, QWidget *parent) :  
27 - QMainWindow(parent), ui(new Ui::MainWindow), dsoControl(dsoControl), dataAnalyzer(dataAnalyser), settings(settings)  
28 -{ 24 +MainWindow::MainWindow(HantekDsoControl *dsoControl, DsoSettings *settings, QWidget *parent)
  25 + : QMainWindow(parent), ui(new Ui::MainWindow), mSettings(settings) {
29 ui->setupUi(this); 26 ui->setupUi(this);
30 27
31 -  
32 // Window title 28 // Window title
33 setWindowIcon(QIcon(":openhantek.png")); 29 setWindowIcon(QIcon(":openhantek.png"));
34 setWindowTitle(tr("OpenHantek - Device %1").arg(QString::fromStdString(dsoControl->getDevice()->getModel()->name))); 30 setWindowTitle(tr("OpenHantek - Device %1").arg(QString::fromStdString(dsoControl->getDevice()->getModel()->name)));
@@ -38,40 +34,46 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -38,40 +34,46 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
38 setDockOptions(dockOptions() | QMainWindow::GroupedDragging); 34 setDockOptions(dockOptions() | QMainWindow::GroupedDragging);
39 #endif 35 #endif
40 36
  37 + DsoSettingsScope *scope = &(mSettings->scope);
  38 + const Dso::ControlSpecification *spec = &dsoControl->getDevice()->getModel()->specification;
  39 +
41 registerDockMetaTypes(); 40 registerDockMetaTypes();
42 - horizontalDock = new HorizontalDock(&settings->scope, this);  
43 - triggerDock = new TriggerDock(&settings->scope, settings->deviceSpecification, this);  
44 - spectrumDock = new SpectrumDock(&settings->scope, this);  
45 - voltageDock = new VoltageDock(&settings->scope, settings->deviceSpecification, this);  
46 41
47 - // Central oszilloscope widget  
48 - dsoWidget = new DsoWidget(&settings->scope, &settings->view, settings->deviceSpecification);  
49 - connect(dataAnalyzer, &DataAnalyzer::analyzed,  
50 - [this]() { dsoWidget->showNewData(this->dataAnalyzer->getNextResult()); });  
51 - setCentralWidget(dsoWidget); 42 + // Docking windows
  43 + HorizontalDock *horizontalDock;
  44 + TriggerDock *triggerDock;
  45 + SpectrumDock *spectrumDock;
  46 + VoltageDock *voltageDock;
  47 + horizontalDock = new HorizontalDock(scope, this);
  48 + triggerDock = new TriggerDock(scope, spec, this);
  49 + spectrumDock = new SpectrumDock(scope, this);
  50 + voltageDock = new VoltageDock(scope, spec, this);
52 51
53 addDockWidget(Qt::RightDockWidgetArea, horizontalDock); 52 addDockWidget(Qt::RightDockWidgetArea, horizontalDock);
54 addDockWidget(Qt::RightDockWidgetArea, triggerDock); 53 addDockWidget(Qt::RightDockWidgetArea, triggerDock);
55 addDockWidget(Qt::RightDockWidgetArea, voltageDock); 54 addDockWidget(Qt::RightDockWidgetArea, voltageDock);
56 addDockWidget(Qt::RightDockWidgetArea, spectrumDock); 55 addDockWidget(Qt::RightDockWidgetArea, spectrumDock);
57 56
58 - restoreGeometry(settings->mainWindowGeometry);  
59 - restoreState(settings->mainWindowState); 57 + restoreGeometry(mSettings->mainWindowGeometry);
  58 + restoreState(mSettings->mainWindowState);
  59 +
  60 + // Central oszilloscope widget
  61 + dsoWidget = new DsoWidget(&mSettings->scope, &mSettings->view, spec);
  62 + setCentralWidget(dsoWidget);
60 63
61 // Command field inside the status bar 64 // Command field inside the status bar
62 - QLineEdit* commandEdit = new QLineEdit(this); 65 + QLineEdit *commandEdit = new QLineEdit(this);
63 commandEdit->hide(); 66 commandEdit->hide();
64 67
65 statusBar()->addPermanentWidget(commandEdit, 1); 68 statusBar()->addPermanentWidget(commandEdit, 1);
66 69
67 connect(ui->actionManualCommand, &QAction::toggled, [this, commandEdit](bool checked) { 70 connect(ui->actionManualCommand, &QAction::toggled, [this, commandEdit](bool checked) {
68 commandEdit->setVisible(checked); 71 commandEdit->setVisible(checked);
69 - if (checked)  
70 - commandEdit->setFocus(); 72 + if (checked) commandEdit->setFocus();
71 }); 73 });
72 74
73 - connect(commandEdit, &QLineEdit::returnPressed, [this, commandEdit]() {  
74 - Dso::ErrorCode errorCode = this->dsoControl->stringCommand(commandEdit->text()); 75 + connect(commandEdit, &QLineEdit::returnPressed, [this, commandEdit, dsoControl]() {
  76 + Dso::ErrorCode errorCode = dsoControl->stringCommand(commandEdit->text());
75 commandEdit->clear(); 77 commandEdit->clear();
76 this->ui->actionManualCommand->setChecked(false); 78 this->ui->actionManualCommand->setChecked(false);
77 if (errorCode != Dso::ErrorCode::NONE) statusBar()->showMessage(tr("Invalid command"), 3000); 79 if (errorCode != Dso::ErrorCode::NONE) statusBar()->showMessage(tr("Invalid command"), 3000);
@@ -81,38 +83,38 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -81,38 +83,38 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
81 connect(dsoControl, &HantekDsoControl::statusMessage, statusBar(), &QStatusBar::showMessage); 83 connect(dsoControl, &HantekDsoControl::statusMessage, statusBar(), &QStatusBar::showMessage);
82 84
83 // Connect signals to DSO controller and widget 85 // Connect signals to DSO controller and widget
84 - connect(horizontalDock, &HorizontalDock::samplerateChanged, [this]() {  
85 - this->dsoControl->setSamplerate(this->settings->scope.horizontal.samplerate);  
86 - this->dsoWidget->updateSamplerate(this->settings->scope.horizontal.samplerate); 86 + connect(horizontalDock, &HorizontalDock::samplerateChanged, [dsoControl, this]() {
  87 + dsoControl->setSamplerate(mSettings->scope.horizontal.samplerate);
  88 + this->dsoWidget->updateSamplerate(mSettings->scope.horizontal.samplerate);
87 }); 89 });
88 - connect(horizontalDock, &HorizontalDock::timebaseChanged, [this](){  
89 - this->dsoControl->setRecordTime(this->settings->scope.horizontal.timebase * DIVS_TIME);  
90 - this->dsoWidget->updateTimebase(this->settings->scope.horizontal.timebase); 90 + connect(horizontalDock, &HorizontalDock::timebaseChanged, [dsoControl, this]() {
  91 + dsoControl->setRecordTime(mSettings->scope.horizontal.timebase * DIVS_TIME);
  92 + this->dsoWidget->updateTimebase(mSettings->scope.horizontal.timebase);
91 }); 93 });
92 connect(horizontalDock, &HorizontalDock::frequencybaseChanged, dsoWidget, &DsoWidget::updateFrequencybase); 94 connect(horizontalDock, &HorizontalDock::frequencybaseChanged, dsoWidget, &DsoWidget::updateFrequencybase);
93 - connect(horizontalDock, &HorizontalDock::recordLengthChanged, [this](unsigned long recordLength) {  
94 - this->dsoControl->setRecordLength(recordLength);  
95 - });  
96 -  
97 - connect(dsoControl, &HantekDsoControl::recordTimeChanged, [this](double duration) {  
98 - if (this->settings->scope.horizontal.samplerateSource == DsoSettingsScopeHorizontal::Samplerrate &&  
99 - this->settings->scope.horizontal.recordLength != UINT_MAX) {  
100 - // The samplerate was set, let's adapt the timebase accordingly  
101 - this->settings->scope.horizontal.timebase = horizontalDock->setTimebase(duration / DIVS_TIME);  
102 - }  
103 -  
104 - // The trigger position should be kept at the same place but the timebase has  
105 - // changed  
106 - this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase *  
107 - DIVS_TIME);  
108 -  
109 - dsoWidget->updateTimebase(this->settings->scope.horizontal.timebase);  
110 - });  
111 - connect(dsoControl, &HantekDsoControl::samplerateChanged, [this](double samplerate) {  
112 - if (this->settings->scope.horizontal.samplerateSource == DsoSettingsScopeHorizontal::Duration &&  
113 - this->settings->scope.horizontal.recordLength != UINT_MAX) { 95 + connect(horizontalDock, &HorizontalDock::recordLengthChanged,
  96 + [dsoControl](unsigned long recordLength) { dsoControl->setRecordLength(recordLength); });
  97 +
  98 + connect(dsoControl, &HantekDsoControl::recordTimeChanged,
  99 + [this, settings, horizontalDock, dsoControl](double duration) {
  100 + if (settings->scope.horizontal.samplerateSource == DsoSettingsScopeHorizontal::Samplerrate &&
  101 + settings->scope.horizontal.recordLength != UINT_MAX) {
  102 + // The samplerate was set, let's adapt the timebase accordingly
  103 + settings->scope.horizontal.timebase = horizontalDock->setTimebase(duration / DIVS_TIME);
  104 + }
  105 +
  106 + // The trigger position should be kept at the same place but the timebase has
  107 + // changed
  108 + dsoControl->setPretriggerPosition(settings->scope.trigger.position *
  109 + settings->scope.horizontal.timebase * DIVS_TIME);
  110 +
  111 + this->dsoWidget->updateTimebase(settings->scope.horizontal.timebase);
  112 + });
  113 + connect(dsoControl, &HantekDsoControl::samplerateChanged, [this, horizontalDock](double samplerate) {
  114 + if (mSettings->scope.horizontal.samplerateSource == DsoSettingsScopeHorizontal::Duration &&
  115 + mSettings->scope.horizontal.recordLength != UINT_MAX) {
114 // The timebase was set, let's adapt the samplerate accordingly 116 // The timebase was set, let's adapt the samplerate accordingly
115 - this->settings->scope.horizontal.samplerate = samplerate; 117 + mSettings->scope.horizontal.samplerate = samplerate;
116 horizontalDock->setSamplerate(samplerate); 118 horizontalDock->setSamplerate(samplerate);
117 dsoWidget->updateSamplerate(samplerate); 119 dsoWidget->updateSamplerate(samplerate);
118 } 120 }
@@ -127,19 +129,18 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -127,19 +129,18 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
127 connect(dsoWidget, &DsoWidget::triggerPositionChanged, dsoControl, &HantekDsoControl::setPretriggerPosition); 129 connect(dsoWidget, &DsoWidget::triggerPositionChanged, dsoControl, &HantekDsoControl::setPretriggerPosition);
128 connect(dsoWidget, &DsoWidget::triggerLevelChanged, dsoControl, &HantekDsoControl::setTriggerLevel); 130 connect(dsoWidget, &DsoWidget::triggerLevelChanged, dsoControl, &HantekDsoControl::setTriggerLevel);
129 131
130 - auto usedChanged = [this](ChannelID channel, bool used) {  
131 - if (channel >= (unsigned int)this->settings->scope.voltage.size()) return; 132 + auto usedChanged = [this, dsoControl, spec](ChannelID channel, bool used) {
  133 + if (channel >= (unsigned int)mSettings->scope.voltage.size()) return;
132 134
133 - bool mathUsed = this->settings->scope.anyUsed(this->settings->deviceSpecification->channels); 135 + bool mathUsed = mSettings->scope.anyUsed(spec->channels);
134 136
135 // Normal channel, check if voltage/spectrum or math channel is used 137 // Normal channel, check if voltage/spectrum or math channel is used
136 - if (channel < this->settings->deviceSpecification->channels)  
137 - this->dsoControl->setChannelUsed(  
138 - channel, mathUsed | this->settings->scope.anyUsed(channel)); 138 + if (channel < spec->channels)
  139 + dsoControl->setChannelUsed(channel, mathUsed | mSettings->scope.anyUsed(channel));
139 // Math channel, update all channels 140 // Math channel, update all channels
140 - else if (channel == this->settings->deviceSpecification->channels) {  
141 - for (ChannelID c = 0; c < this->settings->deviceSpecification->channels; ++c)  
142 - this->dsoControl->setChannelUsed(c, mathUsed | this->settings->scope.anyUsed(c)); 141 + else if (channel == spec->channels) {
  142 + for (ChannelID c = 0; c < spec->channels; ++c)
  143 + dsoControl->setChannelUsed(c, mathUsed | mSettings->scope.anyUsed(c));
143 } 144 }
144 }; 145 };
145 connect(voltageDock, &VoltageDock::usedChanged, usedChanged); 146 connect(voltageDock, &VoltageDock::usedChanged, usedChanged);
@@ -148,15 +149,15 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -148,15 +149,15 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
148 connect(voltageDock, &VoltageDock::couplingChanged, dsoControl, &HantekDsoControl::setCoupling); 149 connect(voltageDock, &VoltageDock::couplingChanged, dsoControl, &HantekDsoControl::setCoupling);
149 connect(voltageDock, &VoltageDock::couplingChanged, dsoWidget, &DsoWidget::updateVoltageCoupling); 150 connect(voltageDock, &VoltageDock::couplingChanged, dsoWidget, &DsoWidget::updateVoltageCoupling);
150 connect(voltageDock, &VoltageDock::modeChanged, dsoWidget, &DsoWidget::updateMathMode); 151 connect(voltageDock, &VoltageDock::modeChanged, dsoWidget, &DsoWidget::updateMathMode);
151 - connect(voltageDock, &VoltageDock::gainChanged, [this](ChannelID channel, double gain) {  
152 - if (channel >= this->settings->deviceSpecification->channels) return; 152 + connect(voltageDock, &VoltageDock::gainChanged, [this, dsoControl, spec](ChannelID channel, double gain) {
  153 + if (channel >= spec->channels) return;
153 154
154 - this->dsoControl->setGain(channel, this->settings->scope.gain(channel) * DIVS_VOLTAGE); 155 + dsoControl->setGain(channel, mSettings->scope.gain(channel) * DIVS_VOLTAGE);
155 }); 156 });
156 connect(voltageDock, &VoltageDock::gainChanged, dsoWidget, &DsoWidget::updateVoltageGain); 157 connect(voltageDock, &VoltageDock::gainChanged, dsoWidget, &DsoWidget::updateVoltageGain);
157 - connect(dsoWidget, &DsoWidget::offsetChanged, [this](ChannelID channel) {  
158 - if (channel >= this->settings->deviceSpecification->channels) return;  
159 - this->dsoControl->setOffset(channel, (this->settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5); 158 + connect(dsoWidget, &DsoWidget::offsetChanged, [this, dsoControl, spec](ChannelID channel) {
  159 + if (channel >= spec->channels) return;
  160 + dsoControl->setOffset(channel, (mSettings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
160 }); 161 });
161 162
162 connect(voltageDock, &VoltageDock::usedChanged, dsoWidget, &DsoWidget::updateVoltageUsed); 163 connect(voltageDock, &VoltageDock::usedChanged, dsoWidget, &DsoWidget::updateVoltageUsed);
@@ -164,21 +165,21 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -164,21 +165,21 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
164 connect(spectrumDock, &SpectrumDock::magnitudeChanged, dsoWidget, &DsoWidget::updateSpectrumMagnitude); 165 connect(spectrumDock, &SpectrumDock::magnitudeChanged, dsoWidget, &DsoWidget::updateSpectrumMagnitude);
165 166
166 // Started/stopped signals from oscilloscope 167 // Started/stopped signals from oscilloscope
167 - connect(dsoControl, &HantekDsoControl::samplingStarted, [this]() { 168 + connect(dsoControl, &HantekDsoControl::samplingStarted, [this, dsoControl]() {
168 this->ui->actionSampling->setText(tr("&Stop")); 169 this->ui->actionSampling->setText(tr("&Stop"));
169 this->ui->actionSampling->setIcon(QIcon(":actions/stop.png")); 170 this->ui->actionSampling->setIcon(QIcon(":actions/stop.png"));
170 this->ui->actionSampling->setStatusTip(tr("Stop the oscilloscope")); 171 this->ui->actionSampling->setStatusTip(tr("Stop the oscilloscope"));
171 172
172 - disconnect(this->ui->actionSampling, &QAction::triggered, this->dsoControl, &HantekDsoControl::startSampling);  
173 - connect(this->ui->actionSampling, &QAction::triggered, this->dsoControl, &HantekDsoControl::stopSampling); 173 + disconnect(this->ui->actionSampling, &QAction::triggered, dsoControl, &HantekDsoControl::startSampling);
  174 + connect(this->ui->actionSampling, &QAction::triggered, dsoControl, &HantekDsoControl::stopSampling);
174 }); 175 });
175 - connect(dsoControl, &HantekDsoControl::samplingStopped, [this]() { 176 + connect(dsoControl, &HantekDsoControl::samplingStopped, [this, dsoControl]() {
176 this->ui->actionSampling->setText(tr("&Start")); 177 this->ui->actionSampling->setText(tr("&Start"));
177 this->ui->actionSampling->setIcon(QIcon(":actions/start.png")); 178 this->ui->actionSampling->setIcon(QIcon(":actions/start.png"));
178 this->ui->actionSampling->setStatusTip(tr("Start the oscilloscope")); 179 this->ui->actionSampling->setStatusTip(tr("Start the oscilloscope"));
179 180
180 - disconnect(this->ui->actionSampling, &QAction::triggered, this->dsoControl, &HantekDsoControl::stopSampling);  
181 - connect(this->ui->actionSampling, &QAction::triggered, this->dsoControl, &HantekDsoControl::startSampling); 181 + disconnect(this->ui->actionSampling, &QAction::triggered, dsoControl, &HantekDsoControl::stopSampling);
  182 + connect(this->ui->actionSampling, &QAction::triggered, dsoControl, &HantekDsoControl::startSampling);
182 }); 183 });
183 184
184 connect(dsoControl, &HantekDsoControl::availableRecordLengthsChanged, horizontalDock, 185 connect(dsoControl, &HantekDsoControl::availableRecordLengthsChanged, horizontalDock,
@@ -190,67 +191,67 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -190,67 +191,67 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
190 connect(ui->actionOpen, &QAction::triggered, [this]() { 191 connect(ui->actionOpen, &QAction::triggered, [this]() {
191 QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), "", tr("Settings (*.ini)")); 192 QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), "", tr("Settings (*.ini)"));
192 if (!fileName.isEmpty()) { 193 if (!fileName.isEmpty()) {
193 - if (this->settings->setFilename(fileName)) {  
194 - this->settings->load();  
195 - } 194 + if (mSettings->setFilename(fileName)) { mSettings->load(); }
196 } 195 }
197 }); 196 });
198 197
199 connect(ui->actionSave, &QAction::triggered, [this]() { 198 connect(ui->actionSave, &QAction::triggered, [this]() {
200 - this->settings->mainWindowGeometry = saveGeometry();  
201 - this->settings->mainWindowState = saveState();  
202 - this->settings->save(); 199 + mSettings->mainWindowGeometry = saveGeometry();
  200 + mSettings->mainWindowState = saveState();
  201 + mSettings->save();
203 }); 202 });
204 203
205 connect(ui->actionSave_as, &QAction::triggered, [this]() { 204 connect(ui->actionSave_as, &QAction::triggered, [this]() {
206 QString fileName = QFileDialog::getSaveFileName(this, tr("Save settings"), "", tr("Settings (*.ini)")); 205 QString fileName = QFileDialog::getSaveFileName(this, tr("Save settings"), "", tr("Settings (*.ini)"));
207 if (fileName.isEmpty()) return; 206 if (fileName.isEmpty()) return;
208 - this->settings->mainWindowGeometry = saveGeometry();  
209 - this->settings->mainWindowState = saveState();  
210 - this->settings->setFilename(fileName);  
211 - this->settings->save(); 207 + mSettings->mainWindowGeometry = saveGeometry();
  208 + mSettings->mainWindowState = saveState();
  209 + mSettings->setFilename(fileName);
  210 + mSettings->save();
212 }); 211 });
213 212
214 - connect(ui->actionPrint, &QAction::triggered, [this]() {  
215 - this->dsoWidget->setExporterForNextFrame(std::unique_ptr<Exporter>(Exporter::createPrintExporter(this->settings))); 213 + connect(ui->actionPrint, &QAction::triggered, [this, spec]() {
  214 + this->dsoWidget->setExporterForNextFrame(
  215 + std::unique_ptr<Exporter>(Exporter::createPrintExporter(spec, this->mSettings)));
216 }); 216 });
217 217
218 - connect(ui->actionExport, &QAction::triggered, [this]() {  
219 - this->dsoWidget->setExporterForNextFrame(std::unique_ptr<Exporter>(Exporter::createSaveToFileExporter(this->settings))); 218 + connect(ui->actionExport, &QAction::triggered, [this, spec]() {
  219 + this->dsoWidget->setExporterForNextFrame(
  220 + std::unique_ptr<Exporter>(Exporter::createSaveToFileExporter(spec, this->mSettings)));
220 }); 221 });
221 222
222 connect(ui->actionExit, &QAction::triggered, this, &QWidget::close); 223 connect(ui->actionExit, &QAction::triggered, this, &QWidget::close);
223 224
224 connect(ui->actionSettings, &QAction::triggered, [this]() { 225 connect(ui->actionSettings, &QAction::triggered, [this]() {
225 - this->settings->mainWindowGeometry = saveGeometry();  
226 - this->settings->mainWindowState = saveState(); 226 + mSettings->mainWindowGeometry = saveGeometry();
  227 + mSettings->mainWindowState = saveState();
227 228
228 - DsoConfigDialog* configDialog = new DsoConfigDialog(this->settings, this); 229 + DsoConfigDialog *configDialog = new DsoConfigDialog(this->mSettings, this);
229 configDialog->setModal(true); 230 configDialog->setModal(true);
230 configDialog->show(); 231 configDialog->show();
231 }); 232 });
232 233
233 connect(this->ui->actionDigital_phosphor, &QAction::toggled, [this](bool enabled) { 234 connect(this->ui->actionDigital_phosphor, &QAction::toggled, [this](bool enabled) {
234 - this->settings->view.digitalPhosphor = enabled; 235 + mSettings->view.digitalPhosphor = enabled;
235 236
236 - if (this->settings->view.digitalPhosphor) 237 + if (mSettings->view.digitalPhosphor)
237 this->ui->actionDigital_phosphor->setStatusTip(tr("Disable fading of previous graphs")); 238 this->ui->actionDigital_phosphor->setStatusTip(tr("Disable fading of previous graphs"));
238 else 239 else
239 this->ui->actionDigital_phosphor->setStatusTip(tr("Enable fading of previous graphs")); 240 this->ui->actionDigital_phosphor->setStatusTip(tr("Enable fading of previous graphs"));
240 }); 241 });
241 - this->ui->actionDigital_phosphor->setChecked(settings->view.digitalPhosphor); 242 + this->ui->actionDigital_phosphor->setChecked(mSettings->view.digitalPhosphor);
242 243
243 connect(ui->actionZoom, &QAction::toggled, [this](bool enabled) { 244 connect(ui->actionZoom, &QAction::toggled, [this](bool enabled) {
244 - this->settings->view.zoom = enabled; 245 + mSettings->view.zoom = enabled;
245 246
246 - if (this->settings->view.zoom) 247 + if (mSettings->view.zoom)
247 this->ui->actionZoom->setStatusTip(tr("Hide magnified scope")); 248 this->ui->actionZoom->setStatusTip(tr("Hide magnified scope"));
248 else 249 else
249 this->ui->actionZoom->setStatusTip(tr("Show magnified scope")); 250 this->ui->actionZoom->setStatusTip(tr("Show magnified scope"));
250 251
251 this->dsoWidget->updateZoom(enabled); 252 this->dsoWidget->updateZoom(enabled);
252 }); 253 });
253 - ui->actionZoom->setChecked(settings->view.zoom); 254 + ui->actionZoom->setChecked(mSettings->view.zoom);
254 255
255 connect(ui->actionAbout, &QAction::triggered, [this]() { 256 connect(ui->actionAbout, &QAction::triggered, [this]() {
256 QMessageBox::about( 257 QMessageBox::about(
@@ -263,29 +264,28 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, @@ -263,29 +264,28 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
263 264
264 }); 265 });
265 266
266 - if (settings->scope.horizontal.samplerateSource == DsoSettingsScopeHorizontal::Samplerrate)  
267 - dsoWidget->updateSamplerate(settings->scope.horizontal.samplerate); 267 + if (mSettings->scope.horizontal.samplerateSource == DsoSettingsScopeHorizontal::Samplerrate)
  268 + dsoWidget->updateSamplerate(mSettings->scope.horizontal.samplerate);
268 else 269 else
269 - dsoWidget->updateTimebase(settings->scope.horizontal.timebase); 270 + dsoWidget->updateTimebase(mSettings->scope.horizontal.timebase);
270 271
271 - for (ChannelID channel = 0; channel < settings->deviceSpecification->channels; ++channel) {  
272 - this->dsoWidget->updateVoltageUsed(channel, settings->scope.voltage[channel].used);  
273 - this->dsoWidget->updateSpectrumUsed(channel, settings->scope.spectrum[channel].used); 272 + for (ChannelID channel = 0; channel < spec->channels; ++channel) {
  273 + this->dsoWidget->updateVoltageUsed(channel, mSettings->scope.voltage[channel].used);
  274 + this->dsoWidget->updateSpectrumUsed(channel, mSettings->scope.spectrum[channel].used);
274 } 275 }
275 } 276 }
276 277
277 -MainWindow::~MainWindow()  
278 -{  
279 - delete ui;  
280 -} 278 +MainWindow::~MainWindow() { delete ui; }
  279 +
  280 +void MainWindow::showNewData(std::shared_ptr<PPresult> data) { dsoWidget->showNew(data); }
281 281
282 /// \brief Save the settings before exiting. 282 /// \brief Save the settings before exiting.
283 /// \param event The close event that should be handled. 283 /// \param event The close event that should be handled.
284 void MainWindow::closeEvent(QCloseEvent *event) { 284 void MainWindow::closeEvent(QCloseEvent *event) {
285 - if (settings->options.alwaysSave) {  
286 - settings->mainWindowGeometry = saveGeometry();  
287 - settings->mainWindowState = saveState();  
288 - settings->save(); 285 + if (mSettings->alwaysSave) {
  286 + mSettings->mainWindowGeometry = saveGeometry();
  287 + mSettings->mainWindowState = saveState();
  288 + mSettings->save();
289 } 289 }
290 290
291 QMainWindow::closeEvent(event); 291 QMainWindow::closeEvent(event);
openhantek/src/mainwindow.h
1 #pragma once 1 #pragma once
2 #include <QMainWindow> 2 #include <QMainWindow>
  3 +#include <memory>
  4 +#include "post/ppresult.h"
3 5
4 -class DataAnalyzer; 6 +class SpectrumGenerator;
5 class HantekDsoControl; 7 class HantekDsoControl;
6 class DsoSettings; 8 class DsoSettings;
7 class DsoWidget; 9 class DsoWidget;
@@ -22,27 +24,19 @@ class MainWindow : public QMainWindow @@ -22,27 +24,19 @@ class MainWindow : public QMainWindow
22 Q_OBJECT 24 Q_OBJECT
23 25
24 public: 26 public:
25 - explicit MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser, DsoSettings *settings, QWidget *parent = 0); 27 + explicit MainWindow(HantekDsoControl *dsoControl, DsoSettings *mSettings, QWidget *parent = 0);
26 ~MainWindow(); 28 ~MainWindow();
  29 +public slots:
  30 + void showNewData(std::shared_ptr<PPresult> data);
27 31
28 protected: 32 protected:
29 void closeEvent(QCloseEvent *event) override; 33 void closeEvent(QCloseEvent *event) override;
30 private: 34 private:
31 Ui::MainWindow *ui; 35 Ui::MainWindow *ui;
32 36
33 - // Docking windows  
34 - HorizontalDock *horizontalDock;  
35 - TriggerDock *triggerDock;  
36 - SpectrumDock *spectrumDock;  
37 - VoltageDock *voltageDock;  
38 -  
39 // Central widgets 37 // Central widgets
40 DsoWidget *dsoWidget; 38 DsoWidget *dsoWidget;
41 39
42 - // Data handling classes  
43 - HantekDsoControl *dsoControl;  
44 - DataAnalyzer *dataAnalyzer;  
45 -  
46 // Settings used for the whole program 40 // Settings used for the whole program
47 - DsoSettings *settings; 41 + DsoSettings *mSettings;
48 }; 42 };
openhantek/src/utils/dsoStrings.h
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 #pragma once 3 #pragma once
4 #include <QString> 4 #include <QString>
5 -#include "analyse/enums.h" 5 +#include "post/enums.h"
6 #include "hantekdso/enums.h" 6 #include "hantekdso/enums.h"
7 7
8 #define MARKER_COUNT 2 ///< Number of markers 8 #define MARKER_COUNT 2 ///< Number of markers