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 10  
11 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 19 #include "glscope.h"
16 20 #include "scopesettings.h"
  21 +#include "viewconstants.h"
17 22 #include "viewsettings.h"
18   -#include "utils/dsoStrings.h"
19   -#include "utils/printutils.h"
20 23 #include "widgets/levelslider.h"
21   -#include "viewconstants.h"
22   -#include "analyse/dataanalyzerresult.h"
23 24  
24 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 32 // Palette for this widget
31 33 QPalette palette;
... ... @@ -37,6 +39,7 @@ DsoWidget::DsoWidget(DsoSettingsScope *scope, DsoSettingsView *view, const Dso::
37 39  
38 40 connect(mainScope, &GlScope::markerMoved, [this] (int marker, double position) {
39 41 double step = this->mainSliders.markerSlider->step(marker);
  42 +
40 43 this->scope->horizontal.marker[marker] =
41 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 65 swTriggerStatus->setText(tr("TR"));
63 66 swTriggerStatus->setAlignment(Qt::AlignCenter);
64 67 swTriggerStatus->setAutoFillBackground(true);
  68 + swTriggerStatus->setVisible(false);
65 69 settingsLayout = new QHBoxLayout();
66 70 settingsLayout->addWidget(swTriggerStatus);
67 71 settingsLayout->addWidget(settingsTriggerLabel);
... ... @@ -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 267 this->exportNextFrame = std::move(exporter);
271 268 }
272 269  
... ... @@ -317,9 +314,12 @@ void DsoWidget::updateMarkerDetails() {
317 314 markerFrequencybaseLabel->setText(
318 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 324 markerTimeLabel->setText(valueToString(time, UNIT_SECONDS, 4));
325 325 markerFrequencyLabel->setText(valueToString(1.0 / time, UNIT_HERTZ, 4));
... ... @@ -330,8 +330,8 @@ void DsoWidget::updateSpectrumDetails(ChannelID channel) {
330 330 setMeasurementVisible(channel);
331 331  
332 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 335 else
336 336 measurementMagnitudeLabel[channel]->setText(QString());
337 337 }
... ... @@ -346,8 +346,7 @@ void DsoWidget::updateTriggerDetails() {
346 346 QString pretriggerString = tr("%L1%").arg((int)(scope->trigger.position * 100 + 0.5));
347 347 settingsTriggerLabel->setText(tr("%1 %2 %3 %4")
348 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 351 /// \todo This won't work for special trigger sources
353 352 }
... ... @@ -359,8 +358,7 @@ void DsoWidget::updateVoltageDetails(ChannelID channel) {
359 358 setMeasurementVisible(channel);
360 359  
361 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 362 else
365 363 measurementGainLabel[channel]->setText(QString());
366 364 }
... ... @@ -435,13 +433,12 @@ void DsoWidget::updateTriggerSource() {
435 433 void DsoWidget::updateVoltageCoupling(ChannelID channel) {
436 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 439 /// \brief Handles modeChanged signal from the voltage dock.
442 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 444 /// \brief Handles gainChanged signal from the voltage dock.
... ... @@ -505,26 +502,32 @@ void DsoWidget::updateZoom(bool enabled) {
505 502 }
506 503  
507 504 /// \brief Prints analyzed data.
508   -void DsoWidget::doShowNewData() {
  505 +void DsoWidget::showNew(std::shared_ptr<PPresult> data) {
509 506 if (exportNextFrame) {
510 507 exportNextFrame->exportSamples(data.get());
511 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 526 for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {
524 527 if (scope->voltage[channel].used && data.get()->data(channel)) {
525 528 // Amplitude string representation (4 significant digits)
526 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 531 // Frequency string representation (5 significant digits)
529 532 measurementFrequencyLabel[channel]->setText(
530 533 valueToString(data.get()->data(channel)->frequency, UNIT_HERTZ, 5));
... ...
openhantek/src/dsowidget.h
... ... @@ -8,16 +8,15 @@
8 8 #include <QGridLayout>
9 9 #include <memory>
10 10  
11   -#include "exporter.h"
  11 +#include "exporting/exporter.h"
12 12 #include "glscope.h"
13 13 #include "levelslider.h"
14 14 #include "hantekdso/controlspecification.h"
15 15  
16   -class DataAnalyzer;
  16 +class SpectrumGenerator;
17 17 struct DsoSettingsScope;
18 18 struct DsoSettingsView;
19 19  
20   -/// \class DsoWidget
21 20 /// \brief The widget for the oszilloscope-screen
22 21 /// This widget contains the scopes and all level sliders.
23 22 class DsoWidget : public QWidget {
... ... @@ -37,9 +36,11 @@ class DsoWidget : public QWidget {
37 36 /// \param parent The parent widget.
38 37 /// \param flags Flags for the window manager.
39 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 39 void setExporterForNextFrame(std::unique_ptr<Exporter> exporter);
42 40  
  41 + // Data arrived
  42 + void showNew(std::shared_ptr<PPresult> data);
  43 +
43 44 protected:
44 45 void setupSliders(Sliders &sliders);
45 46 void adaptTriggerLevelSlider(DsoWidget::Sliders &sliders, ChannelID channel);
... ... @@ -83,11 +84,10 @@ class DsoWidget : public QWidget {
83 84 DsoSettingsView* view;
84 85 const Dso::ControlSpecification* spec;
85 86  
86   - GlGenerator *generator; ///< The generator for the OpenGL vertex arrays
87 87 GlScope *mainScope; ///< The main scope screen
88 88 GlScope *zoomScope; ///< The optional magnified scope screen
89 89 std::unique_ptr<Exporter> exportNextFrame;
90   - std::unique_ptr<DataAnalyzerResult> data;
  90 + std::shared_ptr<PPresult> data;
91 91  
92 92 public slots:
93 93 // Horizontal axis
... ... @@ -117,9 +117,6 @@ class DsoWidget : public QWidget {
117 117 // Scope control
118 118 void updateZoom(bool enabled);
119 119  
120   - // Data analyzer
121   - void doShowNewData();
122   -
123 120 private slots:
124 121 // Sliders
125 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 1 // SPDX-License-Identifier: GPL-2.0+
2 2  
3 3 #include <cmath>
  4 +#include <iostream>
4 5  
5 6 #include <QColor>
  7 +#include <QDebug>
  8 +#include <QMatrix4x4>
6 9 #include <QMouseEvent>
  10 +#include <QOpenGLShaderProgram>
7 11  
  12 +#include <QOpenGLFunctions_3_3_Core>
8 13 #include <QOpenGLFunctions_ES2>
9   -#include <QOpenGLFunctions_3_2_Core>
10   -#include <QOpenGLFunctions_1_3>
11 14  
12 15 #include "glscope.h"
13 16  
14   -#include "glgenerator.h"
  17 +#include "post/graphgenerator.h"
  18 +#include "post/ppresult.h"
15 19 #include "scopesettings.h"
16   -#include "viewsettings.h"
17 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 28 s->zoomed = false;
23 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 34 s->zoomed = true;
30 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 45 void GlScope::mousePressEvent(QMouseEvent *event) {
117 46 if (!zoomed && event->button() == Qt::LeftButton) {
... ... @@ -126,9 +55,7 @@ void GlScope::mousePressEvent(QMouseEvent *event) {
126 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 60 event->accept();
134 61 }
... ... @@ -139,12 +66,11 @@ void GlScope::mouseMoveEvent(QMouseEvent *event) {
139 66 if (selectedMarker == NO_MARKER) {
140 67 // User started draging outside the snap area of any marker:
141 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 70 emit markerMoved(marker, position);
144 71 selectedMarker = marker;
145 72 }
146   - }
147   - else if (selectedMarker < MARKER_COUNT) {
  73 + } else if (selectedMarker < MARKER_COUNT) {
148 74 emit markerMoved(selectedMarker, position);
149 75 }
150 76 }
... ... @@ -154,106 +80,339 @@ void GlScope::mouseMoveEvent(QMouseEvent *event) {
154 80 void GlScope::mouseReleaseEvent(QMouseEvent *event) {
155 81 if (!zoomed && event->button() == Qt::LeftButton) {
156 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 84 selectedMarker = NO_MARKER;
161 85 }
162 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 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 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 2  
3 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 12 #include <QOpenGLWidget>
  13 +
  14 +#include "glscopegraph.h"
10 15 #include "hantekdso/enums.h"
11   -#include "hantekprotocol/definitions.h"
  16 +#include "hantekprotocol/types.h"
12 17  
13   -class GlGenerator;
14   -struct DsoSettingsScope;
15 18 struct DsoSettingsView;
  19 +struct DsoSettingsScope;
  20 +class PPresult;
16 21  
17 22 /// \brief OpenGL accelerated widget that displays the oscilloscope screen.
18 23 class GlScope : public QOpenGLWidget {
19 24 Q_OBJECT
20 25  
21 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 38 protected:
26 39 /// \brief Initializes the scope widget.
27 40 /// \param settings The settings that should be used.
28 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 45 /// \brief Initializes OpenGL output.
32 46 void initializeGL() override;
33 47  
34   - /// \brief Draw the graphs and the grid.
  48 + /// \brief Draw the graphs, marker and the grid.
35 49 void paintGL() override;
36 50  
37 51 /// \brief Resize the widget.
... ... @@ -45,28 +59,47 @@ class GlScope : public QOpenGLWidget {
45 59  
46 60 /// \brief Draw the grid.
47 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 67 signals:
60   - void markerMoved(int marker, double position);
  68 + void markerMoved(unsigned marker, double position);
61 69  
62 70 private:
63   - const int NO_MARKER = -1;
  71 + // User settings
64 72 DsoSettingsScope *scope;
65 73 DsoSettingsView *view;
66   - const GlGenerator *generator;
67   - std::vector<int> fadingFactor;
68   -
69   - std::vector<GLfloat> vaMarker[2];
70 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 1 // SPDX-License-Identifier: GPL-2.0+
2 2  
3   -#include <QDebug>
4 3 #include <QApplication>
  4 +#include <QDebug>
5 5 #include <QLibraryInfo>
6 6 #include <QLocale>
7   -#include <QTranslator>
8 7 #include <QSurfaceFormat>
  8 +#include <QTranslator>
9 9  
10 10 #include <iostream>
11   -#include <memory>
12 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 20 #include "hantekdsocontrol.h"
16 21 #include "mainwindow.h"
  22 +#include "selectdevice/selectsupporteddevice.h"
17 23 #include "settings.h"
18 24 #include "usb/usbdevice.h"
19   -#include "dsomodel.h"
20   -#include "selectdevice/selectsupporteddevice.h"
21 25 #include "viewconstants.h"
22 26  
23 27 #ifndef VERSION
... ... @@ -26,12 +30,12 @@
26 30  
27 31 using namespace Hantek;
28 32  
29   -
30 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 36 bool mathUsed = scope->anyUsed(spec->channels);
33 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 39 dsoControl->setGain(channel, scope->gain(channel) * DIVS_VOLTAGE);
36 40 dsoControl->setOffset(channel, (scope->voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
37 41 dsoControl->setTriggerLevel(channel, scope->voltage[channel].trigger);
... ... @@ -47,9 +51,9 @@ void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope
47 51 dsoControl->setRecordLength(scope->horizontal.recordLength);
48 52 else {
49 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 58 dsoControl->setTriggerMode(scope->trigger.mode);
55 59 dsoControl->setPretriggerPosition(scope->trigger.position * scope->horizontal.timebase * DIVS_TIME);
... ... @@ -57,7 +61,6 @@ void applySettingsToDevice(HantekDsoControl* dsoControl, DsoSettingsScope* scope
57 61 dsoControl->setTriggerSource(scope->trigger.special, scope->trigger.source);
58 62 }
59 63  
60   -
61 64 /// \brief Initialize resources and translations and show the main window.
62 65 int main(int argc, char *argv[]) {
63 66 //////// Set application information ////////
... ... @@ -69,6 +72,7 @@ int main(int argc, char *argv[]) {
69 72 QCoreApplication::setAttribute(Qt::AA_UseOpenGLES, true);
70 73 QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
71 74  
  75 + // Prefer full desktop OpenGL without fixed pipeline
72 76 QSurfaceFormat format;
73 77 format.setProfile(QSurfaceFormat::CoreProfile);
74 78 QSurfaceFormat::setDefaultFormat(format);
... ... @@ -111,27 +115,36 @@ int main(int argc, char *argv[]) {
111 115 QObject::connect(device.get(), &USBDevice::deviceDisconnected, QCoreApplication::instance(),
112 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 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 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 145 //////// Start DSO thread and go into GUI main loop
133 146 dsoControl.startSampling();
134   - dataAnalyzerThread.start();
  147 + postProcessingThread.start();
135 148 dsoControlThread.start();
136 149 int res = openHantekApplication.exec();
137 150  
... ... @@ -139,7 +152,7 @@ int main(int argc, char *argv[]) {
139 152 dsoControlThread.quit();
140 153 dsoControlThread.wait(10000);
141 154  
142   - dataAnalyzerThread.quit();
143   - dataAnalyzerThread.wait(10000);
  155 + postProcessingThread.quit();
  156 + postProcessingThread.wait(10000);
144 157 return res;
145 158 }
... ...
openhantek/src/mainwindow.cpp
... ... @@ -6,15 +6,13 @@
6 6 #include "TriggerDock.h"
7 7 #include "VoltageDock.h"
8 8 #include "dockwindows.h"
9   -#include "exporter.h"
10 9  
11 10 #include "configdialog.h"
12   -#include "analyse/dataanalyzer.h"
13 11 #include "dockwindows.h"
  12 +#include "dsomodel.h"
14 13 #include "dsowidget.h"
15 14 #include "hantekdsocontrol.h"
16 15 #include "usb/usbdevice.h"
17   -#include "dsomodel.h"
18 16 #include "viewconstants.h"
19 17  
20 18 #include "settings.h"
... ... @@ -23,12 +21,10 @@
23 21 #include <QLineEdit>
24 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 26 ui->setupUi(this);
30 27  
31   -
32 28 // Window title
33 29 setWindowIcon(QIcon(":openhantek.png"));
34 30 setWindowTitle(tr("OpenHantek - Device %1").arg(QString::fromStdString(dsoControl->getDevice()->getModel()->name)));
... ... @@ -38,40 +34,46 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
38 34 setDockOptions(dockOptions() | QMainWindow::GroupedDragging);
39 35 #endif
40 36  
  37 + DsoSettingsScope *scope = &(mSettings->scope);
  38 + const Dso::ControlSpecification *spec = &dsoControl->getDevice()->getModel()->specification;
  39 +
41 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 52 addDockWidget(Qt::RightDockWidgetArea, horizontalDock);
54 53 addDockWidget(Qt::RightDockWidgetArea, triggerDock);
55 54 addDockWidget(Qt::RightDockWidgetArea, voltageDock);
56 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 64 // Command field inside the status bar
62   - QLineEdit* commandEdit = new QLineEdit(this);
  65 + QLineEdit *commandEdit = new QLineEdit(this);
63 66 commandEdit->hide();
64 67  
65 68 statusBar()->addPermanentWidget(commandEdit, 1);
66 69  
67 70 connect(ui->actionManualCommand, &QAction::toggled, [this, commandEdit](bool checked) {
68 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 77 commandEdit->clear();
76 78 this->ui->actionManualCommand->setChecked(false);
77 79 if (errorCode != Dso::ErrorCode::NONE) statusBar()->showMessage(tr("Invalid command"), 3000);
... ... @@ -81,38 +83,38 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
81 83 connect(dsoControl, &HantekDsoControl::statusMessage, statusBar(), &QStatusBar::showMessage);
82 84  
83 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 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 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 118 horizontalDock->setSamplerate(samplerate);
117 119 dsoWidget->updateSamplerate(samplerate);
118 120 }
... ... @@ -127,19 +129,18 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
127 129 connect(dsoWidget, &DsoWidget::triggerPositionChanged, dsoControl, &HantekDsoControl::setPretriggerPosition);
128 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 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 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 146 connect(voltageDock, &VoltageDock::usedChanged, usedChanged);
... ... @@ -148,15 +149,15 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
148 149 connect(voltageDock, &VoltageDock::couplingChanged, dsoControl, &HantekDsoControl::setCoupling);
149 150 connect(voltageDock, &VoltageDock::couplingChanged, dsoWidget, &DsoWidget::updateVoltageCoupling);
150 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 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 163 connect(voltageDock, &VoltageDock::usedChanged, dsoWidget, &DsoWidget::updateVoltageUsed);
... ... @@ -164,21 +165,21 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
164 165 connect(spectrumDock, &SpectrumDock::magnitudeChanged, dsoWidget, &DsoWidget::updateSpectrumMagnitude);
165 166  
166 167 // Started/stopped signals from oscilloscope
167   - connect(dsoControl, &HantekDsoControl::samplingStarted, [this]() {
  168 + connect(dsoControl, &HantekDsoControl::samplingStarted, [this, dsoControl]() {
168 169 this->ui->actionSampling->setText(tr("&Stop"));
169 170 this->ui->actionSampling->setIcon(QIcon(":actions/stop.png"));
170 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 177 this->ui->actionSampling->setText(tr("&Start"));
177 178 this->ui->actionSampling->setIcon(QIcon(":actions/start.png"));
178 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 185 connect(dsoControl, &HantekDsoControl::availableRecordLengthsChanged, horizontalDock,
... ... @@ -190,67 +191,67 @@ MainWindow::MainWindow(HantekDsoControl *dsoControl, DataAnalyzer *dataAnalyser,
190 191 connect(ui->actionOpen, &QAction::triggered, [this]() {
191 192 QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), "", tr("Settings (*.ini)"));
192 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 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 204 connect(ui->actionSave_as, &QAction::triggered, [this]() {
206 205 QString fileName = QFileDialog::getSaveFileName(this, tr("Save settings"), "", tr("Settings (*.ini)"));
207 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 223 connect(ui->actionExit, &QAction::triggered, this, &QWidget::close);
223 224  
224 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 230 configDialog->setModal(true);
230 231 configDialog->show();
231 232 });
232 233  
233 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 238 this->ui->actionDigital_phosphor->setStatusTip(tr("Disable fading of previous graphs"));
238 239 else
239 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 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 248 this->ui->actionZoom->setStatusTip(tr("Hide magnified scope"));
248 249 else
249 250 this->ui->actionZoom->setStatusTip(tr("Show magnified scope"));
250 251  
251 252 this->dsoWidget->updateZoom(enabled);
252 253 });
253   - ui->actionZoom->setChecked(settings->view.zoom);
  254 + ui->actionZoom->setChecked(mSettings->view.zoom);
254 255  
255 256 connect(ui->actionAbout, &QAction::triggered, [this]() {
256 257 QMessageBox::about(
... ... @@ -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 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 282 /// \brief Save the settings before exiting.
283 283 /// \param event The close event that should be handled.
284 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 291 QMainWindow::closeEvent(event);
... ...
openhantek/src/mainwindow.h
1 1 #pragma once
2 2 #include <QMainWindow>
  3 +#include <memory>
  4 +#include "post/ppresult.h"
3 5  
4   -class DataAnalyzer;
  6 +class SpectrumGenerator;
5 7 class HantekDsoControl;
6 8 class DsoSettings;
7 9 class DsoWidget;
... ... @@ -22,27 +24,19 @@ class MainWindow : public QMainWindow
22 24 Q_OBJECT
23 25  
24 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 28 ~MainWindow();
  29 +public slots:
  30 + void showNewData(std::shared_ptr<PPresult> data);
27 31  
28 32 protected:
29 33 void closeEvent(QCloseEvent *event) override;
30 34 private:
31 35 Ui::MainWindow *ui;
32 36  
33   - // Docking windows
34   - HorizontalDock *horizontalDock;
35   - TriggerDock *triggerDock;
36   - SpectrumDock *spectrumDock;
37   - VoltageDock *voltageDock;
38   -
39 37 // Central widgets
40 38 DsoWidget *dsoWidget;
41 39  
42   - // Data handling classes
43   - HantekDsoControl *dsoControl;
44   - DataAnalyzer *dataAnalyzer;
45   -
46 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 2  
3 3 #pragma once
4 4 #include <QString>
5   -#include "analyse/enums.h"
  5 +#include "post/enums.h"
6 6 #include "hantekdso/enums.h"
7 7  
8 8 #define MARKER_COUNT 2 ///< Number of markers
... ...