Commit f26fec83726394bb3f3fa46452f00dc1d6bb07d1
Committed by
David Gräff
1 parent
9c6b32e7
Remove private fields of MainWindow that are not used. Adapt MainWindow and DsoWidget to changes.
Showing
12 changed files
with
695 additions
and
732 deletions
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 |