Commit 2f274863084227ccc144437a57a75f8d50f08c8b

Authored by David Gräff
Committed by GitHub
1 parent 73fe7c68

Enumclasses (#136)

* All protocol enums are now enum classes
* All hantekdso enums are enum classes now
* Type-safety enforced on several places
* Rework command and control buffers
* Remove controlindex
* Enerything in hantekprotocol is now in the Hantek namespace
* Implement new device selection dialog. List supported devices. Add dialog to try a new device with the specifications of an already supported device. Not yet completed.
* Do not try to build firmware extractor for windows users
* Move software trigger algorithm into own class
Showing 78 changed files with 2497 additions and 2168 deletions
CMakeLists.txt
... ... @@ -18,10 +18,11 @@ include(cmake/CPackInfos.cmake)
18 18  
19 19 # Qt Widgets based Gui with OpenGL canvas
20 20 add_subdirectory(openhantek)
21   -add_subdirectory(firmware EXCLUDE_FROM_ALL)
22 21  
23 22 if (WIN32)
24 23 install(FILES COPYING readme.md DESTINATION ".")
  24 +else()
  25 + add_subdirectory(firmware EXCLUDE_FROM_ALL)
25 26 endif()
26 27  
27 28 if("${CMAKE_SYSTEM}" MATCHES "Linux")
... ...
openhantek/CMakeLists.txt
... ... @@ -19,6 +19,7 @@ include_directories(src/ src/hantekdso src/widgets src/docks src/configdialog)
19 19 # collect sources and other files
20 20 file(GLOB_RECURSE SRC "src/*.cpp")
21 21 file(GLOB_RECURSE HEADERS "src/*.h")
  22 +file(GLOB_RECURSE UI "src/*.ui")
22 23 file(GLOB_RECURSE QRC "res/*.qrc")
23 24  
24 25 add_custom_target(format SOURCES ".clang-format"
... ... @@ -29,7 +30,7 @@ add_subdirectory(translations)
29 30 add_definitions(-DVERSION="${CPACK_PACKAGE_VERSION}")
30 31  
31 32 # make executable
32   -add_executable(${PROJECT_NAME} ${SRC} ${HEADERS} ${QRC} ${TRANSLATION_BIN_FILES} ${TRANSLATION_QRC})
  33 +add_executable(${PROJECT_NAME} ${SRC} ${HEADERS} ${UI} ${QRC} ${TRANSLATION_BIN_FILES} ${TRANSLATION_QRC})
33 34 target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::PrintSupport Qt5::OpenGL ${OPENGL_LIBRARIES} )
34 35 target_compile_features(${PROJECT_NAME} PRIVATE cxx_range_for)
35 36 if(MSVC)
... ...
openhantek/src/analyse/dataanalyzer.cpp
... ... @@ -15,7 +15,7 @@
15 15 #include "settings.h"
16 16 #include "utils/printutils.h"
17 17  
18   -std::unique_ptr<DataAnalyzerResult> DataAnalyzer::convertData(const DSOsamples *data, const DsoSettingsScope *scope) {
  18 +std::unique_ptr<DataAnalyzerResult> DataAnalyzer::convertData(const DSOsamples *data, const DsoSettingsScope *scope, unsigned physicalChannels) {
19 19 QReadLocker locker(&data->lock);
20 20  
21 21 unsigned int channelCount = (unsigned int)scope->voltage.size();
... ... @@ -26,9 +26,9 @@ std::unique_ptr&lt;DataAnalyzerResult&gt; DataAnalyzer::convertData(const DSOsamples *
26 26 for (unsigned int channel = 0; channel < channelCount; ++channel) {
27 27 DataChannel *const channelData = result->modifyData(channel);
28 28  
29   - bool gotDataForChannel = channel < scope->physicalChannels && channel < (unsigned int)data->data.size() &&
  29 + bool gotDataForChannel = channel < physicalChannels && channel < (unsigned int)data->data.size() &&
30 30 !data->data.at(channel).empty();
31   - bool isMathChannel = channel >= scope->physicalChannels &&
  31 + bool isMathChannel = channel >= physicalChannels &&
32 32 (scope->voltage[channel].used || scope->spectrum[channel].used) &&
33 33 result->channelCount() >= 2 && !result->data(0)->voltage.sample.empty() &&
34 34 !result->data(1)->voltage.sample.empty();
... ... @@ -36,7 +36,7 @@ std::unique_ptr&lt;DataAnalyzerResult&gt; DataAnalyzer::convertData(const DSOsamples *
36 36 if (!gotDataForChannel && !isMathChannel) {
37 37 // Clear unused channels
38 38 channelData->voltage.sample.clear();
39   - result->modifyData(scope->physicalChannels)->voltage.interval = 0;
  39 + result->modifyData(physicalChannels)->voltage.interval = 0;
40 40 continue;
41 41 }
42 42  
... ... @@ -49,15 +49,15 @@ std::unique_ptr&lt;DataAnalyzerResult&gt; DataAnalyzer::convertData(const DSOsamples *
49 49 }
50 50  
51 51 unsigned int size;
52   - if (channel < scope->physicalChannels) {
53   - size = data->data.at(channel).size();
  52 + if (channel < physicalChannels) {
  53 + size = (unsigned) data->data.at(channel).size();
54 54 if (data->append) size += channelData->voltage.sample.size();
55 55 result->challengeMaxSamples(size);
56 56 } else
57 57 size = result->getMaxSamples();
58 58  
59 59 // Physical channels
60   - if (channel < scope->physicalChannels) {
  60 + if (channel < physicalChannels) {
61 61 // Copy the buffer of the oscilloscope into the sample buffer
62 62 if (data->append)
63 63 channelData->voltage.sample.insert(channelData->voltage.sample.end(), data->data.at(channel).begin(),
... ... @@ -68,20 +68,20 @@ std::unique_ptr&lt;DataAnalyzerResult&gt; DataAnalyzer::convertData(const DSOsamples *
68 68 // Resize the sample vector
69 69 channelData->voltage.sample.resize(size);
70 70 // Set sampling interval
71   - result->modifyData(scope->physicalChannels)->voltage.interval = result->data(0)->voltage.interval;
  71 + result->modifyData(physicalChannels)->voltage.interval = result->data(0)->voltage.interval;
72 72  
73 73 // Resize the sample vector
74   - result->modifyData(scope->physicalChannels)
  74 + result->modifyData(physicalChannels)
75 75 ->voltage.sample.resize(
76 76 qMin(result->data(0)->voltage.sample.size(), result->data(1)->voltage.sample.size()));
77 77  
78 78 // Calculate values and write them into the sample buffer
79 79 std::vector<double>::const_iterator ch1Iterator = result->data(0)->voltage.sample.begin();
80 80 std::vector<double>::const_iterator ch2Iterator = result->data(1)->voltage.sample.begin();
81   - std::vector<double> &resultData = result->modifyData(scope->physicalChannels)->voltage.sample;
  81 + std::vector<double> &resultData = result->modifyData(physicalChannels)->voltage.sample;
82 82 for (std::vector<double>::iterator resultIterator = resultData.begin(); resultIterator != resultData.end();
83 83 ++resultIterator) {
84   - switch (scope->voltage[scope->physicalChannels].math) {
  84 + switch (scope->voltage[physicalChannels].math) {
85 85 case Dso::MathMode::ADD_CH1_CH2:
86 86 *resultIterator = *ch1Iterator + *ch2Iterator;
87 87 break;
... ... @@ -105,7 +105,7 @@ DataAnalyzer::~DataAnalyzer() {
105 105 if (window) fftw_free(window);
106 106 }
107 107  
108   -void DataAnalyzer::applySettings(DsoSettingsScope *scope) { this->scope = scope; }
  108 +void DataAnalyzer::applySettings(DsoSettings *settings) { this->settings = settings; }
109 109  
110 110 void DataAnalyzer::setSourceData(const DSOsamples *data) { sourceData = data; }
111 111  
... ... @@ -113,8 +113,8 @@ std::unique_ptr&lt;DataAnalyzerResult&gt; DataAnalyzer::getNextResult() { return std::
113 113  
114 114 void DataAnalyzer::samplesAvailable() {
115 115 if (sourceData == nullptr) return;
116   - std::unique_ptr<DataAnalyzerResult> result = convertData(sourceData, scope);
117   - spectrumAnalysis(result.get(), lastWindow, lastRecordLength, window, scope);
  116 + std::unique_ptr<DataAnalyzerResult> result = convertData(sourceData, &settings->scope,settings->deviceSpecification->channels);
  117 + spectrumAnalysis(result.get(), lastWindow, lastRecordLength, window, &settings->scope);
118 118 lastResult.swap(result);
119 119 emit analyzed();
120 120 }
... ... @@ -134,11 +134,11 @@ void DataAnalyzer::spectrumAnalysis(DataAnalyzerResult *result, Dso::WindowFunct
134 134 }
135 135  
136 136 // Calculate new window
137   - unsigned int sampleCount = channelData->voltage.sample.size();
  137 + size_t sampleCount = channelData->voltage.sample.size();
138 138 if (!lastWindowBuffer || lastWindow != scope->spectrumWindow || lastRecordLength != sampleCount) {
139 139 if (lastWindowBuffer) fftw_free(lastWindowBuffer);
140 140 lastWindowBuffer = fftw_alloc_real(sampleCount);
141   - lastRecordLength = sampleCount;
  141 + lastRecordLength = (unsigned)sampleCount;
142 142  
143 143 unsigned int windowEnd = lastRecordLength - 1;
144 144 lastWindow = scope->spectrumWindow;
... ...
openhantek/src/analyse/dataanalyzer.h
... ... @@ -13,6 +13,7 @@
13 13 #include "utils/printutils.h"
14 14 #include "enums.h"
15 15  
  16 +class DsoSettings;
16 17 struct DsoSettingsScope;
17 18  
18 19 ////////////////////////////////////////////////////////////////////////////////
... ... @@ -25,7 +26,7 @@ class DataAnalyzer : public QObject {
25 26  
26 27 public:
27 28 ~DataAnalyzer();
28   - void applySettings(DsoSettingsScope *scope);
  29 + void applySettings(DsoSettings *settings);
29 30 void setSourceData(const DSOsamples *data);
30 31 std::unique_ptr<DataAnalyzerResult> getNextResult();
31 32 /**
... ... @@ -34,13 +35,13 @@ class DataAnalyzer : public QObject {
34 35 void samplesAvailable();
35 36  
36 37 private:
37   - static std::unique_ptr<DataAnalyzerResult> convertData(const DSOsamples *data, const DsoSettingsScope *scope);
  38 + static std::unique_ptr<DataAnalyzerResult> convertData(const DSOsamples *data, const DsoSettingsScope *scope, unsigned physicalChannels);
38 39 static void spectrumAnalysis(DataAnalyzerResult *result, Dso::WindowFunction &lastWindow,
39 40 unsigned int lastRecordLength, double *&lastWindowBuffer,
40 41 const DsoSettingsScope *scope);
41 42  
42 43 private:
43   - DsoSettingsScope *scope;
  44 + DsoSettings *settings;
44 45 unsigned int lastRecordLength = 0; ///< The record length of the previously analyzed data
45 46 Dso::WindowFunction lastWindow = (Dso::WindowFunction)-1; ///< The previously used dft window function
46 47 double *window = nullptr;
... ...
openhantek/src/analyse/dataanalyzerresult.cpp
... ... @@ -9,13 +9,13 @@ DataAnalyzerResult::DataAnalyzerResult(unsigned int channelCount) { analyzedData
9 9 /// \brief Returns the analyzed data.
10 10 /// \param channel Channel, whose data should be returned.
11 11 /// \return Analyzed data as AnalyzedData struct.
12   -const DataChannel *DataAnalyzerResult::data(unsigned channel) const {
  12 +const DataChannel *DataAnalyzerResult::data(ChannelID channel) const {
13 13 if (channel >= this->analyzedData.size()) return 0;
14 14  
15 15 return &this->analyzedData[(size_t)channel];
16 16 }
17 17  
18   -DataChannel *DataAnalyzerResult::modifyData(unsigned channel) {
  18 +DataChannel *DataAnalyzerResult::modifyData(ChannelID channel) {
19 19 if (channel >= this->analyzedData.size())
20 20 throw new std::runtime_error("If you modfiy the DataAnalyzerResult, you "
21 21 "need to set the channels first!");
... ...
openhantek/src/analyse/dataanalyzerresult.h
... ... @@ -3,6 +3,7 @@
3 3 #pragma once
4 4  
5 5 #include <vector>
  6 +#include "hantekprotocol/definitions.h"
6 7  
7 8 ////////////////////////////////////////////////////////////////////////////////
8 9 /// \struct SampleValues dataanalyzer.h
... ... @@ -25,8 +26,8 @@ struct DataChannel {
25 26 class DataAnalyzerResult {
26 27 public:
27 28 DataAnalyzerResult(unsigned int channelCount);
28   - const DataChannel *data(unsigned channel) const;
29   - DataChannel *modifyData(unsigned channel);
  29 + const DataChannel *data(ChannelID channel) const;
  30 + DataChannel *modifyData(ChannelID channel);
30 31 unsigned int sampleCount() const;
31 32 unsigned int channelCount() const;
32 33  
... ...
openhantek/src/analyse/enums.cpp 0 → 100644
  1 +#include "enums.h"
  2 +
  3 +namespace Dso {
  4 +
  5 +Enum<Dso::MathMode,Dso::MathMode::ADD_CH1_CH2,Dso::MathMode::SUB_CH1_FROM_CH2> MathModeEnum;
  6 +Enum<Dso::WindowFunction,Dso::WindowFunction::RECTANGULAR,Dso::WindowFunction::FLATTOP> WindowFunctionEnum;
  7 +
  8 +}
... ...
openhantek/src/analyse/enums.h
... ... @@ -9,11 +9,9 @@ namespace Dso {
9 9 enum class MathMode {
10 10 ADD_CH1_CH2,
11 11 SUB_CH2_FROM_CH1,
12   - SUB_CH1_FROM_CH2,
13   -
14   - First = ADD_CH1_CH2,
15   - Last = SUB_CH1_FROM_CH2
  12 + SUB_CH1_FROM_CH2
16 13 };
  14 +extern Enum<Dso::MathMode,Dso::MathMode::ADD_CH1_CH2,Dso::MathMode::SUB_CH1_FROM_CH2> MathModeEnum;
17 15  
18 16 /// \enum WindowFunction
19 17 /// \brief The supported window functions.
... ... @@ -34,11 +32,9 @@ enum class WindowFunction: int {
34 32 NUTTALL, ///< Nuttall window, cont. first deriv.
35 33 BLACKMANHARRIS, ///< Blackman-Harris window
36 34 BLACKMANNUTTALL, ///< Blackman-Nuttall window
37   - FLATTOP, ///< Flat top window
38   -
39   - First = RECTANGULAR,
40   - Last = FLATTOP
  35 + FLATTOP ///< Flat top window
41 36 };
  37 +extern Enum<Dso::WindowFunction,Dso::WindowFunction::RECTANGULAR,Dso::WindowFunction::FLATTOP> WindowFunctionEnum;
42 38  
43 39 }
44 40  
... ...
openhantek/src/configdialog/DsoConfigColorsPage.cpp
... ... @@ -51,12 +51,12 @@ DsoConfigColorsPage::DsoConfigColorsPage(DsoSettings *settings, QWidget *parent)
51 51 printSpectrumLabel = new QLabel(tr("Spectrum"));
52 52 printSpectrumLabel->setAlignment(Qt::AlignHCenter);
53 53  
54   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
55   - colorLabel.append(new QLabel(settings->scope.voltage[channel].name));
56   - screenChannelColorBox.append(new ColorBox(colorSettings.screen.voltage[channel]));
57   - screenSpectrumColorBox.append(new ColorBox(colorSettings.screen.spectrum[channel]));
58   - printChannelColorBox.append(new ColorBox(colorSettings.print.voltage[channel]));
59   - printSpectrumColorBox.append(new ColorBox(colorSettings.print.spectrum[channel]));
  54 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  55 + colorLabel.push_back(new QLabel(settings->scope.voltage[channel].name));
  56 + screenChannelColorBox.push_back(new ColorBox(colorSettings.screen.voltage[channel]));
  57 + screenSpectrumColorBox.push_back(new ColorBox(colorSettings.screen.spectrum[channel]));
  58 + printChannelColorBox.push_back(new ColorBox(colorSettings.print.voltage[channel]));
  59 + printSpectrumColorBox.push_back(new ColorBox(colorSettings.print.spectrum[channel]));
60 60 }
61 61  
62 62 // Plot Area Layout
... ... @@ -106,7 +106,7 @@ DsoConfigColorsPage::DsoConfigColorsPage(DsoSettings *settings, QWidget *parent)
106 106 colorsLayout->addWidget(printSpectrumLabel, row, COL_PRT_SPECTRUM);
107 107 ++row;
108 108  
109   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel, ++row) {
  109 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel, ++row) {
110 110 colorsLayout->addWidget(colorLabel[channel], row, COL_LABEL);
111 111 colorsLayout->addWidget(screenChannelColorBox[channel], row, COL_SCR_CHANNEL);
112 112 colorsLayout->addWidget(screenSpectrumColorBox[channel], row, COL_SCR_SPECTRUM);
... ... @@ -146,7 +146,7 @@ void DsoConfigColorsPage::saveSettings() {
146 146 colorSettings.print.text = printTextColorBox->getColor();
147 147  
148 148 // Graph category
149   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  149 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
150 150 colorSettings.screen.voltage[channel] = screenChannelColorBox[channel]->getColor();
151 151 colorSettings.screen.spectrum[channel] = screenSpectrumColorBox[channel]->getColor();
152 152 colorSettings.print.voltage[channel] = printChannelColorBox[channel]->getColor();
... ...
openhantek/src/configdialog/DsoConfigColorsPage.h
... ... @@ -46,9 +46,9 @@ class DsoConfigColorsPage : public QWidget {
46 46 QLabel *graphLabel;
47 47  
48 48 QLabel *screenChannelLabel, *screenSpectrumLabel, *printChannelLabel, *printSpectrumLabel;
49   - QList<QLabel *> colorLabel;
50   - QList<ColorBox *> screenChannelColorBox;
51   - QList<ColorBox *> screenSpectrumColorBox;
52   - QList<ColorBox *> printChannelColorBox;
53   - QList<ColorBox *> printSpectrumColorBox;
  49 + std::vector<QLabel *> colorLabel;
  50 + std::vector<ColorBox *> screenChannelColorBox;
  51 + std::vector<ColorBox *> screenSpectrumColorBox;
  52 + std::vector<ColorBox *> printChannelColorBox;
  53 + std::vector<ColorBox *> printSpectrumColorBox;
54 54 };
... ...
openhantek/src/configdialog/configdialog.cpp
... ... @@ -90,9 +90,9 @@ DsoConfigDialog::DsoConfigDialog(DsoSettings *settings, QWidget *parent, Qt::Win
90 90 this->mainLayout->addLayout(this->buttonsLayout);
91 91 this->setLayout(this->mainLayout);
92 92  
93   - connect(this->acceptButton, SIGNAL(clicked()), this, SLOT(accept()));
94   - connect(this->applyButton, SIGNAL(clicked()), this, SLOT(apply()));
95   - connect(this->rejectButton, SIGNAL(clicked()), this, SLOT(reject()));
  93 + connect(this->acceptButton, &QAbstractButton::clicked, this, &DsoConfigDialog::accept);
  94 + connect(this->applyButton, &QAbstractButton::clicked, this, &DsoConfigDialog::apply);
  95 + connect(this->rejectButton, &QAbstractButton::clicked, this, &QDialog::reject);
96 96 }
97 97  
98 98 /// \brief Cleans up the dialog.
... ... @@ -116,8 +116,8 @@ void DsoConfigDialog::createIcons() {
116 116 scopeButton->setIcon(QIcon(":config/scope.png"));
117 117 scopeButton->setText(tr("Scope"));
118 118  
119   - connect(contentsWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this,
120   - SLOT(changePage(QListWidgetItem *, QListWidgetItem *)));
  119 + connect(contentsWidget, &QListWidget::currentItemChanged, this,
  120 + &DsoConfigDialog::changePage);
121 121 }
122 122  
123 123 /// \brief Saves the settings and closes the dialog.
... ...
openhantek/src/docks/HorizontalDock.cpp
... ... @@ -59,8 +59,8 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
59 59  
60 60 this->formatLabel = new QLabel(tr("Format"));
61 61 this->formatComboBox = new QComboBox();
62   - for (int format = Dso::GRAPHFORMAT_TY; format < Dso::GRAPHFORMAT_COUNT; ++format)
63   - this->formatComboBox->addItem(Dso::graphFormatString((Dso::GraphFormat)format));
  62 + for (Dso::GraphFormat format: Dso::GraphFormatEnum)
  63 + this->formatComboBox->addItem(Dso::graphFormatString(format));
64 64  
65 65 this->dockLayout = new QGridLayout();
66 66 this->dockLayout->setColumnMinimumWidth(0, 64);
... ... @@ -156,7 +156,7 @@ void HorizontalDock::setRecordLength(unsigned int recordLength) {
156 156 /// \return Index of format-value, -1 on error.
157 157 int HorizontalDock::setFormat(Dso::GraphFormat format) {
158 158 QSignalBlocker blocker(formatComboBox);
159   - if (format >= Dso::GRAPHFORMAT_TY && format <= Dso::GRAPHFORMAT_XY) {
  159 + if (format >= Dso::GraphFormat::TY && format <= Dso::GraphFormat::XY) {
160 160 formatComboBox->setCurrentIndex(format);
161 161 return format;
162 162 }
... ...
openhantek/src/docks/SpectrumDock.cpp
... ... @@ -26,42 +26,37 @@ SpectrumDock::SpectrumDock(DsoSettings *settings, QWidget *parent, Qt::WindowFla
26 26 : QDockWidget(tr("Spectrum"), parent, flags), settings(settings) {
27 27  
28 28 // Initialize lists for comboboxes
29   - this->magnitudeSteps << 1e0 << 2e0 << 3e0 << 6e0 << 1e1 << 2e1 << 3e1 << 6e1 << 1e2 << 2e2 << 3e2
30   - << 6e2; ///< Magnitude steps in dB/div
31   - for (QList<double>::iterator magnitude = this->magnitudeSteps.begin(); magnitude != this->magnitudeSteps.end();
32   - ++magnitude)
33   - this->magnitudeStrings << valueToString(*magnitude, UNIT_DECIBEL, 0);
  29 + this->magnitudeSteps = { 1e0 , 2e0 , 3e0 , 6e0 , 1e1 , 2e1 , 3e1 , 6e1 , 1e2 , 2e2 , 3e2, 6e2 };
  30 + for (const auto& magnitude: magnitudeSteps)
  31 + this->magnitudeStrings << valueToString(magnitude, UNIT_DECIBEL, 0);
34 32  
35 33 // Initialize elements
36   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
37   - this->magnitudeComboBox.append(new QComboBox());
  34 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  35 + this->magnitudeComboBox.push_back(new QComboBox());
38 36 this->magnitudeComboBox[channel]->addItems(this->magnitudeStrings);
39 37  
40   - this->usedCheckBox.append(new QCheckBox(settings->scope.voltage[channel].name));
  38 + this->usedCheckBox.push_back(new QCheckBox(settings->scope.voltage[channel].name));
41 39 }
42 40  
43 41 this->dockLayout = new QGridLayout();
44 42 this->dockLayout->setColumnMinimumWidth(0, 64);
45 43 this->dockLayout->setColumnStretch(1, 1);
46   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
47   - this->dockLayout->addWidget(this->usedCheckBox[channel], channel, 0);
48   - this->dockLayout->addWidget(this->magnitudeComboBox[channel], channel, 1);
49   - }
50   -
51   - this->dockWidget = new QWidget();
52   - SetupDockWidget(this, dockWidget, dockLayout);
  44 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  45 + this->dockLayout->addWidget(this->usedCheckBox[channel], (int)channel, 0);
  46 + this->dockLayout->addWidget(this->magnitudeComboBox[channel], (int)channel, 1);
53 47  
54   - // Connect signals and slots
55   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
56   - connect(this->magnitudeComboBox[channel], SIGNAL(currentIndexChanged(int)), this, SLOT(magnitudeSelected(int)));
57   - connect(this->usedCheckBox[channel], SIGNAL(toggled(bool)), this, SLOT(usedSwitched(bool)));
58   - }
  48 + // Connect signals and slots
  49 + connect(usedCheckBox[channel], &QCheckBox::toggled, this, &SpectrumDock::usedSwitched);
  50 + QComboBox* cmb = magnitudeComboBox[channel];
  51 + connect(cmb, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &SpectrumDock::magnitudeSelected);
59 52  
60   - // Set values
61   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  53 + // Set values
62 54 this->setMagnitude(channel, settings->scope.spectrum[channel].magnitude);
63 55 this->setUsed(channel, settings->scope.spectrum[channel].used);
64 56 }
  57 +
  58 + dockWidget = new QWidget();
  59 + SetupDockWidget(this, dockWidget, dockLayout);
65 60 }
66 61  
67 62 /// \brief Don't close the dock, just hide it
... ... @@ -76,32 +71,31 @@ void SpectrumDock::closeEvent(QCloseEvent *event) {
76 71 /// \param channel The channel, whose magnitude should be set.
77 72 /// \param magnitude The magnitude in dB.
78 73 /// \return Index of magnitude-value, -1 on error.
79   -int SpectrumDock::setMagnitude(int channel, double magnitude) {
80   - if (channel < 0 || channel >= settings->scope.voltage.size()) return -1;
81   -
82   - int index = this->magnitudeSteps.indexOf(magnitude);
83   - if (index != -1) this->magnitudeComboBox[channel]->setCurrentIndex(index);
  74 +int SpectrumDock::setMagnitude(ChannelID channel, double magnitude) {
  75 + if (channel >= settings->scope.voltage.size()) return -1;
84 76  
  77 + auto indexIt = std::find(magnitudeSteps.begin(),magnitudeSteps.end(),magnitude);
  78 + if (indexIt == magnitudeSteps.end()) return -1;
  79 + int index = (int)std::distance(magnitudeSteps.begin(), indexIt);
  80 + magnitudeComboBox[channel]->setCurrentIndex(index);
85 81 return index;
86 82 }
87 83  
88 84 /// \brief Enables/disables a channel.
89 85 /// \param channel The channel, that should be enabled/disabled.
90 86 /// \param used True if the channel should be enabled, false otherwise.
91   -/// \return Index of channel, -1 on error.
92   -int SpectrumDock::setUsed(int channel, bool used) {
93   - if (channel >= 0 && channel < settings->scope.voltage.size()) {
94   - this->usedCheckBox[channel]->setChecked(used);
95   - return channel;
96   - }
  87 +/// \return Index of channel, INT_MAX on error.
  88 +unsigned SpectrumDock::setUsed(ChannelID channel, bool used) {
  89 + if (channel >= settings->scope.voltage.size()) return INT_MAX;
97 90  
98   - return -1;
  91 + this->usedCheckBox[channel]->setChecked(used);
  92 + return channel;
99 93 }
100 94  
101 95 /// \brief Called when the source combo box changes it's value.
102 96 /// \param index The index of the combo box item.
103   -void SpectrumDock::magnitudeSelected(int index) {
104   - int channel;
  97 +void SpectrumDock::magnitudeSelected(unsigned index) {
  98 + ChannelID channel;
105 99  
106 100 // Which combobox was it?
107 101 for (channel = 0; channel < settings->scope.voltage.size(); ++channel)
... ... @@ -117,7 +111,7 @@ void SpectrumDock::magnitudeSelected(int index) {
117 111 /// \brief Called when the used checkbox is switched.
118 112 /// \param checked The check-state of the checkbox.
119 113 void SpectrumDock::usedSwitched(bool checked) {
120   - int channel;
  114 + ChannelID channel;
121 115  
122 116 // Which checkbox was it?
123 117 for (channel = 0; channel < settings->scope.voltage.size(); ++channel)
... ...
openhantek/src/docks/SpectrumDock.h
... ... @@ -22,27 +22,27 @@ class SpectrumDock : public QDockWidget {
22 22 public:
23 23 SpectrumDock(DsoSettings *settings, QWidget *parent, Qt::WindowFlags flags = 0);
24 24  
25   - int setMagnitude(int channel, double magnitude);
26   - int setUsed(int channel, bool used);
  25 + int setMagnitude(ChannelID channel, double magnitude);
  26 + unsigned setUsed(ChannelID channel, bool used);
27 27  
28 28 protected:
29 29 void closeEvent(QCloseEvent *event);
30 30  
31 31 QGridLayout *dockLayout; ///< The main layout for the dock window
32 32 QWidget *dockWidget; ///< The main widget for the dock window
33   - QList<QCheckBox *> usedCheckBox; ///< Enable/disable spectrum for a channel
34   - QList<QComboBox *> magnitudeComboBox; ///< Select the vertical magnitude for the spectrums
  33 + std::vector<QCheckBox *> usedCheckBox; ///< Enable/disable spectrum for a channel
  34 + std::vector<QComboBox *> magnitudeComboBox; ///< Select the vertical magnitude for the spectrums
35 35  
36 36 DsoSettings *settings; ///< The settings provided by the parent class
37 37  
38   - QList<double> magnitudeSteps; ///< The selectable magnitude steps
  38 + std::vector<double> magnitudeSteps; ///< The selectable magnitude steps in dB/div
39 39 QStringList magnitudeStrings; ///< String representations for the magnitude steps
40 40  
41 41 public slots:
42   - void magnitudeSelected(int index);
  42 + void magnitudeSelected(unsigned index);
43 43 void usedSwitched(bool checked);
44 44  
45 45 signals:
46   - void magnitudeChanged(unsigned int channel, double magnitude); ///< A magnitude has been selected
47   - void usedChanged(unsigned int channel, bool used); ///< A spectrum has been enabled/disabled
  46 + void magnitudeChanged(ChannelID channel, double magnitude); ///< A magnitude has been selected
  47 + void usedChanged(ChannelID channel, bool used); ///< A spectrum has been enabled/disabled
48 48 };
... ...
openhantek/src/docks/TriggerDock.cpp
... ... @@ -28,7 +28,7 @@ TriggerDock::TriggerDock(DsoSettings *settings, const std::vector&lt;std::string&gt; &amp;
28 28 : QDockWidget(tr("Trigger"), parent, flags), settings(settings) {
29 29  
30 30 // Initialize lists for comboboxes
31   - for (unsigned int channel = 0; channel < settings->scope.physicalChannels; ++channel)
  31 + for (unsigned int channel = 0; channel < settings->deviceSpecification->channels; ++channel)
32 32 this->sourceStandardStrings << tr("CH%1").arg(channel + 1);
33 33 for(const std::string& name: specialTriggers)
34 34 this->sourceSpecialStrings.append(QString::fromStdString(name));
... ... @@ -36,13 +36,13 @@ TriggerDock::TriggerDock(DsoSettings *settings, const std::vector&lt;std::string&gt; &amp;
36 36 // Initialize elements
37 37 this->modeLabel = new QLabel(tr("Mode"));
38 38 this->modeComboBox = new QComboBox();
39   - for (int mode = Dso::TRIGGERMODE_AUTO; mode < Dso::TRIGGERMODE_COUNT; ++mode)
40   - this->modeComboBox->addItem(Dso::triggerModeString((Dso::TriggerMode)mode));
  39 + for (Dso::TriggerMode mode: Dso::TriggerModeEnum)
  40 + this->modeComboBox->addItem(Dso::triggerModeString(mode));
41 41  
42 42 this->slopeLabel = new QLabel(tr("Slope"));
43 43 this->slopeComboBox = new QComboBox();
44   - for (int slope = Dso::SLOPE_POSITIVE; slope < Dso::SLOPE_COUNT; ++slope)
45   - this->slopeComboBox->addItem(Dso::slopeString((Dso::Slope)slope));
  44 + for (Dso::Slope slope: Dso::SlopeEnum)
  45 + this->slopeComboBox->addItem(Dso::slopeString(slope));
46 46  
47 47 this->sourceLabel = new QLabel(tr("Source"));
48 48 this->sourceComboBox = new QComboBox();
... ... @@ -63,9 +63,9 @@ TriggerDock::TriggerDock(DsoSettings *settings, const std::vector&lt;std::string&gt; &amp;
63 63 SetupDockWidget(this, dockWidget, dockLayout);
64 64  
65 65 // Connect signals and slots
66   - connect(this->modeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(modeSelected(int)));
67   - connect(this->slopeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slopeSelected(int)));
68   - connect(this->sourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceSelected(int)));
  66 + connect(this->modeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TriggerDock::modeSelected);
  67 + connect(this->slopeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TriggerDock::slopeSelected);
  68 + connect(this->sourceComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &TriggerDock::sourceSelected);
69 69  
70 70 // Set values
71 71 this->setMode(settings->scope.trigger.mode);
... ... @@ -84,25 +84,15 @@ void TriggerDock::closeEvent(QCloseEvent *event) {
84 84 /// \brief Changes the trigger mode if the new mode is supported.
85 85 /// \param mode The trigger mode.
86 86 /// \return Index of mode-value, -1 on error.
87   -int TriggerDock::setMode(Dso::TriggerMode mode) {
88   - if (mode >= Dso::TRIGGERMODE_AUTO && mode < Dso::TRIGGERMODE_COUNT) {
89   - this->modeComboBox->setCurrentIndex(mode);
90   - return mode;
91   - }
92   -
93   - return -1;
  87 +void TriggerDock::setMode(Dso::TriggerMode mode) {
  88 + this->modeComboBox->setCurrentIndex((int)mode);
94 89 }
95 90  
96 91 /// \brief Changes the trigger slope if the new slope is supported.
97 92 /// \param slope The trigger slope.
98 93 /// \return Index of slope-value, -1 on error.
99   -int TriggerDock::setSlope(Dso::Slope slope) {
100   - if (slope >= Dso::SLOPE_POSITIVE && slope <= Dso::SLOPE_NEGATIVE) {
101   - this->slopeComboBox->setCurrentIndex(slope);
102   - return slope;
103   - }
104   -
105   - return -1;
  94 +void TriggerDock::setSlope(Dso::Slope slope) {
  95 + this->slopeComboBox->setCurrentIndex((int)slope);
106 96 }
107 97  
108 98 /// \brief Changes the trigger source if the new source is supported.
... ... @@ -114,7 +104,7 @@ int TriggerDock::setSource(bool special, unsigned int id) {
114 104 (special && id >= (unsigned int)this->sourceSpecialStrings.count()))
115 105 return -1;
116 106  
117   - int index = id;
  107 + int index = (int)id;
118 108 if (special) index += this->sourceStandardStrings.count();
119 109 this->sourceComboBox->setCurrentIndex(index);
120 110  
... ...
openhantek/src/docks/TriggerDock.h
... ... @@ -21,9 +21,9 @@ class TriggerDock : public QDockWidget {
21 21 public:
22 22 TriggerDock(DsoSettings *settings, const std::vector<std::string>& specialTriggers, QWidget *parent, Qt::WindowFlags flags = 0);
23 23  
24   - int setMode(Dso::TriggerMode mode);
  24 + void setMode(Dso::TriggerMode mode);
25 25 int setSource(bool special, unsigned int id);
26   - int setSlope(Dso::Slope slope);
  26 + void setSlope(Dso::Slope slope);
27 27  
28 28 protected:
29 29 void closeEvent(QCloseEvent *event);
... ...
openhantek/src/docks/VoltageDock.cpp
... ... @@ -26,184 +26,100 @@ VoltageDock::VoltageDock(DsoSettings *settings, QWidget *parent, Qt::WindowFlags
26 26 : QDockWidget(tr("Voltage"), parent, flags), settings(settings) {
27 27  
28 28 // Initialize lists for comboboxes
29   - for (int coupling = Dso::COUPLING_AC; coupling < Dso::COUPLING_COUNT; ++coupling)
30   - this->couplingStrings.append(Dso::couplingString((Dso::Coupling)coupling));
  29 + for (Dso::Coupling c: settings->deviceSpecification->couplings)
  30 + couplingStrings.append(Dso::couplingString(c));
31 31  
32   - for( auto e: Enum<Dso::MathMode>() ) {
33   - this->modeStrings.append(Dso::mathModeString(e));
  32 + for( auto e: Dso::MathModeEnum ) {
  33 + modeStrings.append(Dso::mathModeString(e));
34 34 }
35 35  
36   - this->gainSteps << 1e-2 << 2e-2 << 5e-2 << 1e-1 << 2e-1 << 5e-1 << 1e0 << 2e0 << 5e0; ///< Voltage steps in V/div
37   - for (QList<double>::iterator gain = this->gainSteps.begin(); gain != this->gainSteps.end(); ++gain)
38   - this->gainStrings << valueToString(*gain, UNIT_VOLTS, 0);
  36 + for (double gainStep: settings->scope.gainSteps)
  37 + gainStrings << valueToString(gainStep, UNIT_VOLTS, 0);
39 38  
40   - // Initialize elements
41   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
42   - this->miscComboBox.append(new QComboBox());
43   - if (channel < (int)settings->scope.physicalChannels)
44   - this->miscComboBox[channel]->addItems(this->couplingStrings);
45   - else
46   - this->miscComboBox[channel]->addItems(this->modeStrings);
47   -
48   - this->gainComboBox.append(new QComboBox());
49   - this->gainComboBox[channel]->addItems(this->gainStrings);
  39 + dockLayout = new QGridLayout();
  40 + dockLayout->setColumnMinimumWidth(0, 64);
  41 + dockLayout->setColumnStretch(1, 1);
50 42  
51   - this->invertCheckBox.append(new QCheckBox(tr("Invert")));
  43 + // Initialize elements
  44 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  45 + ChannelBlock b;
52 46  
53   - this->usedCheckBox.append(new QCheckBox(settings->scope.voltage[channel].name));
54   - }
  47 + b.miscComboBox=(new QComboBox());
  48 + b.gainComboBox=(new QComboBox());
  49 + b.invertCheckBox=(new QCheckBox(tr("Invert")));
  50 + b.usedCheckBox=(new QCheckBox(settings->scope.voltage[channel].name));
55 51  
56   - this->dockLayout = new QGridLayout();
57   - this->dockLayout->setColumnMinimumWidth(0, 64);
58   - this->dockLayout->setColumnStretch(1, 1);
59   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
60   - this->dockLayout->addWidget(this->usedCheckBox[channel], channel * 3, 0);
61   - this->dockLayout->addWidget(this->gainComboBox[channel], channel * 3, 1);
62   - this->dockLayout->addWidget(this->miscComboBox[channel], channel * 3 + 1, 1);
63   - this->dockLayout->addWidget(this->invertCheckBox[channel], channel * 3 + 2, 1);
  52 + if (channel < settings->deviceSpecification->channels)
  53 + b.miscComboBox->addItems(couplingStrings);
  54 + else
  55 + b.miscComboBox->addItems(modeStrings);
  56 +
  57 + b.gainComboBox->addItems(gainStrings);
  58 +
  59 + dockLayout->addWidget(b.usedCheckBox, (int)channel * 3, 0);
  60 + dockLayout->addWidget(b.gainComboBox, (int)channel * 3, 1);
  61 + dockLayout->addWidget(b.miscComboBox, (int)channel * 3 + 1, 1);
  62 + dockLayout->addWidget(b.invertCheckBox, (int)channel * 3 + 2, 1);
  63 +
  64 + connect(b.gainComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this,channel](int index) {
  65 + this->settings->scope.voltage[channel].gainStepIndex = (unsigned)index;
  66 + emit gainChanged(channel, this->settings->scope.gain(channel));
  67 + });
  68 + connect(b.invertCheckBox, &QAbstractButton::toggled, [this,channel](bool checked) {
  69 + this->settings->scope.voltage[channel].inverted = checked;
  70 + });
  71 + connect(b.miscComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this,channel](int index){
  72 + if (channel < this->settings->deviceSpecification->channels) {
  73 + this->settings->scope.voltage[channel].couplingIndex = (unsigned)index;
  74 + emit couplingChanged(channel, this->settings->coupling(channel));
  75 + } else {
  76 + this->settings->scope.voltage[channel].math = (Dso::MathMode) index;
  77 + emit modeChanged(this->settings->scope.voltage[channel].math);
  78 + }
  79 + });
  80 + connect(b.usedCheckBox, &QAbstractButton::toggled, [this,channel](bool checked) {
  81 + this->settings->scope.voltage[channel].used = checked;
  82 + emit usedChanged(channel, checked);
  83 + });
  84 +
  85 + channelBlocks.push_back(std::move(b));
  86 +
  87 + if (channel < settings->deviceSpecification->channels)
  88 + setCoupling(channel, settings->scope.voltage[channel].couplingIndex);
  89 + else
  90 + setMode(settings->scope.voltage[channel].math);
  91 + setGain(channel, settings->scope.voltage[channel].gainStepIndex);
  92 + setUsed(channel, settings->scope.voltage[channel].used);
64 93 }
65 94  
66   - this->dockWidget = new QWidget();
  95 + dockWidget = new QWidget();
67 96 SetupDockWidget(this, dockWidget, dockLayout);
68   -
69   - // Connect signals and slots
70   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
71   - connect(this->gainComboBox[channel], SIGNAL(currentIndexChanged(int)), this, SLOT(gainSelected(int)));
72   - connect(this->invertCheckBox[channel], SIGNAL(toggled(bool)), this, SLOT(invertSwitched(bool)));
73   - connect(this->miscComboBox[channel], SIGNAL(currentIndexChanged(int)), this, SLOT(miscSelected(int)));
74   - connect(this->usedCheckBox[channel], SIGNAL(toggled(bool)), this, SLOT(usedSwitched(bool)));
75   - }
76   -
77   - // Set values
78   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
79   - if (channel < (int)settings->scope.physicalChannels)
80   - this->setCoupling(channel, settings->scope.voltage[channel].coupling);
81   - else
82   - this->setMode(settings->scope.voltage[channel].math);
83   - this->setGain(channel, settings->scope.voltage[channel].gain);
84   - this->setUsed(channel, settings->scope.voltage[channel].used);
85   - }
86 97 }
87 98  
88 99 /// \brief Don't close the dock, just hide it
89 100 /// \param event The close event that should be handled.
90 101 void VoltageDock::closeEvent(QCloseEvent *event) {
91   - this->hide();
92   -
  102 + hide();
93 103 event->accept();
94 104 }
95 105  
96   -/// \brief Sets the coupling for a channel.
97   -/// \param channel The channel, whose coupling should be set.
98   -/// \param coupling The coupling-mode.
99   -/// \return Index of coupling-mode, -1 on error.
100   -int VoltageDock::setCoupling(int channel, Dso::Coupling coupling) {
101   - if (coupling < Dso::COUPLING_AC || coupling > Dso::COUPLING_GND) return -1;
102   - if (channel < 0 || channel >= (int)settings->scope.physicalChannels) return -1;
103   -
104   - this->miscComboBox[channel]->setCurrentIndex(coupling);
105   - return coupling;
  106 +void VoltageDock::setCoupling(ChannelID channel, unsigned couplingIndex) {
  107 + if (channel >= settings->deviceSpecification->channels) return;
  108 + if (couplingIndex >= settings->deviceSpecification->couplings.size()) return;
  109 + channelBlocks[channel].miscComboBox->setCurrentIndex((int)couplingIndex);
106 110 }
107 111  
108   -/// \brief Sets the gain for a channel.
109   -/// \param channel The channel, whose gain should be set.
110   -/// \param gain The gain in volts.
111   -/// \return Index of gain-value, -1 on error.
112   -int VoltageDock::setGain(int channel, double gain) {
113   - if (channel < 0 || channel >= settings->scope.voltage.size()) return -1;
114   -
115   - int index = this->gainSteps.indexOf(gain);
116   - if (index != -1) this->gainComboBox[channel]->setCurrentIndex(index);
117   -
118   - return index;
  112 +void VoltageDock::setGain(ChannelID channel, unsigned gainStepIndex) {
  113 + if (channel >= settings->scope.voltage.size()) return;
  114 + if (gainStepIndex >= settings->scope.gainSteps.size()) return;
  115 + channelBlocks[channel].gainComboBox->setCurrentIndex((unsigned)gainStepIndex);
119 116 }
120 117  
121   -/// \brief Sets the mode for the math channel.
122   -/// \param mode The math-mode.
123   -/// \return Index of math-mode, -1 on error.
124 118 void VoltageDock::setMode(Dso::MathMode mode) {
125   - miscComboBox[settings->scope.physicalChannels]->setCurrentIndex((int)mode);
  119 + channelBlocks[settings->deviceSpecification->channels].miscComboBox->setCurrentIndex((int)mode);
126 120 }
127 121  
128   -/// \brief Enables/disables a channel.
129   -/// \param channel The channel, that should be enabled/disabled.
130   -/// \param used True if the channel should be enabled, false otherwise.
131   -/// \return Index of channel, -1 on error.
132   -int VoltageDock::setUsed(int channel, bool used) {
133   - if (channel >= 0 && channel < settings->scope.voltage.size()) {
134   - this->usedCheckBox[channel]->setChecked(used);
135   - return channel;
136   - }
137   -
138   - return -1;
139   -}
140   -
141   -/// \brief Called when the gain combo box changes it's value.
142   -/// \param index The index of the combo box item.
143   -void VoltageDock::gainSelected(int index) {
144   - int channel;
145   -
146   - // Which combobox was it?
147   - for (channel = 0; channel < settings->scope.voltage.size(); ++channel)
148   - if (this->sender() == this->gainComboBox[channel]) break;
149   -
150   - // Send signal if it was one of the comboboxes
151   - if (channel < settings->scope.voltage.size()) {
152   - settings->scope.voltage[channel].gain = this->gainSteps.at(index);
153   -
154   - emit gainChanged(channel, settings->scope.voltage[channel].gain);
155   - }
156   -}
157   -
158   -/// \brief Called when the misc combo box changes it's value.
159   -/// \param index The index of the combo box item.
160   -void VoltageDock::miscSelected(int index) {
161   - int channel;
162   -
163   - // Which combobox was it?
164   - for (channel = 0; channel < settings->scope.voltage.size(); ++channel)
165   - if (this->sender() == this->miscComboBox[channel]) break;
166   -
167   - // Send signal if it was one of the comboboxes
168   - if (channel < settings->scope.voltage.size()) {
169   - if (channel < (int)settings->scope.physicalChannels) {
170   - settings->scope.voltage[channel].coupling = (Dso::Coupling) index;
171   - emit couplingChanged(channel, settings->scope.voltage[channel].coupling);
172   - } else {
173   - settings->scope.voltage[channel].math = (Dso::MathMode) index;
174   - emit modeChanged(settings->scope.voltage[channel].math);
175   - }
176   - }
177   -}
178   -
179   -/// \brief Called when the used checkbox is switched.
180   -/// \param checked The check-state of the checkbox.
181   -void VoltageDock::usedSwitched(bool checked) {
182   - int channel;
183   -
184   - // Which checkbox was it?
185   - for (channel = 0; channel < settings->scope.voltage.size(); ++channel)
186   - if (this->sender() == this->usedCheckBox[channel]) break;
187   -
188   - // Send signal if it was one of the checkboxes
189   - if (channel < settings->scope.voltage.size()) {
190   - settings->scope.voltage[channel].used = checked;
191   - emit usedChanged(channel, checked);
192   - }
193   -}
194   -
195   -/// \brief Called when the invert checkbox is switched.
196   -/// \param checked The check-state of the checkbox.
197   -void VoltageDock::invertSwitched(bool checked) {
198   - int channel;
199   -
200   - // Which checkbox was it?
201   - for (channel = 0; channel < settings->scope.voltage.size(); ++channel)
202   - if (this->sender() == this->invertCheckBox[channel]) break;
203   -
204   - // Send signal if it was one of the checkboxes
205   - if (channel < settings->scope.voltage.size()) {
206   - settings->scope.voltage[channel].inverted = checked;
207   - // Should we emit an event here?
208   - }
  122 +void VoltageDock::setUsed(ChannelID channel, bool used) {
  123 + if (channel >= settings->scope.voltage.size()) return;
  124 + channelBlocks[channel].usedCheckBox->setChecked(used);
209 125 }
... ...
openhantek/src/docks/VoltageDock.h
... ... @@ -4,13 +4,12 @@
4 4  
5 5 #include <QDockWidget>
6 6 #include <QGridLayout>
  7 +#include <QCheckBox>
  8 +#include <QComboBox>
  9 +#include <QLabel>
7 10  
8 11 #include "settings.h"
9 12  
10   -class QLabel;
11   -class QCheckBox;
12   -class QComboBox;
13   -
14 13 class SiSpinBox;
15 14  
16 15 /// \brief Dock window for the voltage channel settings.
... ... @@ -22,34 +21,46 @@ class VoltageDock : public QDockWidget {
22 21 public:
23 22 VoltageDock(DsoSettings *settings, QWidget *parent, Qt::WindowFlags flags = 0);
24 23  
25   - int setCoupling(int channel, Dso::Coupling coupling);
26   - int setGain(int channel, double gain);
  24 + /// \brief Sets the coupling for a channel.
  25 + /// \param channel The channel, whose coupling should be set.
  26 + /// \param coupling The coupling-mode.
  27 + void setCoupling(ChannelID channel, unsigned couplingIndex);
  28 +
  29 + /// \brief Sets the gain for a channel.
  30 + /// \param channel The channel, whose gain should be set.
  31 + /// \param gain The gain in volts.
  32 + void setGain(ChannelID channel, unsigned gainStepIndex);
  33 +
  34 + /// \brief Sets the mode for the math channel.
  35 + /// \param mode The math-mode.
27 36 void setMode(Dso::MathMode mode);
28   - int setUsed(int channel, bool used);
  37 +
  38 + /// \brief Enables/disables a channel.
  39 + /// \param channel The channel, that should be enabled/disabled.
  40 + /// \param used True if the channel should be enabled, false otherwise.
  41 + void setUsed(ChannelID channel, bool used);
29 42  
30 43 protected:
31 44 void closeEvent(QCloseEvent *event);
32 45  
33 46 QGridLayout *dockLayout; ///< The main layout for the dock window
34 47 QWidget *dockWidget; ///< The main widget for the dock window
35   - QList<QCheckBox *> usedCheckBox; ///< Enable/disable a specific channel
36   - QList<QComboBox *> gainComboBox; ///< Select the vertical gain for the channels
37   - QList<QComboBox *> miscComboBox; ///< Select coupling for real and mode for math channels
38   - QList<QCheckBox *> invertCheckBox; ///< Select if the channels should be displayed inverted
  48 +
  49 + struct ChannelBlock {
  50 + QCheckBox * usedCheckBox; ///< Enable/disable a specific channel
  51 + QComboBox * gainComboBox; ///< Select the vertical gain for the channels
  52 + QComboBox * miscComboBox; ///< Select coupling for real and mode for math channels
  53 + QCheckBox * invertCheckBox; ///< Select if the channels should be displayed inverted
  54 + };
  55 +
  56 + std::vector<ChannelBlock> channelBlocks;
39 57  
40 58 DsoSettings *settings; ///< The settings provided by the parent class
41 59  
42 60 QStringList couplingStrings; ///< The strings for the couplings
43 61 QStringList modeStrings; ///< The strings for the math mode
44   - QList<double> gainSteps; ///< The selectable gain steps
45 62 QStringList gainStrings; ///< String representations for the gain steps
46 63  
47   - protected slots:
48   - void gainSelected(int index);
49   - void miscSelected(int index);
50   - void usedSwitched(bool checked);
51   - void invertSwitched(bool checked);
52   -
53 64 signals:
54 65 void couplingChanged(unsigned int channel, Dso::Coupling coupling); ///< A coupling has been selected
55 66 void gainChanged(unsigned int channel, double gain); ///< A gain has been selected
... ...
openhantek/src/dsowidget.cpp
... ... @@ -16,9 +16,11 @@
16 16 #include "utils/dsoStrings.h"
17 17 #include "utils/printutils.h"
18 18 #include "widgets/levelslider.h"
  19 +#include "viewconstants.h"
  20 +#include "analyse/dataanalyzerresult.h"
19 21  
20 22 DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags flags)
21   - : QWidget(parent, flags), settings(settings), generator(new GlGenerator(&settings->scope, &settings->view)),
  23 + : QWidget(parent, flags), settings(settings), generator(new GlGenerator()),
22 24 mainScope(new GlScope(settings, generator)), zoomScope(new GlScope(settings, generator)) {
23 25  
24 26 // Palette for this widget
... ... @@ -31,7 +33,7 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla
31 33  
32 34 // The offset sliders for all possible channels
33 35 offsetSlider = new LevelSlider(Qt::RightArrow);
34   - for (unsigned channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  36 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
35 37 offsetSlider->addSlider(settings->scope.voltage[channel].name, channel);
36 38 offsetSlider->setColor(channel, settings->view.screen.voltage[channel]);
37 39 offsetSlider->setLimits(channel, -DIVS_VOLTAGE / 2, DIVS_VOLTAGE / 2);
... ... @@ -39,7 +41,7 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla
39 41 offsetSlider->setValue(channel, settings->scope.voltage[channel].offset);
40 42 offsetSlider->setIndexVisible(channel, settings->scope.voltage[channel].used);
41 43 }
42   - for (unsigned channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  44 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
43 45 offsetSlider->addSlider(settings->scope.spectrum[channel].name, settings->scope.voltage.size() + channel);
44 46 offsetSlider->setColor(settings->scope.voltage.size() + channel, settings->view.screen.spectrum[channel]);
45 47 offsetSlider->setLimits(settings->scope.voltage.size() + channel, -DIVS_VOLTAGE / 2, DIVS_VOLTAGE / 2);
... ... @@ -52,17 +54,17 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla
52 54 triggerPositionSlider = new LevelSlider(Qt::DownArrow);
53 55 triggerPositionSlider->addSlider();
54 56 triggerPositionSlider->setLimits(0, 0.0, 1.0);
55   - triggerPositionSlider->setStep(0, 0.2 / DIVS_TIME);
  57 + triggerPositionSlider->setStep(0, 0.2 / (double)DIVS_TIME);
56 58 triggerPositionSlider->setValue(0, settings->scope.trigger.position);
57 59 triggerPositionSlider->setIndexVisible(0, true);
58 60  
59 61 // The sliders for the trigger levels
60 62 triggerLevelSlider = new LevelSlider(Qt::LeftArrow);
61   - for (int channel = 0; channel < (int)settings->scope.physicalChannels; ++channel) {
62   - triggerLevelSlider->addSlider(channel);
  63 + for (ChannelID channel = 0; channel < settings->deviceSpecification->channels; ++channel) {
  64 + triggerLevelSlider->addSlider((int)channel);
63 65 triggerLevelSlider->setColor(
64 66 channel,
65   - (!settings->scope.trigger.special && channel == (int)settings->scope.trigger.source)
  67 + (!settings->scope.trigger.special && channel == settings->scope.trigger.source)
66 68 ? settings->view.screen.voltage[channel]
67 69 : settings->view.screen.voltage[channel].darker());
68 70 adaptTriggerLevelSlider(channel);
... ... @@ -142,33 +144,33 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla
142 144 measurementLayout->setColumnStretch(3, 2);
143 145 measurementLayout->setColumnStretch(4, 3);
144 146 measurementLayout->setColumnStretch(5, 3);
145   - for (int channel = 0; channel < (int)settings->scope.voltage.size(); ++channel) {
  147 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
146 148 tablePalette.setColor(QPalette::WindowText, settings->view.screen.voltage[channel]);
147   - measurementNameLabel.append(new QLabel(settings->scope.voltage[channel].name));
  149 + measurementNameLabel.push_back(new QLabel(settings->scope.voltage[channel].name));
148 150 measurementNameLabel[channel]->setPalette(tablePalette);
149   - measurementMiscLabel.append(new QLabel());
  151 + measurementMiscLabel.push_back(new QLabel());
150 152 measurementMiscLabel[channel]->setPalette(tablePalette);
151   - measurementGainLabel.append(new QLabel());
  153 + measurementGainLabel.push_back(new QLabel());
152 154 measurementGainLabel[channel]->setAlignment(Qt::AlignRight);
153 155 measurementGainLabel[channel]->setPalette(tablePalette);
154 156 tablePalette.setColor(QPalette::WindowText, settings->view.screen.spectrum[channel]);
155   - measurementMagnitudeLabel.append(new QLabel());
  157 + measurementMagnitudeLabel.push_back(new QLabel());
156 158 measurementMagnitudeLabel[channel]->setAlignment(Qt::AlignRight);
157 159 measurementMagnitudeLabel[channel]->setPalette(tablePalette);
158   - measurementAmplitudeLabel.append(new QLabel());
  160 + measurementAmplitudeLabel.push_back(new QLabel());
159 161 measurementAmplitudeLabel[channel]->setAlignment(Qt::AlignRight);
160 162 measurementAmplitudeLabel[channel]->setPalette(palette);
161   - measurementFrequencyLabel.append(new QLabel());
  163 + measurementFrequencyLabel.push_back(new QLabel());
162 164 measurementFrequencyLabel[channel]->setAlignment(Qt::AlignRight);
163 165 measurementFrequencyLabel[channel]->setPalette(palette);
164 166 setMeasurementVisible(channel, settings->scope.voltage[channel].used);
165   - measurementLayout->addWidget(measurementNameLabel[channel], channel, 0);
166   - measurementLayout->addWidget(measurementMiscLabel[channel], channel, 1);
167   - measurementLayout->addWidget(measurementGainLabel[channel], channel, 2);
168   - measurementLayout->addWidget(measurementMagnitudeLabel[channel], channel, 3);
169   - measurementLayout->addWidget(measurementAmplitudeLabel[channel], channel, 4);
170   - measurementLayout->addWidget(measurementFrequencyLabel[channel], channel, 5);
171   - if ((unsigned)channel < settings->scope.physicalChannels)
  167 + measurementLayout->addWidget(measurementNameLabel[channel], (int)channel, 0);
  168 + measurementLayout->addWidget(measurementMiscLabel[channel], (int)channel, 1);
  169 + measurementLayout->addWidget(measurementGainLabel[channel], (int)channel, 2);
  170 + measurementLayout->addWidget(measurementMagnitudeLabel[channel], (int)channel, 3);
  171 + measurementLayout->addWidget(measurementAmplitudeLabel[channel], (int)channel, 4);
  172 + measurementLayout->addWidget(measurementFrequencyLabel[channel], (int)channel, 5);
  173 + if ((unsigned)channel < settings->deviceSpecification->channels)
172 174 updateVoltageCoupling((unsigned)channel);
173 175 else
174 176 updateMathMode();
... ... @@ -233,15 +235,15 @@ void DsoWidget::showNewData(std::unique_ptr&lt;DataAnalyzerResult&gt; data) {
233 235 }
234 236  
235 237 /// \brief Set the trigger level sliders minimum and maximum to the new values.
236   -void DsoWidget::adaptTriggerLevelSlider(unsigned int channel) {
  238 +void DsoWidget::adaptTriggerLevelSlider(ChannelID channel) {
237 239 triggerLevelSlider->setLimits(
238   - channel, (-DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.voltage[channel].gain,
239   - (DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.voltage[channel].gain);
240   - triggerLevelSlider->setStep(channel, settings->scope.voltage[channel].gain * 0.2);
  240 + (int)channel, (-DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.gain(channel),
  241 + (DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.gain(channel));
  242 + triggerLevelSlider->setStep((int)channel, settings->scope.gain(channel) * 0.2);
241 243 }
242 244  
243 245 /// \brief Show/Hide a line of the measurement table.
244   -void DsoWidget::setMeasurementVisible(unsigned int channel, bool visible) {
  246 +void DsoWidget::setMeasurementVisible(ChannelID channel, bool visible) {
245 247 measurementNameLabel[channel]->setVisible(visible);
246 248 measurementMiscLabel[channel]->setVisible(visible);
247 249 measurementGainLabel[channel]->setVisible(visible);
... ... @@ -272,7 +274,7 @@ void DsoWidget::updateMarkerDetails() {
272 274 }
273 275  
274 276 /// \brief Update the label about the trigger settings
275   -void DsoWidget::updateSpectrumDetails(unsigned int channel) {
  277 +void DsoWidget::updateSpectrumDetails(ChannelID channel) {
276 278 setMeasurementVisible(channel, settings->scope.voltage[channel].used || settings->scope.spectrum[channel].used);
277 279  
278 280 if (settings->scope.spectrum[channel].used)
... ... @@ -299,13 +301,13 @@ void DsoWidget::updateTriggerDetails() {
299 301 }
300 302  
301 303 /// \brief Update the label about the trigger settings
302   -void DsoWidget::updateVoltageDetails(unsigned int channel) {
303   - if (channel >= (unsigned int)settings->scope.voltage.size()) return;
  304 +void DsoWidget::updateVoltageDetails(ChannelID channel) {
  305 + if (channel >= settings->scope.voltage.size()) return;
304 306  
305 307 setMeasurementVisible(channel, settings->scope.voltage[channel].used || settings->scope.spectrum[channel].used);
306 308  
307 309 if (settings->scope.voltage[channel].used)
308   - measurementGainLabel[channel]->setText(valueToString(settings->scope.voltage[channel].gain, UNIT_VOLTS, 3) +
  310 + measurementGainLabel[channel]->setText(valueToString(settings->scope.gain(channel), UNIT_VOLTS, 3) +
309 311 tr("/div"));
310 312 else
311 313 measurementGainLabel[channel]->setText(QString());
... ... @@ -355,12 +357,12 @@ void DsoWidget::updateTriggerSlope() { updateTriggerDetails(); }
355 357 /// \brief Handles sourceChanged signal from the trigger dock.
356 358 void DsoWidget::updateTriggerSource() {
357 359 // Change the colors of the trigger sliders
358   - if (settings->scope.trigger.special || settings->scope.trigger.source >= settings->scope.physicalChannels)
  360 + if (settings->scope.trigger.special || settings->scope.trigger.source >= settings->deviceSpecification->channels)
359 361 triggerPositionSlider->setColor(0, settings->view.screen.border);
360 362 else
361 363 triggerPositionSlider->setColor(0, settings->view.screen.voltage[settings->scope.trigger.source]);
362 364  
363   - for (int channel = 0; channel < (int)settings->scope.physicalChannels; ++channel)
  365 + for (int channel = 0; channel < (int)settings->deviceSpecification->channels; ++channel)
364 366 triggerLevelSlider->setColor(
365 367 channel,
366 368 (!settings->scope.trigger.special && channel == (int)settings->scope.trigger.source)
... ... @@ -375,13 +377,13 @@ void DsoWidget::updateTriggerSource() {
375 377 void DsoWidget::updateVoltageCoupling(unsigned int channel) {
376 378 if (channel >= (unsigned int)settings->scope.voltage.size()) return;
377 379  
378   - measurementMiscLabel[channel]->setText(Dso::couplingString(settings->scope.voltage[channel].coupling));
  380 + measurementMiscLabel[channel]->setText(Dso::couplingString(settings->coupling(channel)));
379 381 }
380 382  
381 383 /// \brief Handles modeChanged signal from the voltage dock.
382 384 void DsoWidget::updateMathMode() {
383   - measurementMiscLabel[settings->scope.physicalChannels]->setText(
384   - Dso::mathModeString(settings->scope.voltage[settings->scope.physicalChannels].math));
  385 + measurementMiscLabel[settings->deviceSpecification->channels]->setText(
  386 + Dso::mathModeString(settings->scope.voltage[settings->deviceSpecification->channels].math));
385 387 }
386 388  
387 389 /// \brief Handles gainChanged signal from the voltage dock.
... ... @@ -389,7 +391,7 @@ void DsoWidget::updateMathMode() {
389 391 void DsoWidget::updateVoltageGain(unsigned int channel) {
390 392 if (channel >= (unsigned int)settings->scope.voltage.size()) return;
391 393  
392   - if (channel < settings->scope.physicalChannels) adaptTriggerLevelSlider(channel);
  394 + if (channel < settings->deviceSpecification->channels) adaptTriggerLevelSlider(channel);
393 395  
394 396 updateVoltageDetails(channel);
395 397 }
... ... @@ -445,7 +447,8 @@ void DsoWidget::doShowNewData() {
445 447 exportNextFrame.reset(nullptr);
446 448 }
447 449  
448   - bool triggered = generator->generateGraphs(data.get());
  450 + bool triggered = generator->generateGraphs(data.get(), settings->view.digitalPhosphorDraws(),&settings->scope,settings->deviceSpecification->channels);
  451 +
449 452 QPalette triggerLabelPalette = palette();
450 453 triggerLabelPalette.setColor(QPalette::WindowText, Qt::black);
451 454 triggerLabelPalette.setColor(QPalette::Background, triggered ? Qt::green : Qt::red);
... ... @@ -453,8 +456,8 @@ void DsoWidget::doShowNewData() {
453 456  
454 457 updateRecordLength(data.get()->getMaxSamples());
455 458  
456   - for (int channel = 0; channel < (int)settings->scope.voltage.size(); ++channel) {
457   - if (settings->scope.voltage[(unsigned)channel].used && data.get()->data(channel)) {
  459 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  460 + if (settings->scope.voltage[channel].used && data.get()->data(channel)) {
458 461 // Amplitude string representation (4 significant digits)
459 462 measurementAmplitudeLabel[channel]->setText(
460 463 valueToString(data.get()->data(channel)->amplitude, UNIT_VOLTS, 4));
... ... @@ -468,11 +471,11 @@ void DsoWidget::doShowNewData() {
468 471 /// \brief Handles valueChanged signal from the offset sliders.
469 472 /// \param channel The channel whose offset was changed.
470 473 /// \param value The new offset for the channel.
471   -void DsoWidget::updateOffset(unsigned channel, double value) {
  474 +void DsoWidget::updateOffset(ChannelID channel, double value) {
472 475 if (channel < settings->scope.voltage.size()) {
473 476 settings->scope.voltage[channel].offset = value;
474 477  
475   - if (channel < settings->scope.physicalChannels) adaptTriggerLevelSlider(channel);
  478 + if (channel < settings->deviceSpecification->channels) adaptTriggerLevelSlider(channel);
476 479 } else if (channel < settings->scope.voltage.size() * 2)
477 480 settings->scope.spectrum[channel - settings->scope.voltage.size()].offset = value;
478 481  
... ...
openhantek/src/dsowidget.h
... ... @@ -31,12 +31,12 @@ class DsoWidget : public QWidget {
31 31 void showNewData(std::unique_ptr<DataAnalyzerResult> data);
32 32  
33 33 protected:
34   - void adaptTriggerLevelSlider(unsigned int channel);
35   - void setMeasurementVisible(unsigned int channel, bool visible);
  34 + void adaptTriggerLevelSlider(ChannelID channel);
  35 + void setMeasurementVisible(ChannelID channel, bool visible);
36 36 void updateMarkerDetails();
37   - void updateSpectrumDetails(unsigned int channel);
  37 + void updateSpectrumDetails(ChannelID channel);
38 38 void updateTriggerDetails();
39   - void updateVoltageDetails(unsigned int channel);
  39 + void updateVoltageDetails(ChannelID channel);
40 40  
41 41 QGridLayout *mainLayout; ///< The main layout for this widget
42 42 LevelSlider *offsetSlider; ///< The sliders for the graph offsets
... ... @@ -61,12 +61,12 @@ class DsoWidget : public QWidget {
61 61 QLabel *markerFrequencybaseLabel; ///< The frequencybase for the zoomed scope
62 62  
63 63 QGridLayout *measurementLayout; ///< The table for the signal details
64   - QList<QLabel *> measurementNameLabel; ///< The name of the channel
65   - QList<QLabel *> measurementGainLabel; ///< The gain for the voltage (V/div)
66   - QList<QLabel *> measurementMagnitudeLabel; ///< The magnitude for the spectrum (dB/div)
67   - QList<QLabel *> measurementMiscLabel; ///< Coupling or math mode
68   - QList<QLabel *> measurementAmplitudeLabel; ///< Amplitude of the signal (V)
69   - QList<QLabel *> measurementFrequencyLabel; ///< Frequency of the signal (Hz)
  64 + std::vector<QLabel *> measurementNameLabel; ///< The name of the channel
  65 + std::vector<QLabel *> measurementGainLabel; ///< The gain for the voltage (V/div)
  66 + std::vector<QLabel *> measurementMagnitudeLabel; ///< The magnitude for the spectrum (dB/div)
  67 + std::vector<QLabel *> measurementMiscLabel; ///< Coupling or math mode
  68 + std::vector<QLabel *> measurementAmplitudeLabel; ///< Amplitude of the signal (V)
  69 + std::vector<QLabel *> measurementFrequencyLabel; ///< Frequency of the signal (Hz)
70 70  
71 71 DsoSettings *settings; ///< The settings provided by the main window
72 72 GlGenerator *generator; ///< The generator for the OpenGL vertex arrays
... ... @@ -111,7 +111,7 @@ class DsoWidget : public QWidget {
111 111  
112 112 private slots:
113 113 // Sliders
114   - void updateOffset(unsigned channel, double value);
  114 + void updateOffset(ChannelID channel, double value);
115 115 void updateTriggerPosition(int index, double value);
116 116 void updateTriggerLevel(int channel, double value);
117 117 void updateMarker(int marker, double value);
... ...
openhantek/src/exporter.cpp
... ... @@ -20,6 +20,7 @@
20 20 #include "analyse/dataanalyzerresult.h"
21 21 #include "glgenerator.h"
22 22 #include "settings.h"
  23 +#include "viewconstants.h"
23 24 #include "utils/dsoStrings.h"
24 25 #include "utils/printutils.h"
25 26  
... ... @@ -145,16 +146,16 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) {
145 146 painter.setPen(colorValues->voltage[channel]);
146 147 painter.drawText(QRectF(0, top, lineHeight * 4, lineHeight), settings->scope.voltage[channel].name);
147 148 // Print coupling/math mode
148   - if ((unsigned int)channel < settings->scope.physicalChannels)
  149 + if ((unsigned int)channel < settings->deviceSpecification->channels)
149 150 painter.drawText(QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight),
150   - Dso::couplingString(settings->scope.voltage[channel].coupling));
  151 + Dso::couplingString(settings->coupling(channel)));
151 152 else
152 153 painter.drawText(QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight),
153 154 Dso::mathModeString(settings->scope.voltage[channel].math));
154 155  
155 156 // Print voltage gain
156 157 painter.drawText(QRectF(lineHeight * 6, top, stretchBase * 2, lineHeight),
157   - valueToString(settings->scope.voltage[channel].gain, UNIT_VOLTS, 0) + tr("/div"),
  158 + valueToString(settings->scope.gain(channel), UNIT_VOLTS, 0) + tr("/div"),
158 159 QTextOption(Qt::AlignRight));
159 160 // Print spectrum magnitude
160 161 if (settings->scope.spectrum[channel].used) {
... ... @@ -229,9 +230,9 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) {
229 230  
230 231 for (int zoomed = 0; zoomed < (settings->view.zoom ? 2 : 1); ++zoomed) {
231 232 switch (settings->scope.horizontal.format) {
232   - case Dso::GRAPHFORMAT_TY:
  233 + case Dso::GraphFormat::TY:
233 234 // Add graphs for channels
234   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  235 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
235 236 if (settings->scope.voltage[channel].used && result->data(channel)) {
236 237 painter.setPen(QPen(colorValues->voltage[channel], 0));
237 238  
... ... @@ -257,7 +258,7 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) {
257 258 for (unsigned int position = firstPosition; position <= lastPosition; ++position)
258 259 graph[position - firstPosition] = QPointF(position * horizontalFactor - DIVS_TIME / 2,
259 260 result->data(channel)->voltage.sample[position] /
260   - settings->scope.voltage[channel].gain +
  261 + settings->scope.gain(channel) +
261 262 settings->scope.voltage[channel].offset);
262 263  
263 264 painter.drawPolyline(graph, lastPosition - firstPosition + 1);
... ... @@ -266,7 +267,7 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) {
266 267 }
267 268  
268 269 // Add spectrum graphs
269   - for (unsigned channel = 0; channel < settings->scope.spectrum.size(); ++channel) {
  270 + for (ChannelID channel = 0; channel < settings->scope.spectrum.size(); ++channel) {
270 271 if (settings->scope.spectrum[channel].used && result->data(channel)) {
271 272 painter.setPen(QPen(colorValues->spectrum[channel], 0));
272 273  
... ... @@ -302,7 +303,7 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) {
302 303 }
303 304 break;
304 305  
305   - case Dso::GRAPHFORMAT_XY:
  306 + case Dso::GraphFormat::XY:
306 307 break;
307 308  
308 309 default:
... ...
openhantek/src/glgenerator.cpp
1 1 // SPDX-License-Identifier: GPL-2.0+
2 2  
3 3 #include <QMutex>
  4 +#include <QDebug>
4 5  
5 6 #include "glgenerator.h"
6 7 #include "utils/printutils.h"
7 8 #include "settings.h"
  9 +#include "analyse/dataanalyzerresult.h"
  10 +#include "viewconstants.h"
  11 +#include "hantekdso/softwaretrigger.h"
8 12  
9   -GlGenerator::GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view) : settings(scope), view(view) {
  13 +static const SampleValues& useSamplesOf(Dso::ChannelMode mode, ChannelID channel, const DataAnalyzerResult *result, const DsoSettingsScope *scope) {
  14 + static SampleValues emptyDefault;
  15 + if (mode == Dso::ChannelMode::Voltage) {
  16 + if (!scope->voltage[channel].used || !result->data(channel)) return emptyDefault;
  17 + return result->data(channel)->voltage;
  18 + } else {
  19 + if (!scope->spectrum[channel].used || !result->data(channel)) return emptyDefault;
  20 + return result->data(channel)->spectrum;
  21 + }
  22 +}
  23 +
  24 +GlGenerator::GlGenerator() {
10 25 // Grid
11 26 const int DIVS_TIME_S2 = (int)DIVS_TIME - 2;
12 27 const int DIVS_VOLTAGE_S2 = (int)DIVS_VOLTAGE - 2;
... ... @@ -97,109 +112,24 @@ GlGenerator::GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view) : setti
97 112 *(glIterator++) = DIVS_VOLTAGE / 2;
98 113 }
99 114  
100   -const std::vector<GLfloat> &GlGenerator::channel(int mode, unsigned channel, unsigned index) const {
101   - return vaChannel[mode][channel][index];
  115 +const std::vector<GLfloat> &GlGenerator::channel(Dso::ChannelMode mode, ChannelID channel, unsigned index) const {
  116 + return vaChannel[(unsigned)mode][channel][index];
102 117 }
103 118  
104 119 const std::vector<GLfloat> &GlGenerator::grid(int a) const { return vaGrid[a]; }
105 120  
106 121 bool GlGenerator::isReady() const { return ready; }
107 122  
108   -GlGenerator::PrePostStartTriggerSamples GlGenerator::computeSoftwareTriggerTY(const DataAnalyzerResult *result)
109   -{
110   - unsigned int preTrigSamples = 0;
111   - unsigned int postTrigSamples = 0;
112   - unsigned int swTriggerStart = 0;
113   - unsigned int channel = settings->trigger.source;
114   -
115   - // check trigger point for software trigger
116   - if (settings->trigger.mode != Dso::TRIGGERMODE_SOFTWARE || channel >= settings->physicalChannels)
117   - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
118   -
119   - // Trigger channel not in use
120   - if (!settings->voltage[channel].used || !result->data(channel) ||
121   - result->data(channel)->voltage.sample.empty())
122   - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
123   -
124   - const std::vector<double>& samples = result->data(channel)->voltage.sample;
125   - double level = settings->voltage[channel].trigger;
126   - size_t sampleCount = samples.size();
127   - double timeDisplay = settings->horizontal.timebase * DIVS_TIME;
128   - double samplesDisplay = timeDisplay * settings->horizontal.samplerate;
129   - if (samplesDisplay >= sampleCount) {
130   - // For sure not enough samples to adjust for jitter.
131   - // Following options exist:
132   - // 1: Decrease sample rate
133   - // 2: Change trigger mode to auto
134   - // 3: Ignore samples
135   - // For now #3 is chosen
136   - timestampDebug(QString("Too few samples to make a steady "
137   - "picture. Decrease sample rate"));
138   - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
139   - }
140   - preTrigSamples = (unsigned)(settings->trigger.position * samplesDisplay);
141   - postTrigSamples = (unsigned)sampleCount - ((unsigned)samplesDisplay - preTrigSamples);
142   -
143   - const int swTriggerThreshold = 7;
144   - const int swTriggerSampleSet = 11;
145   - double prev;
146   - bool (*opcmp)(double,double,double);
147   - bool (*smplcmp)(double,double);
148   - if (settings->trigger.slope == Dso::SLOPE_POSITIVE) {
149   - prev = INT_MAX;
150   - opcmp = [](double value, double level, double prev) { return value > level && prev <= level;};
151   - smplcmp = [](double sampleK, double value) { return sampleK >= value;};
152   - } else {
153   - prev = INT_MIN;
154   - opcmp = [](double value, double level, double prev) { return value < level && prev >= level;};
155   - smplcmp = [](double sampleK, double value) { return sampleK < value;};
156   - }
157   -
158   - for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) {
159   - double value = samples[i];
160   - if (opcmp(value, level, prev)) {
161   - int rising = 0;
162   - for (unsigned int k = i + 1; k < i + swTriggerSampleSet && k < sampleCount; k++) {
163   - if (smplcmp(samples[k], value)) { rising++; }
164   - }
165   - if (rising > swTriggerThreshold) {
166   - swTriggerStart = i;
167   - break;
168   - }
169   - }
170   - prev = value;
171   - }
172   - if (swTriggerStart == 0) {
173   - timestampDebug(QString("Trigger not asserted. Data ignored"));
174   - preTrigSamples = 0; // preTrigSamples may never be greater than swTriggerStart
175   - postTrigSamples = 0;
176   - }
177   - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
178   -}
179   -
180   -const SampleValues& GlGenerator::useSamplesOf(int mode, unsigned channel, const DataAnalyzerResult *result) const
181   -{
182   - static SampleValues emptyDefault;
183   - if (mode == Dso::CHANNELMODE_VOLTAGE) {
184   - if (!settings->voltage[channel].used || !result->data(channel)) return emptyDefault;
185   - return result->data(channel)->voltage;
186   - } else {
187   - if (!settings->spectrum[channel].used || !result->data(channel)) return emptyDefault;
188   - return result->data(channel)->spectrum;
189   - }
190   -}
191   -
192   -bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
193   -
194   - unsigned digitalPhosphorDepth = view->digitalPhosphor ? view->digitalPhosphorDepth : 1;
  123 +bool GlGenerator::generateGraphs(const DataAnalyzerResult *result, unsigned digitalPhosphorDepth,
  124 + const DsoSettingsScope *scope, unsigned physicalChannels) {
195 125  
196 126 // Handle all digital phosphor related list manipulations
197   - for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
198   - DrawLinesWithHistoryPerChannel& d = vaChannel[mode];
  127 + for (Dso::ChannelMode mode: Dso::ChannelModeEnum) {
  128 + DrawLinesWithHistoryPerChannel& d = vaChannel[(unsigned)mode];
199 129 // Resize to the number of channels
200   - d.resize(settings->voltage.size());
  130 + d.resize(scope->voltage.size());
201 131  
202   - for (unsigned int channel = 0; channel < vaChannel[mode].size(); ++channel) {
  132 + for (unsigned int channel = 0; channel < vaChannel[(unsigned)mode].size(); ++channel) {
203 133 DrawLinesWithHistory& drawLinesHistory = d[channel];
204 134 // Move the last list element to the front
205 135 if (digitalPhosphorDepth > 1 && drawLinesHistory.size())
... ... @@ -216,16 +146,18 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
216 146 unsigned postTrigSamples=0;
217 147 unsigned swTriggerStart=0;
218 148 bool triggered = false;
219   - switch (settings->horizontal.format) {
220   - case Dso::GRAPHFORMAT_TY:
221   - std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = computeSoftwareTriggerTY(result);
  149 +
  150 + switch (scope->horizontal.format) {
  151 + case Dso::GraphFormat::TY:
  152 + std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = SoftwareTrigger::computeTY(result, scope, physicalChannels);
222 153 triggered = postTrigSamples > preTrigSamples;
  154 +
223 155 // Add graphs for channels
224   - for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
225   - DrawLinesWithHistoryPerChannel& dPerChannel = vaChannel[mode];
226   - for (unsigned channel = 0; channel < settings->voltage.size(); ++channel) {
  156 + for (Dso::ChannelMode mode: Dso::ChannelModeEnum) {
  157 + DrawLinesWithHistoryPerChannel& dPerChannel = vaChannel[(unsigned)mode];
  158 + for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {
227 159 DrawLinesWithHistory& withHistory = dPerChannel[channel];
228   - const SampleValues& samples = useSamplesOf(mode, channel, result);
  160 + const SampleValues& samples = useSamplesOf(mode, channel, result, scope);
229 161  
230 162 // Check if this channel is used and available at the data analyzer
231 163 if (samples.sample.empty()) {
... ... @@ -236,10 +168,11 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
236 168 }
237 169 // Check if the sample count has changed
238 170 size_t sampleCount = samples.sample.size();
239   - if (sampleCount>9000) {
240   - throw new std::runtime_error("");
  171 + if (sampleCount>500000) {
  172 + qWarning() << "Sample count too high!";
  173 + throw new std::runtime_error("Sample count too high!");
241 174 }
242   - if (mode == Dso::CHANNELMODE_VOLTAGE)
  175 + if (mode == Dso::ChannelMode::Voltage)
243 176 sampleCount -= (swTriggerStart - preTrigSamples);
244 177 size_t neededSize = sampleCount * 2;
245 178  
... ... @@ -258,17 +191,17 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
258 191  
259 192 // What's the horizontal distance between sampling points?
260 193 float horizontalFactor;
261   - if (mode == Dso::CHANNELMODE_VOLTAGE)
262   - horizontalFactor = (float)(samples.interval / settings->horizontal.timebase);
  194 + if (mode == Dso::ChannelMode::Voltage)
  195 + horizontalFactor = (float)(samples.interval / scope->horizontal.timebase);
263 196 else
264   - horizontalFactor = (float)(samples.interval / settings->horizontal.frequencybase);
  197 + horizontalFactor = (float)(samples.interval / scope->horizontal.frequencybase);
265 198  
266 199 // Fill vector array
267   - if (mode == Dso::CHANNELMODE_VOLTAGE) {
  200 + if (mode == Dso::ChannelMode::Voltage) {
268 201 std::vector<double>::const_iterator dataIterator = samples.sample.begin();
269   - const float gain = (float) settings->voltage[channel].gain;
270   - const float offset = (float) settings->voltage[channel].offset;
271   - const float invert = settings->voltage[channel].inverted ? -1.0f : 1.0f;
  202 + const float gain = (float) scope->gain(channel);
  203 + const float offset = (float) scope->voltage[channel].offset;
  204 + const float invert = scope->voltage[channel].inverted ? -1.0f : 1.0f;
272 205  
273 206 std::advance(dataIterator, swTriggerStart - preTrigSamples);
274 207  
... ... @@ -278,8 +211,8 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
278 211 }
279 212 } else {
280 213 std::vector<double>::const_iterator dataIterator = samples.sample.begin();
281   - const float magnitude = (float)settings->spectrum[channel].magnitude;
282   - const float offset = (float)settings->spectrum[channel].offset;
  214 + const float magnitude = (float)scope->spectrum[channel].magnitude;
  215 + const float offset = (float)scope->spectrum[channel].offset;
283 216  
284 217 for (unsigned int position = 0; position < sampleCount; ++position) {
285 218 *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2;
... ... @@ -290,19 +223,19 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
290 223 }
291 224 break;
292 225  
293   - case Dso::GRAPHFORMAT_XY:
  226 + case Dso::GraphFormat::XY:
294 227 triggered = true;
295   - for (unsigned channel = 0; channel < settings->voltage.size(); ++channel) {
  228 + for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) {
296 229 // For even channel numbers check if this channel is used and this and the
297 230 // following channel are available at the data analyzer
298   - if (channel % 2 == 0 && channel + 1 < settings->voltage.size() && settings->voltage[channel].used &&
  231 + if (channel % 2 == 0 && channel + 1 < scope->voltage.size() && scope->voltage[channel].used &&
299 232 result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) &&
300 233 !result->data(channel + 1)->voltage.sample.empty()) {
301 234 // Check if the sample count has changed
302 235 const size_t sampleCount = std::min(result->data(channel)->voltage.sample.size(),
303 236 result->data(channel + 1)->voltage.sample.size());
304 237 const size_t neededSize = sampleCount * 2;
305   - DrawLinesWithHistory& withHistory = vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel];
  238 + DrawLinesWithHistory& withHistory = vaChannel[(unsigned)Dso::ChannelMode::Voltage][(size_t)channel];
306 239 for (unsigned index = 0; index < digitalPhosphorDepth; ++index) {
307 240 if (withHistory[index].size() != neededSize)
308 241 withHistory[index].clear(); // Something was changed, drop old traces
... ... @@ -320,12 +253,12 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
320 253 unsigned int yChannel = channel + 1;
321 254 std::vector<double>::const_iterator xIterator = result->data(xChannel)->voltage.sample.begin();
322 255 std::vector<double>::const_iterator yIterator = result->data(yChannel)->voltage.sample.begin();
323   - const double xGain = settings->voltage[xChannel].gain;
324   - const double yGain = settings->voltage[yChannel].gain;
325   - const double xOffset = settings->voltage[xChannel].offset;
326   - const double yOffset = settings->voltage[yChannel].offset;
327   - const double xInvert = settings->voltage[xChannel].inverted ? -1.0 : 1.0;
328   - const double yInvert = settings->voltage[yChannel].inverted ? -1.0 : 1.0;
  256 + const double xGain = scope->gain(xChannel);
  257 + const double yGain = scope->gain(yChannel);
  258 + const double xOffset = scope->voltage[xChannel].offset;
  259 + const double yOffset = scope->voltage[yChannel].offset;
  260 + const double xInvert = scope->voltage[xChannel].inverted ? -1.0 : 1.0;
  261 + const double yInvert = scope->voltage[yChannel].inverted ? -1.0 : 1.0;
329 262  
330 263 for (unsigned int position = 0; position < sampleCount; ++position) {
331 264 *(glIterator++) = (GLfloat)( *(xIterator++) / xGain * xInvert + xOffset);
... ... @@ -333,18 +266,15 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) {
333 266 }
334 267 } else {
335 268 // Delete all vector arrays
336   - for (unsigned int index = 0; index < (unsigned)digitalPhosphorDepth; ++index)
337   - vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel][index].clear();
  269 + for (unsigned index = 0; index < digitalPhosphorDepth; ++index)
  270 + vaChannel[(unsigned)Dso::ChannelMode::Voltage][channel][index].clear();
338 271 }
339 272  
340 273 // Delete all spectrum graphs
341   - for (unsigned int index = 0; index < (unsigned)digitalPhosphorDepth; ++index)
342   - vaChannel[Dso::CHANNELMODE_SPECTRUM][(size_t)channel][index].clear();
  274 + for (unsigned index = 0; index < digitalPhosphorDepth; ++index)
  275 + vaChannel[(unsigned)Dso::ChannelMode::Spectrum][channel][index].clear();
343 276 }
344 277 break;
345   -
346   - default:
347   - break;
348 278 }
349 279  
350 280 emit graphsGenerated();
... ...
openhantek/src/glgenerator.h
... ... @@ -7,11 +7,11 @@
7 7 #include <QGLFunctions>
8 8 #include <QObject>
9 9  
10   -#include "analyse/dataanalyzerresult.h"
11   -#include "scopesettings.h"
12   -#include "viewconstants.h"
13   -#include "viewsettings.h"
14   -class GlScope;
  10 +#include "hantekdso/enums.h"
  11 +#include "hantekprotocol/definitions.h"
  12 +
  13 +struct DsoSettingsScope;
  14 +class DataAnalyzerResult;
15 15  
16 16 ////////////////////////////////////////////////////////////////////////////////
17 17 /// \class GlGenerator
... ... @@ -23,26 +23,22 @@ class GlGenerator : public QObject {
23 23 /// \brief Initializes the scope widget.
24 24 /// \param settings The target settings object.
25 25 /// \param parent The parent widget.
26   - GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view);
27   - bool generateGraphs(const DataAnalyzerResult *result);
28   - const std::vector<GLfloat> &channel(int mode, unsigned channel, unsigned index) const;
  26 +
  27 + GlGenerator();
  28 + bool generateGraphs(const DataAnalyzerResult *result, unsigned digitalPhosphorDepth, const DsoSettingsScope *scope,
  29 + unsigned physicalChannels);
  30 + const std::vector<GLfloat> &channel(Dso::ChannelMode mode, ChannelID channel, unsigned index) const;
  31 +
29 32 const std::vector<GLfloat> &grid(int a) const;
30 33 bool isReady() const;
31 34  
32 35 private:
33   - typedef std::tuple<unsigned,unsigned,unsigned> PrePostStartTriggerSamples;
34 36 typedef std::vector<GLfloat> DrawLines;
35 37 typedef std::deque<DrawLines> DrawLinesWithHistory;
36 38 typedef std::vector<DrawLinesWithHistory> DrawLinesWithHistoryPerChannel;
37   - DrawLinesWithHistoryPerChannel vaChannel[Dso::CHANNELMODE_COUNT];
38   -
39   - PrePostStartTriggerSamples computeSoftwareTriggerTY(const DataAnalyzerResult *result);
40   - DsoSettingsScope *settings;
41   - DsoSettingsView *view;
  39 + DrawLinesWithHistoryPerChannel vaChannel[Dso::ChannelModes];
42 40 std::vector<GLfloat> vaGrid[3];
43 41 bool ready = false;
44   -
45   - const SampleValues &useSamplesOf(int mode, unsigned channel, const DataAnalyzerResult *result) const;
46 42 signals:
47 43 void graphsGenerated(); ///< The graphs are ready to be drawn
48 44 };
... ...
openhantek/src/glscope.cpp
... ... @@ -8,13 +8,13 @@
8 8  
9 9 #include "glgenerator.h"
10 10 #include "settings.h"
  11 +#include "viewconstants.h"
11 12  
12 13 GlScope::GlScope(DsoSettings *settings, const GlGenerator *generator, QWidget *parent)
13 14 : GL_WIDGET_CLASS(parent), settings(settings), generator(generator) {
14 15 connect(generator, &GlGenerator::graphsGenerated, [this]() { update(); });
15 16 }
16 17  
17   -/// \brief Initializes OpenGL output.
18 18 void GlScope::initializeGL() {
19 19 glDisable(GL_DEPTH_TEST);
20 20 glEnable(GL_BLEND);
... ... @@ -23,7 +23,7 @@ void GlScope::initializeGL() {
23 23 glPointSize(1);
24 24  
25 25 QColor bg = settings->view.screen.background;
26   - glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF());
  26 + glClearColor((GLfloat)bg.redF(), (GLfloat)bg.greenF(), (GLfloat)bg.blueF(), (GLfloat)bg.alphaF());
27 27  
28 28 glShadeModel(GL_SMOOTH /*GL_FLAT*/);
29 29 glLineStipple(1, 0x3333);
... ... @@ -31,20 +31,18 @@ void GlScope::initializeGL() {
31 31 glEnableClientState(GL_VERTEX_ARRAY);
32 32 }
33 33  
34   -/// \brief Draw the graphs and the grid.
35 34 void GlScope::paintGL() {
36 35 // Clear OpenGL buffer and configure settings
37 36 glClear(GL_COLOR_BUFFER_BIT);
38 37 glLineWidth(1);
39 38  
40   - int digitalPhosphorDepth = settings->view.digitalPhosphor ? settings->view.digitalPhosphorDepth : 1;
41   - if (generator->isReady()) { drawGraph(digitalPhosphorDepth); }
  39 + if (generator->isReady()) { drawGraph(settings->view.digitalPhosphorDraws()); }
42 40  
43 41 if (!this->zoomed) {
44 42 // Draw vertical lines at marker positions
45 43 glEnable(GL_LINE_STIPPLE);
46 44 QColor trColor = settings->view.screen.markers;
47   - glColor4f(trColor.redF(), trColor.greenF(), trColor.blueF(), trColor.alphaF());
  45 + glColor4f((GLfloat)trColor.redF(), (GLfloat)trColor.greenF(), (GLfloat)trColor.blueF(), (GLfloat)trColor.alphaF());
48 46  
49 47 for (int marker = 0; marker < MARKER_COUNT; ++marker) {
50 48 if (!settings->scope.horizontal.marker_visible[marker]) continue;
... ... @@ -54,11 +52,11 @@ void GlScope::paintGL() {
54 52 vaMarker[marker][3] = DIVS_VOLTAGE;
55 53 }
56 54  
57   - vaMarker[marker][0] = settings->scope.horizontal.marker[marker];
58   - vaMarker[marker][2] = settings->scope.horizontal.marker[marker];
  55 + vaMarker[marker][0] = (GLfloat)settings->scope.horizontal.marker[marker];
  56 + vaMarker[marker][2] = (GLfloat)settings->scope.horizontal.marker[marker];
59 57  
60 58 glVertexPointer(2, GL_FLOAT, 0, &vaMarker[marker].front());
61   - glDrawArrays(GL_LINES, 0, vaMarker[marker].size() / 2);
  59 + glDrawArrays(GL_LINES, 0, (GLsizei)vaMarker[marker].size() / 2);
62 60 }
63 61  
64 62 glDisable(GL_LINE_STIPPLE);
... ... @@ -68,9 +66,6 @@ void GlScope::paintGL() {
68 66 this->drawGrid();
69 67 }
70 68  
71   -/// \brief Resize the widget.
72   -/// \param width The new width of the widget.
73   -/// \param height The new height of the widget.
74 69 void GlScope::resizeGL(int width, int height) {
75 70 glViewport(0, 0, (GLint)width, (GLint)height);
76 71  
... ... @@ -80,8 +75,8 @@ void GlScope::resizeGL(int width, int height) {
80 75 glLoadIdentity();
81 76 GLdouble pixelizationWidthCorrection = (width > 0) ? (GLdouble)width / (width - 1) : 1;
82 77 GLdouble pixelizationHeightCorrection = (height > 0) ? (GLdouble)height / (height - 1) : 1;
83   - glOrtho(-(DIVS_TIME / 2) * pixelizationWidthCorrection, (DIVS_TIME / 2) * pixelizationWidthCorrection,
84   - -(DIVS_VOLTAGE / 2) * pixelizationHeightCorrection, (DIVS_VOLTAGE / 2) * pixelizationHeightCorrection, -1.0,
  78 + glOrtho(-(DIVS_TIME / 2.0) * pixelizationWidthCorrection, (DIVS_TIME / 2.0) * pixelizationWidthCorrection,
  79 + -(DIVS_VOLTAGE / 2.0) * pixelizationHeightCorrection, (DIVS_VOLTAGE / 2.0) * pixelizationHeightCorrection, -1.0,
85 80 1.0);
86 81  
87 82 glMatrixMode(GL_MODELVIEW);
... ... @@ -89,9 +84,8 @@ void GlScope::resizeGL(int width, int height) {
89 84  
90 85 /// \brief Set the zoom mode for this GlScope.
91 86 /// \param zoomed true magnifies the area between the markers.
92   -void GlScope::setZoomMode(bool zoomed) { this->zoomed = zoomed; }
  87 +void GlScope::setZoomMode(bool zoomEnabled) { this->zoomed = zoomEnabled; }
93 88  
94   -/// \brief Draw the grid.
95 89 void GlScope::drawGrid() {
96 90 glDisable(GL_POINT_SMOOTH);
97 91 glDisable(GL_LINE_SMOOTH);
... ... @@ -99,35 +93,35 @@ void GlScope::drawGrid() {
99 93 QColor color;
100 94 // Grid
101 95 color = settings->view.screen.grid;
102   - glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
  96 + glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF());
103 97 glVertexPointer(2, GL_FLOAT, 0, &generator->grid(0).front());
104   - glDrawArrays(GL_POINTS, 0, generator->grid(0).size() / 2);
  98 + glDrawArrays(GL_POINTS, 0, (GLsizei) generator->grid(0).size() / 2);
105 99 // Axes
106 100 color = settings->view.screen.axes;
107   - glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
  101 + glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF());
108 102 glVertexPointer(2, GL_FLOAT, 0, &generator->grid(1).front());
109   - glDrawArrays(GL_LINES, 0, generator->grid(1).size() / 2);
  103 + glDrawArrays(GL_LINES, 0, (GLsizei) generator->grid(1).size() / 2);
110 104 // Border
111 105 color = settings->view.screen.border;
112   - glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF());
  106 + glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF());
113 107 glVertexPointer(2, GL_FLOAT, 0, &generator->grid(2).front());
114   - glDrawArrays(GL_LINE_LOOP, 0, generator->grid(2).size() / 2);
  108 + glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) generator->grid(2).size() / 2);
115 109 }
116 110  
117   -void GlScope::drawGraphDepth(int mode, int channel, int index) {
  111 +void GlScope::drawGraphDepth(Dso::ChannelMode mode, ChannelID channel, unsigned index) {
118 112 if (generator->channel(mode, channel, index).empty()) return;
119 113 QColor trColor;
120   - if (mode == Dso::CHANNELMODE_VOLTAGE)
  114 + if (mode == Dso::ChannelMode::Voltage)
121 115 trColor = settings->view.screen.voltage[channel].darker(fadingFactor[index]);
122 116 else
123 117 trColor = settings->view.screen.spectrum[channel].darker(fadingFactor[index]);
124   - glColor4f(trColor.redF(), trColor.greenF(), trColor.blueF(), trColor.alphaF());
  118 + glColor4f((GLfloat)trColor.redF(), (GLfloat)trColor.greenF(), (GLfloat)trColor.blueF(), (GLfloat)trColor.alphaF());
125 119 glVertexPointer(2, GL_FLOAT, 0, &generator->channel(mode, channel, index).front());
126 120 glDrawArrays((settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0,
127   - generator->channel(mode, channel, index).size() / 2);
  121 + (GLsizei)generator->channel(mode, channel, index).size() / 2);
128 122 }
129 123  
130   -void GlScope::drawGraph(int digitalPhosphorDepth) {
  124 +void GlScope::drawGraph(unsigned digitalPhosphorDepth) {
131 125 if (settings->view.antialiasing) {
132 126 glEnable(GL_POINT_SMOOTH);
133 127 glEnable(GL_LINE_SMOOTH);
... ... @@ -137,57 +131,53 @@ void GlScope::drawGraph(int digitalPhosphorDepth) {
137 131 // Apply zoom settings via matrix transformation
138 132 if (this->zoomed) {
139 133 glPushMatrix();
140   - glScalef(DIVS_TIME / fabs(settings->scope.horizontal.marker[1] - settings->scope.horizontal.marker[0]), 1.0,
141   - 1.0);
142   - glTranslatef(-(settings->scope.horizontal.marker[0] + settings->scope.horizontal.marker[1]) / 2, 0.0, 0.0);
  134 + glScalef(DIVS_TIME / (GLfloat)fabs(settings->scope.horizontal.marker[1] - settings->scope.horizontal.marker[0]), 1.0f,
  135 + 1.0f);
  136 + glTranslatef((GLfloat)-(settings->scope.horizontal.marker[0] + settings->scope.horizontal.marker[1]) / 2, 0.0f, 0.0f);
143 137 }
144 138  
145 139 // Values we need for the fading of the digital phosphor
146   - if ((int)fadingFactor.size() != digitalPhosphorDepth) {
147   - fadingFactor.resize((size_t)digitalPhosphorDepth);
  140 + if (fadingFactor.size() != digitalPhosphorDepth) {
  141 + fadingFactor.resize(digitalPhosphorDepth);
148 142 fadingFactor[0] = 100;
149 143 double fadingRatio = pow(10.0, 2.0 / digitalPhosphorDepth);
150 144 for (size_t index = 1; index < (size_t)digitalPhosphorDepth; ++index)
151   - fadingFactor[index] = fadingFactor[index - 1] * fadingRatio;
  145 + fadingFactor[index] = int(fadingFactor[index - 1] * fadingRatio);
152 146 }
153 147  
154 148 switch (settings->scope.horizontal.format) {
155   - case Dso::GRAPHFORMAT_TY:
  149 + case Dso::GraphFormat::TY:
156 150 // Real and virtual channels
157   - for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
158   - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) {
  151 + for (Dso::ChannelMode mode: Dso::ChannelModeEnum) {
  152 + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) {
159 153 if (!channelUsed(mode, channel)) continue;
160 154  
161 155 // Draw graph for all available depths
162   - for (int index = digitalPhosphorDepth - 1; index >= 0; index--) {
163   - drawGraphDepth(mode, channel, index);
  156 + for (unsigned index = digitalPhosphorDepth; index > 0; index--) {
  157 + drawGraphDepth(mode, channel, index-1);
164 158 }
165 159 }
166 160 }
167 161 break;
168   -
169   - case Dso::GRAPHFORMAT_XY:
  162 + case Dso::GraphFormat::XY:
  163 + const Dso::ChannelMode mode = Dso::ChannelMode::Voltage;
170 164 // Real and virtual channels
171   - for (int channel = 0; channel < settings->scope.voltage.size() - 1; channel += 2) {
172   - if (settings->scope.voltage[channel].used) {
173   - for (int index = digitalPhosphorDepth - 1; index >= 0; index--) {
174   - drawGraphDepth(Dso::CHANNELMODE_VOLTAGE, channel, index);
175   - }
  165 + for (ChannelID channel = 0; channel < settings->scope.voltage.size() - 1; channel += 2) {
  166 + if (!channelUsed(mode, channel)) continue;
  167 + for (unsigned index = digitalPhosphorDepth; index > 0; index--) {
  168 + drawGraphDepth(mode, channel, index-1);
176 169 }
177 170 }
178 171 break;
179   -
180   - default:
181   - break;
182 172 }
183 173  
184 174 glDisable(GL_POINT_SMOOTH);
185 175 glDisable(GL_LINE_SMOOTH);
186 176  
187   - if (this->zoomed) glPopMatrix();
  177 + if (zoomed) glPopMatrix();
188 178 }
189 179  
190   -bool GlScope::channelUsed(int mode, int channel) {
191   - return (mode == Dso::CHANNELMODE_VOLTAGE) ? settings->scope.voltage[channel].used
  180 +bool GlScope::channelUsed(Dso::ChannelMode mode, ChannelID channel) {
  181 + return (mode == Dso::ChannelMode::Voltage) ? settings->scope.voltage[channel].used
192 182 : settings->scope.spectrum[channel].used;
193 183 }
... ...
openhantek/src/glscope.h
... ... @@ -5,6 +5,7 @@
5 5 #include <QMetaObject>
6 6 #include <QtGlobal>
7 7 #include <array>
  8 +
8 9 #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0))
9 10 #include <QOpenGLWidget>
10 11 using GL_WIDGET_CLASS = QOpenGLWidget;
... ... @@ -13,11 +14,12 @@ using GL_WIDGET_CLASS = QOpenGLWidget;
13 14 using GL_WIDGET_CLASS = QGLWidget;
14 15 #endif
15 16  
  17 +#include "hantekdso/enums.h"
  18 +#include "hantekprotocol/definitions.h"
  19 +
16 20 class GlGenerator;
17 21 class DsoSettings;
18 22  
19   -////////////////////////////////////////////////////////////////////////////////
20   -/// \class GlScope glscope.h
21 23 /// \brief OpenGL accelerated widget that displays the oscilloscope screen.
22 24 class GlScope : public GL_WIDGET_CLASS {
23 25 Q_OBJECT
... ... @@ -28,22 +30,37 @@ class GlScope : public GL_WIDGET_CLASS {
28 30 /// \param parent The parent widget.
29 31 GlScope(DsoSettings *settings, const GlGenerator *generator, QWidget *parent = 0);
30 32  
31   - void setZoomMode(bool zoomed);
  33 + void setZoomMode(bool zoomEnabled);
32 34  
33 35 protected:
  36 + /// \brief Initializes OpenGL output.
34 37 void initializeGL() override;
  38 +
  39 + /// \brief Draw the graphs and the grid.
35 40 void paintGL() override;
  41 +
  42 + /// \brief Resize the widget.
  43 + /// \param width The new width of the widget.
  44 + /// \param height The new height of the widget.
36 45 void resizeGL(int width, int height) override;
37 46  
  47 + /// \brief Draw the grid.
38 48 void drawGrid();
39   - void drawGraphDepth(int mode, int channel, int index);
40   - void drawGraph(int digitalPhosphorDepth);
41   - bool channelUsed(int mode, int channel);
  49 +
  50 + void drawGraphDepth(Dso::ChannelMode mode, ChannelID channel, unsigned index);
  51 + void drawGraph(unsigned digitalPhosphorDepth);
  52 +
  53 + /**
  54 + * @brief Return true if the given channel with the given mode is used
  55 + * @param mode The channel mode (spectrum/voltage)
  56 + * @param channel The channel
  57 + */
  58 + bool channelUsed(Dso::ChannelMode mode, ChannelID channel);
42 59  
43 60 private:
44 61 DsoSettings *settings;
45 62 const GlGenerator *generator;
46   - std::vector<double> fadingFactor;
  63 + std::vector<int> fadingFactor;
47 64  
48 65 std::vector<GLfloat> vaMarker[2];
49 66 bool zoomed = false;
... ...
openhantek/src/hantekdso/controlindexes.h deleted
1   -// SPDX-License-Identifier: GPL-2.0+
2   -
3   -#pragma once
4   -
5   -namespace Hantek {
6   -
7   -//////////////////////////////////////////////////////////////////////////////
8   -/// \enum ControlIndex
9   -/// \brief The array indices for the waiting control commands.
10   -enum ControlIndex {
11   - CONTROLINDEX_SETOFFSET,
12   - CONTROLINDEX_SETRELAYS,
13   - CONTROLINDEX_SETVOLTDIV_CH1,
14   - CONTROLINDEX_SETVOLTDIV_CH2,
15   - CONTROLINDEX_SETTIMEDIV, ///< For 6022BL/BE
16   - CONTROLINDEX_ACQUIIRE_HARD_DATA, ///< For 6022BL/BE
17   - CONTROLINDEX_COUNT
18   -};
19   -
20   -}
openhantek/src/hantekdso/controlsettings.cpp
1 1 #include "controlsettings.h"
2 2  
3   -namespace Hantek {
  3 +namespace Dso {
4 4  
5 5 ControlSettings::ControlSettings(ControlSamplerateLimits* limits, size_t channelCount)
6 6 {
7 7 samplerate.limits = limits;
8 8 trigger.level.resize(channelCount);
9 9 voltage.resize(channelCount);
10   - for (unsigned channel = 0; channel < channelCount; ++channel) {
  10 + for (ChannelID channel = 0; channel < channelCount; ++channel) {
11 11 trigger.level[channel] = 0.0;
12 12 voltage[channel].gain = 0;
13 13 voltage[channel].offset = 0.0;
... ...
openhantek/src/hantekdso/controlsettings.h
1 1 #pragma once
2 2  
  3 +#include "controlspecification.h"
3 4 #include "enums.h"
4 5  
5   -namespace Hantek {
  6 +namespace Dso {
6 7  
7 8 struct ControlSamplerateLimits;
8 9  
... ... @@ -10,9 +11,9 @@ struct ControlSamplerateLimits;
10 11 /// \struct ControlSettingsSamplerateTarget hantek/control.h
11 12 /// \brief Stores the target samplerate settings of the device.
12 13 struct ControlSettingsSamplerateTarget {
13   - double samplerate; ///< The target samplerate set via setSamplerate
14   - double duration; ///< The target record time set via setRecordTime
15   - bool samplerateSet; ///< true means samplerate was set last, false duration
  14 + double samplerate; ///< The target samplerate set via setSamplerate
  15 + double duration; ///< The target record time set via setRecordTime
  16 + enum SamplerrateSet { Duration, Samplerrate } samplerateSet;
16 17 };
17 18  
18 19 //////////////////////////////////////////////////////////////////////////////
... ... @@ -21,21 +22,21 @@ struct ControlSettingsSamplerateTarget {
21 22 struct ControlSettingsSamplerate {
22 23 ControlSettingsSamplerateTarget target; ///< The target samplerate values
23 24 ControlSamplerateLimits *limits; ///< The samplerate limits
24   - unsigned int downsampler = 1; ///< The variable downsampling factor
25   - double current = 1e8; ///< The current samplerate
  25 + unsigned int downsampler = 1; ///< The variable downsampling factor
  26 + double current = 1e8; ///< The current samplerate
26 27 };
27 28  
28 29 //////////////////////////////////////////////////////////////////////////////
29 30 /// \struct ControlSettingsTrigger hantek/control.h
30 31 /// \brief Stores the current trigger settings of the device.
31 32 struct ControlSettingsTrigger {
32   - std::vector<double> level; ///< The trigger level for each channel in V
33   - double position = 0.0; ///< The current pretrigger position
34   - unsigned int point = 0; ///< The trigger position in Hantek coding
35   - Dso::TriggerMode mode = Dso::TRIGGERMODE_NORMAL; ///< The trigger mode
36   - Dso::Slope slope = Dso::SLOPE_POSITIVE; ///< The trigger slope
37   - bool special = false; ///< true, if the trigger source is special
38   - unsigned int source = 0; ///< The trigger source
  33 + std::vector<double> level; ///< The trigger level for each channel in V
  34 + double position = 0.0; ///< The current pretrigger position
  35 + unsigned int point = 0; ///< The trigger position in Hantek coding
  36 + Dso::TriggerMode mode = Dso::TriggerMode::NORMAL; ///< The trigger mode
  37 + Dso::Slope slope = Dso::Slope::Positive; ///< The trigger slope
  38 + bool special = false; ///< true, if the trigger source is special
  39 + unsigned int source = 0; ///< The trigger source
39 40 };
40 41  
41 42 //////////////////////////////////////////////////////////////////////////////
... ... @@ -53,14 +54,12 @@ struct ControlSettingsVoltage {
53 54 /// \brief Stores the current settings of the device.
54 55 struct ControlSettings {
55 56 ControlSettings(ControlSamplerateLimits *limits, size_t channelCount);
56   - ControlSettingsSamplerate samplerate; ///< The samplerate settings
  57 + ControlSettingsSamplerate samplerate; ///< The samplerate settings
57 58 std::vector<ControlSettingsVoltage> voltage; ///< The amplification settings
58   - ControlSettingsTrigger trigger; ///< The trigger settings
59   - unsigned recordLengthId = 1; ///< The id in the record length array
60   - unsigned usedChannels = 0; ///< Number of activated channels
  59 + ControlSettingsTrigger trigger; ///< The trigger settings
  60 + RecordLengthID recordLengthId = 1; ///< The id in the record length array
  61 + unsigned usedChannels = 0; ///< Number of activated channels
61 62 // Software trigger, margin
62 63 const unsigned swtriggerSampleMargin = 2000;
63 64 };
64   -
65 65 }
66   -
... ...
openhantek/src/hantekdso/controlspecification.h
... ... @@ -2,58 +2,33 @@
2 2  
3 3 #pragma once
4 4  
5   -#include "hantekprotocol/controlvalue.h"
  5 +#include "enums.h"
6 6 #include "hantekprotocol/bulkcode.h"
7 7 #include "hantekprotocol/controlcode.h"
  8 +#include "hantekprotocol/controlvalue.h"
8 9 #include "hantekprotocol/definitions.h"
9 10 #include <QList>
10 11  
11   -namespace Hantek {
  12 +namespace Dso {
12 13  
13   -typedef unsigned RecordLengthID;
14   -typedef unsigned ChannelID;
  14 +using namespace Hantek;
15 15  
16   -//////////////////////////////////////////////////////////////////////////////
17   -/// \struct ControlSpecificationCommandsBulk hantek/control.h
18 16 /// \brief Stores the bulk command codes used for this device.
19 17 struct ControlSpecificationCommandsBulk {
20   - BulkCode setChannels = (BulkCode)-1; ///< Command for setting used channels
21   - BulkCode setSamplerate = (BulkCode)-1; ///< Command for samplerate settings
22   - BulkCode setGain = (BulkCode)-1; ///< Command for gain settings (Usually in combination with
23   - /// CONTROL_SETRELAYS)
24   - BulkCode setRecordLength = (BulkCode)-1; ///< Command for buffer settings
25   - BulkCode setTrigger = (BulkCode)-1; ///< Command for trigger settings
26   - BulkCode setPretrigger = (BulkCode)-1; ///< Command for pretrigger settings
  18 + BulkCode setChannels = BulkCode::INVALID; ///< Command for setting used channels
  19 + BulkCode setSamplerate = BulkCode::INVALID; ///< Command for samplerate settings
  20 + BulkCode setGain = BulkCode::SETGAIN; ///< Command for gain settings (Usually in combination with
  21 + /// CONTROL_SETRELAYS)
  22 + BulkCode setRecordLength = BulkCode::INVALID; ///< Command for buffer settings
  23 + BulkCode setTrigger = BulkCode::INVALID; ///< Command for trigger settings
  24 + BulkCode setPretrigger = BulkCode::INVALID; ///< Command for pretrigger settings
27 25 };
28 26  
29   -//////////////////////////////////////////////////////////////////////////////
30   -/// \struct ControlSpecificationCommandsControl hantek/control.h
31   -/// \brief Stores the control command codes used for this device.
32   -struct ControlSpecificationCommandsControl {
33   - ControlCode setOffset = (ControlCode)-1; ///< Command for setting offset calibration data
34   - ControlCode setRelays = (ControlCode)-1; ///< Command for setting gain relays (Usually in
35   - /// combination with BulkCode::SETGAIN)
36   -};
37   -
38   -//////////////////////////////////////////////////////////////////////////////
39   -/// \struct ControlSpecificationCommandsValues hantek/control.h
40   -/// \brief Stores the control value codes used for this device.
41   -struct ControlSpecificationCommandsValues {
42   - ControlValue offsetLimits = VALUE_OFFSETLIMITS; ///< Code for channel offset limits
43   - ControlValue voltageLimits = (ControlValue)-1; ///< Code for voltage limits
44   -};
45   -
46   -//////////////////////////////////////////////////////////////////////////////
47   -/// \struct ControlSpecificationCommands hantek/control.h
48 27 /// \brief Stores the command codes used for this device.
49 28 struct ControlSpecificationCommands {
50   - ControlSpecificationCommandsBulk bulk; ///< The used bulk commands
51   - ControlSpecificationCommandsControl control; ///< The used control commands
52   - ControlSpecificationCommandsValues values; ///< The used control values
  29 + ControlSpecificationCommandsBulk bulk; ///< The used bulk commands
53 30 };
54 31  
55   -//////////////////////////////////////////////////////////////////////////////
56   -/// \struct ControlSamplerateLimits hantek/control.h
57 32 /// \brief Stores the samplerate limits for calculations.
58 33 struct ControlSamplerateLimits {
59 34 double base; ///< The base for sample rate calculations
... ... @@ -62,12 +37,10 @@ struct ControlSamplerateLimits {
62 37 std::vector<unsigned> recordLengths; ///< Available record lengths, UINT_MAX means rolling
63 38 };
64 39  
65   -//////////////////////////////////////////////////////////////////////////////
66   -/// \struct ControlSpecificationSamplerate hantek/control.h
67 40 /// \brief Stores the samplerate limits.
68 41 struct ControlSpecificationSamplerate {
69   - ControlSamplerateLimits single = {50e6, 50e6, 0, std::vector<unsigned>()}; ///< The limits for single channel mode
70   - ControlSamplerateLimits multi = {100e6, 100e6, 0, std::vector<unsigned>()}; ///< The limits for multi channel mode
  42 + ControlSamplerateLimits single = {50e6, 50e6, 0, std::vector<unsigned>()}; ///< The limits for single channel mode
  43 + ControlSamplerateLimits multi = {100e6, 100e6, 0, std::vector<unsigned>()}; ///< The limits for multi channel mode
71 44 };
72 45  
73 46 struct ControlSpecificationGainLevel {
... ... @@ -87,17 +60,17 @@ struct SpecialTriggerChannel {
87 60 int hardwareID;
88 61 };
89 62  
90   -//////////////////////////////////////////////////////////////////////////////
91   -/// \struct ControlSpecification hantek/control.h
92 63 /// \brief Stores the specifications of the currently connected device.
93 64 struct ControlSpecification {
  65 + ChannelID channels = HANTEK_CHANNELS;
  66 +
94 67 // Interface
95 68 ControlSpecificationCommands command; ///< The commands for this device
96 69  
97 70 // Limits
98   - ControlSpecificationSamplerate samplerate; ///< The samplerate specifications
99   - std::vector<RecordLengthID> bufferDividers; ///< Samplerate dividers for record lengths
100   - unsigned char sampleSize; ///< Number of bits per sample
  71 + ControlSpecificationSamplerate samplerate; ///< The samplerate specifications
  72 + std::vector<RecordLengthID> bufferDividers; ///< Samplerate dividers for record lengths
  73 + unsigned char sampleSize; ///< Number of bits per sample
101 74  
102 75 // Calibration
103 76 /// The sample values at the top of the screen
... ... @@ -112,6 +85,7 @@ struct ControlSpecification {
112 85 std::vector<FixedSampleRate> fixedSampleRates;
113 86  
114 87 std::vector<SpecialTriggerChannel> specialTriggerChannels;
  88 + std::vector<Coupling> couplings = {Dso::Coupling::DC, Dso::Coupling::AC};
115 89  
116 90 bool isFixedSamplerateDevice = false;
117 91 bool isSoftwareTriggerDevice = false;
... ... @@ -120,6 +94,4 @@ struct ControlSpecification {
120 94 bool supportsOffset = true;
121 95 bool supportsCouplingRelays = true;
122 96 };
123   -
124 97 }
125   -
... ...
openhantek/src/hantekdso/dsomodel.cpp
... ... @@ -4,6 +4,6 @@
4 4 #include "dsomodel.h"
5 5  
6 6 DSOModel::DSOModel(int id, long vendorID, long productID, long vendorIDnoFirmware,
7   - long productIDnoFirmware, const std::string &firmwareToken, const std::string &name, const Hantek::ControlSpecification &specification)
  7 + long productIDnoFirmware, const std::string &firmwareToken, const std::string &name, const Dso::ControlSpecification &specification)
8 8 : ID(id), vendorID(vendorID), productID(productID), vendorIDnoFirmware(vendorIDnoFirmware),
9 9 productIDnoFirmware(productIDnoFirmware), firmwareToken(firmwareToken), name(name), specification(specification) {}
... ...
openhantek/src/hantekdso/dsomodel.h
... ... @@ -25,12 +25,12 @@ class DSOModel {
25 25 /// The firmwareToken is the "devicename" of the pattern above.
26 26 std::string firmwareToken;
27 27 std::string name; ///< User visible name. Does not need internationalisation/translation.
28   - Hantek::ControlSpecification specification;
  28 + Dso::ControlSpecification specification;
29 29 public:
30 30 /// This model may need to modify the HantekDsoControl class to work correctly
31 31 virtual void applyRequirements(HantekDsoControl*) const = 0;
32 32 DSOModel(int id, long vendorID, long productID, long vendorIDnoFirmware, long productIDnoFirmware,
33   - const std::string& firmwareToken, const std::string& name, const Hantek::ControlSpecification& specification);
  33 + const std::string& firmwareToken, const std::string& name, const Dso::ControlSpecification& specification);
34 34 virtual ~DSOModel() = default;
35 35 };
36 36  
... ...
openhantek/src/hantekdso/enums.cpp 0 → 100644
  1 +#include "enums.h"
  2 +
  3 +namespace Dso {
  4 + Enum<Dso::TriggerMode, Dso::TriggerMode::AUTO, Dso::TriggerMode::SOFTWARE> TriggerModeEnum;
  5 + Enum<Dso::Slope, Dso::Slope::Positive, Dso::Slope::Negative> SlopeEnum;
  6 + Enum<Dso::GraphFormat, Dso::GraphFormat::TY, Dso::GraphFormat::XY> GraphFormatEnum;
  7 + Enum<Dso::ChannelMode, Dso::ChannelMode::Voltage, Dso::ChannelMode::Spectrum> ChannelModeEnum;
  8 +}
... ...
openhantek/src/hantekdso/enums.h
1 1 #pragma once
2 2  
3   -#include <QMetaType>
4 3 #include "utils/enumclass.h"
  4 +#include <QMetaType>
5 5 namespace Dso {
6 6 /// \enum ChannelMode
7 7 /// \brief The channel display modes.
8   -enum ChannelMode {
9   - CHANNELMODE_VOLTAGE, ///< Standard voltage view
10   - CHANNELMODE_SPECTRUM, ///< Spectrum view
11   - CHANNELMODE_COUNT ///< The total number of modes
  8 +enum class ChannelMode {
  9 + Voltage, ///< Standard voltage view
  10 + Spectrum ///< Spectrum view
12 11 };
  12 +constexpr int ChannelModes = 2;
  13 +extern Enum<Dso::ChannelMode, Dso::ChannelMode::Voltage, Dso::ChannelMode::Spectrum> ChannelModeEnum;
13 14  
14 15 /// \enum GraphFormat
15 16 /// \brief The possible viewing formats for the graphs on the scope.
16 17 enum GraphFormat {
17   - GRAPHFORMAT_TY, ///< The standard mode
18   - GRAPHFORMAT_XY, ///< CH1 on X-axis, CH2 on Y-axis
19   - GRAPHFORMAT_COUNT ///< The total number of formats
  18 + TY, ///< The standard mode
  19 + XY ///< CH1 on X-axis, CH2 on Y-axis
20 20 };
21 21  
  22 +extern Enum<Dso::GraphFormat, Dso::GraphFormat::TY, Dso::GraphFormat::XY> GraphFormatEnum;
  23 +
22 24 /// \enum Coupling
23 25 /// \brief The coupling modes for the channels.
24   -enum Coupling {
25   - COUPLING_AC, ///< Offset filtered out by condensator
26   - COUPLING_DC, ///< No filtering
27   - COUPLING_GND, ///< Channel is grounded
28   - COUPLING_COUNT ///< The total number of coupling modes
  26 +enum class Coupling {
  27 + AC, ///< Offset filtered out by condensator
  28 + DC, ///< No filtering
  29 + GND ///< Channel is grounded
29 30 };
30 31  
31 32 /// \enum TriggerMode
32 33 /// \brief The different triggering modes.
33   -enum TriggerMode {
34   - TRIGGERMODE_AUTO, ///< Automatic without trigger event
35   - TRIGGERMODE_NORMAL, ///< Normal mode
36   - TRIGGERMODE_SINGLE, ///< Stop after the first trigger event
37   - TRIGGERMODE_SOFTWARE, ///< Software trigger mode
38   - TRIGGERMODE_COUNT ///< The total number of modes
  34 +enum class TriggerMode {
  35 + AUTO, ///< Automatic without trigger event
  36 + NORMAL, ///< Normal mode
  37 + SINGLE, ///< Stop after the first trigger event
  38 + SOFTWARE ///< Software trigger mode
39 39 };
  40 +extern Enum<Dso::TriggerMode, Dso::TriggerMode::AUTO, Dso::TriggerMode::SOFTWARE> TriggerModeEnum;
40 41  
41 42 /// \enum Slope
42 43 /// \brief The slope that causes a trigger.
43   -enum Slope {
44   - SLOPE_POSITIVE, ///< From lower to higher voltage
45   - SLOPE_NEGATIVE, ///< From higher to lower voltage
46   - SLOPE_COUNT ///< Total number of trigger slopes
  44 +enum class Slope : uint8_t {
  45 + Positive = 0, ///< From lower to higher voltage
  46 + Negative = 1 ///< From higher to lower voltage
47 47 };
  48 +extern Enum<Dso::Slope, Dso::Slope::Positive, Dso::Slope::Negative> SlopeEnum;
48 49  
49 50 /// \enum InterpolationMode
50 51 /// \brief The different interpolation modes for the graphs.
... ... @@ -62,4 +63,3 @@ Q_DECLARE_METATYPE(Dso::Coupling)
62 63 Q_DECLARE_METATYPE(Dso::GraphFormat)
63 64 Q_DECLARE_METATYPE(Dso::ChannelMode)
64 65 Q_DECLARE_METATYPE(Dso::InterpolationMode)
65   -
... ...
openhantek/src/hantekdso/hantekdsocontrol.cpp
1 1 // SPDX-License-Identifier: GPL-2.0+
2 2  
  3 +#include <assert.h>
3 4 #include <cmath>
4 5 #include <limits>
  6 +#include <stdexcept>
5 7 #include <vector>
6   -#include <assert.h>
7 8  
8 9 #include <QDebug>
9 10 #include <QEventLoop>
... ... @@ -17,9 +18,9 @@
17 18 #include "models/modelDSO6022.h"
18 19 #include "usb/usbdevice.h"
19 20 #include "utils/printutils.h"
20   -#include <stdexcept>
21 21  
22 22 using namespace Hantek;
  23 +using namespace Dso;
23 24  
24 25 /// \brief Start sampling process.
25 26 void HantekDsoControl::startSampling() {
... ... @@ -35,7 +36,7 @@ void HantekDsoControl::startSampling() {
35 36 if (specification.isFixedSamplerateDevice) {
36 37 // Convert to GUI presentable values (1e5 -> 1.0, 48e6 -> 480.0 etc)
37 38 QList<double> sampleSteps;
38   - for (auto& v : specification.fixedSampleRates) { sampleSteps << v.samplerate / 1e5; }
  39 + for (auto &v : specification.fixedSampleRates) { sampleSteps << v.samplerate / 1e5; }
39 40 emit samplerateSet(1, sampleSteps);
40 41 }
41 42  
... ... @@ -48,12 +49,9 @@ void HantekDsoControl::stopSampling() {
48 49 emit samplingStopped();
49 50 }
50 51  
51   -const std::vector<std::string> HantekDsoControl::getSpecialTriggerSources()
52   -{
  52 +const std::vector<std::string> HantekDsoControl::getSpecialTriggerSources() {
53 53 std::vector<std::string> sources;
54   - for (auto& v: specification.specialTriggerChannels) {
55   - sources.push_back(v.name);
56   - }
  54 + for (auto &v : specification.specialTriggerChannels) { sources.push_back(v.name); }
57 55 return sources;
58 56 }
59 57  
... ... @@ -61,26 +59,22 @@ USBDevice *HantekDsoControl::getDevice() { return device; }
61 59  
62 60 const DSOsamples &HantekDsoControl::getLastSamples() { return result; }
63 61  
64   -HantekDsoControl::HantekDsoControl(USBDevice *device) : device(device),
65   - specification(device->getModel()->specification), controlsettings(&(specification.samplerate.single), HANTEK_CHANNELS) {
  62 +HantekDsoControl::HantekDsoControl(USBDevice *device)
  63 + : device(device), specification(device->getModel()->specification),
  64 + controlsettings(&(specification.samplerate.single), specification.channels) {
66 65 if (device == nullptr) throw new std::runtime_error("No usb device for HantekDsoControl");
67 66  
68   - // Transmission-ready control commands
69   - this->control[CONTROLINDEX_SETOFFSET] = new ControlSetOffset();
70   - this->controlCode[CONTROLINDEX_SETOFFSET] = CONTROL_SETOFFSET;
71   - this->control[CONTROLINDEX_SETRELAYS] = new ControlSetRelays();
72   - this->controlCode[CONTROLINDEX_SETRELAYS] = CONTROL_SETRELAYS;
73   -
74   - // Instantiate the commands needed for all models
75   - command[(uint8_t)BulkCode::FORCETRIGGER] = new BulkForceTrigger();
76   - command[(uint8_t)BulkCode::STARTSAMPLING] = new BulkCaptureStart();
77   - command[(uint8_t)BulkCode::ENABLETRIGGER] = new BulkTriggerEnabled();
78   - command[(uint8_t)BulkCode::GETDATA] = new BulkGetData();
79   - command[(uint8_t)BulkCode::GETCAPTURESTATE] = new BulkGetCaptureState();
80   - command[(uint8_t)BulkCode::SETGAIN] = new BulkSetGain();
81   -
82   - if (specification.useControlNoBulk)
  67 + if (specification.useControlNoBulk) {
83 68 device->setEnableBulkTransfer(false);
  69 + } else {
  70 + // Instantiate the commands needed for all bulk-command-enabled models
  71 + addCommand(BulkCode::FORCETRIGGER, new BulkForceTrigger(), false);
  72 + addCommand(BulkCode::STARTSAMPLING, new BulkCaptureStart(), false);
  73 + addCommand(BulkCode::ENABLETRIGGER, new BulkTriggerEnabled(), false);
  74 + addCommand(BulkCode::GETDATA, new BulkGetData(), false);
  75 + addCommand(BulkCode::GETCAPTURESTATE, new BulkGetCaptureState(), false);
  76 + addCommand(BulkCode::SETGAIN, new BulkSetGain(), false);
  77 + }
84 78  
85 79 // Apply special requirements by the devices model
86 80 device->getModel()->applyRequirements(this);
... ... @@ -89,11 +83,21 @@ HantekDsoControl::HantekDsoControl(USBDevice *device) : device(device),
89 83 }
90 84  
91 85 HantekDsoControl::~HantekDsoControl() {
92   - for (int cIndex = 0; cIndex < (uint8_t)BulkCode::COUNT; ++cIndex) { delete command[cIndex]; }
93   - for (int cIndex = 0; cIndex < CONTROLINDEX_COUNT; ++cIndex) { delete control[cIndex]; }
  86 + while (firstBulkCommand) {
  87 + BulkCommand *t = firstBulkCommand->next;
  88 + delete firstBulkCommand;
  89 + firstBulkCommand = t;
  90 + }
  91 + while (firstControlCommand) {
  92 + ControlCommand *t = firstControlCommand->next;
  93 + delete firstControlCommand;
  94 + firstControlCommand = t;
  95 + }
94 96 }
95 97  
96   -unsigned HantekDsoControl::getChannelCount() { return HANTEK_CHANNELS; }
  98 +unsigned HantekDsoControl::getChannelCount() { return specification.channels; }
  99 +
  100 +const ControlSettings *HantekDsoControl::getDeviceSettings() const { return &controlsettings; }
97 101  
98 102 const std::vector<unsigned> &HantekDsoControl::getAvailableRecordLengths() { //
99 103 return controlsettings.samplerate.limits->recordLengths;
... ... @@ -114,7 +118,7 @@ void HantekDsoControl::updateInterval() {
114 118 // Check the current oscilloscope state everytime 25% of the time the buffer
115 119 // should be refilled
116 120 if (isRollMode())
117   - cycleTime = (int)((double)device->getPacketSize() / (isFastRate() ? 1 : HANTEK_CHANNELS) /
  121 + cycleTime = (int)((double)device->getPacketSize() / (isFastRate() ? 1 : specification.channels) /
118 122 controlsettings.samplerate.current * 250);
119 123 else
120 124 cycleTime = (int)((double)getRecordLength() / controlsettings.samplerate.current * 250);
... ... @@ -137,8 +141,9 @@ unsigned HantekDsoControl::getRecordLength() const {
137 141  
138 142 Dso::ErrorCode HantekDsoControl::retrieveChannelLevelData() {
139 143 // Get channel level data
140   - int errorCode = device->controlRead(CONTROL_VALUE, (unsigned char *)&(specification.offsetLimit),
141   - sizeof(specification.offsetLimit), (int)VALUE_OFFSETLIMITS);
  144 + int errorCode =
  145 + device->controlRead((uint8_t)ControlCode::CONTROL_VALUE, (unsigned char *)&(specification.offsetLimit),
  146 + sizeof(specification.offsetLimit), (uint8_t)ControlValue::VALUE_OFFSETLIMITS);
142 147 if (errorCode < 0) {
143 148 qWarning() << tr("Couldn't get channel level data from oscilloscope");
144 149 emit statusMessage(tr("Couldn't get channel level data from oscilloscope"), 0);
... ... @@ -164,7 +169,7 @@ std::pair&lt;int, unsigned&gt; HantekDsoControl::getCaptureState() const {
164 169  
165 170 if (!specification.supportsCaptureState) return std::make_pair(CAPTURE_READY, 0);
166 171  
167   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::GETCAPTURESTATE], 1);
  172 + errorCode = device->bulkCommand(getCommand(BulkCode::GETCAPTURESTATE), 1);
168 173 if (errorCode < 0) {
169 174 qWarning() << "Getting capture state failed: " << libUsbErrorString(errorCode);
170 175 return std::make_pair(CAPTURE_ERROR, 0);
... ... @@ -181,14 +186,18 @@ std::pair&lt;int, unsigned&gt; HantekDsoControl::getCaptureState() const {
181 186 }
182 187  
183 188 std::vector<unsigned char> HantekDsoControl::getSamples(unsigned &previousSampleCount) const {
  189 + int errorCode;
184 190 if (!specification.useControlNoBulk) {
185 191 // Request data
186   - int errorCode = device->bulkCommand(command[(uint8_t)BulkCode::GETDATA], 1);
187   - if (errorCode < 0) {
188   - qWarning() << "Getting sample data failed: " << libUsbErrorString(errorCode);
189   - emit communicationError();
190   - return std::vector<unsigned char>();
191   - }
  192 + errorCode = device->bulkCommand(getCommand(BulkCode::GETDATA), 1);
  193 + } else {
  194 + const ControlCommand *bulkCommand = getCommand(ControlCode::CONTROL_ACQUIIRE_HARD_DATA);
  195 + errorCode = device->controlWrite((uint8_t)bulkCommand->code, bulkCommand->data(), bulkCommand->getSize());
  196 + }
  197 + if (errorCode < 0) {
  198 + qWarning() << "Getting sample data failed: " << libUsbErrorString(errorCode);
  199 + emit communicationError();
  200 + return std::vector<unsigned char>();
192 201 }
193 202  
194 203 unsigned totalSampleCount = this->getSampleCount();
... ... @@ -226,8 +235,8 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector&lt;unsigned char&gt;
226 235 result.samplerate = controlsettings.samplerate.current;
227 236 result.append = isRollMode();
228 237 // Prepare result buffers
229   - result.data.resize(HANTEK_CHANNELS);
230   - for (int channelCounter = 0; channelCounter < HANTEK_CHANNELS; ++channelCounter)
  238 + result.data.resize(specification.channels);
  239 + for (ChannelID channelCounter = 0; channelCounter < specification.channels; ++channelCounter)
231 240 result.data[channelCounter].clear();
232 241  
233 242 const unsigned extraBitsSize = specification.sampleSize - 8; // Number of extra bits
... ... @@ -236,12 +245,12 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector&lt;unsigned char&gt;
236 245 // Convert channel data
237 246 if (isFastRate()) {
238 247 // Fast rate mode, one channel is using all buffers
239   - unsigned channel = 0;
240   - for (; channel < HANTEK_CHANNELS; ++channel) {
  248 + ChannelID channel = 0;
  249 + for (; channel < specification.channels; ++channel) {
241 250 if (controlsettings.voltage[channel].used) break;
242 251 }
243 252  
244   - if (channel >= HANTEK_CHANNELS) return;
  253 + if (channel >= specification.channels) return;
245 254  
246 255 // Resize sample vector
247 256 result.data[channel].resize(totalSampleCount);
... ... @@ -258,8 +267,8 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector&lt;unsigned char&gt;
258 267 if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount;
259 268  
260 269 const unsigned short low = rawData[bufferPosition];
261   - const unsigned extraBitsPosition = bufferPosition % HANTEK_CHANNELS;
262   - const unsigned shift = (8 - (HANTEK_CHANNELS - 1 - extraBitsPosition) * extraBitsSize);
  270 + const unsigned extraBitsPosition = bufferPosition % specification.channels;
  271 + const unsigned shift = (8 - (specification.channels - 1 - extraBitsPosition) * extraBitsSize);
263 272 const unsigned short high =
264 273 ((unsigned short int)rawData[totalSampleCount + bufferPosition - extraBitsPosition] << shift) &
265 274 extraBitsMask;
... ... @@ -276,13 +285,14 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector&lt;unsigned char&gt;
276 285 }
277 286 } else {
278 287 // Normal mode, channels are using their separate buffers
279   - for (unsigned channel = 0; channel < HANTEK_CHANNELS; ++channel) {
280   - result.data[channel].resize(totalSampleCount / HANTEK_CHANNELS);
  288 + for (ChannelID channel = 0; channel < specification.channels; ++channel) {
  289 + result.data[channel].resize(totalSampleCount / specification.channels);
281 290  
282 291 const unsigned gainID = controlsettings.voltage[channel].gain;
283 292 const unsigned short limit = specification.voltageLimit[channel][gainID];
284 293 const double offset = controlsettings.voltage[channel].offsetReal;
285 294 const double gainStep = specification.gain[gainID].gainSteps;
  295 + int shiftDataBuf = 0;
286 296  
287 297 // Convert data from the oscilloscope and write it into the sample buffer
288 298 unsigned bufferPosition = controlsettings.trigger.point * 2;
... ... @@ -291,10 +301,10 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector&lt;unsigned char&gt;
291 301 unsigned extraBitsIndex = 8 - channel * 2; // Bit position offset for extra bits extraction
292 302  
293 303 for (unsigned realPosition = 0; realPosition < result.data[channel].size();
294   - ++realPosition, bufferPosition += HANTEK_CHANNELS) {
  304 + ++realPosition, bufferPosition += specification.channels) {
295 305 if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount;
296 306  
297   - const unsigned short low = rawData[bufferPosition + HANTEK_CHANNELS - 1 - channel];
  307 + const unsigned short low = rawData[bufferPosition + specification.channels - 1 - channel];
298 308 const unsigned short high =
299 309 ((unsigned short int)rawData[totalSampleCount + bufferPosition] << extraBitsIndex) &
300 310 extraBitsMask;
... ... @@ -311,18 +321,14 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector&lt;unsigned char&gt;
311 321 bufferPosition += DROP_DSO6022_HEAD * 2;
312 322 }
313 323 bufferPosition += channel;
314   - for (unsigned pos = 0; pos < result.data[channel].size(); ++pos, bufferPosition += HANTEK_CHANNELS) {
315   - if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount;
316   - double dataBuf = (double)((int)(rawData[bufferPosition] - 0x83));
317   - result.data[channel][pos] = (dataBuf / limit) * gainStep;
318   - }
  324 + shiftDataBuf = 0x83;
319 325 } else {
320   - bufferPosition += HANTEK_CHANNELS - 1 - channel;
321   - for (unsigned pos = 0; pos < result.data[channel].size(); ++pos, bufferPosition += HANTEK_CHANNELS) {
322   - if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount;
323   - double dataBuf = (double)((int)(rawData[bufferPosition]));
324   - result.data[channel][pos] = (dataBuf / limit - offset) * gainStep;
325   - }
  326 + bufferPosition += specification.channels - 1 - channel;
  327 + }
  328 + for (unsigned pos = 0; pos < result.data[channel].size(); ++pos, bufferPosition += specification.channels) {
  329 + if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount;
  330 + double dataBuf = (double)((int)(rawData[bufferPosition] - shiftDataBuf));
  331 + result.data[channel][pos] = (dataBuf / limit - offset) * gainStep;
326 332 }
327 333 }
328 334 }
... ... @@ -420,39 +426,30 @@ unsigned HantekDsoControl::getSampleCount() const {
420 426 if (isFastRate())
421 427 return getRecordLength();
422 428 else
423   - return getRecordLength() * HANTEK_CHANNELS;
  429 + return getRecordLength() * specification.channels;
424 430 }
425 431 }
426 432  
427   -unsigned HantekDsoControl::updateRecordLength(unsigned index) {
428   - if (index >= (unsigned)controlsettings.samplerate.limits->recordLengths.size()) return 0;
  433 +unsigned HantekDsoControl::updateRecordLength(RecordLengthID index) {
  434 + if (index >= controlsettings.samplerate.limits->recordLengths.size()) return 0;
429 435  
430 436 switch (specification.command.bulk.setRecordLength) {
431 437 case BulkCode::SETTRIGGERANDSAMPLERATE:
432   - // SetTriggerAndSamplerate bulk command for record length
433   - static_cast<BulkSetTriggerAndSamplerate *>(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])->setRecordLength(index);
434   - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
435   -
  438 + modifyCommand<BulkSetTriggerAndSamplerate>(BulkCode::SETTRIGGERANDSAMPLERATE)->setRecordLength(index);
436 439 break;
437 440  
438 441 case BulkCode::DSETBUFFER:
439 442 if (specification.command.bulk.setPretrigger == BulkCode::FSETBUFFER) {
440   - // Pointers to needed commands
441   - BulkSetRecordLength2250 *commandSetRecordLength2250 =
442   - static_cast<BulkSetRecordLength2250 *>(command[(uint8_t)BulkCode::DSETBUFFER]);
443   -
444   - commandSetRecordLength2250->setRecordLength(index);
  443 + modifyCommand<BulkSetRecordLength2250>(BulkCode::DSETBUFFER)->setRecordLength(index);
445 444 } else {
446 445 // SetBuffer5200 bulk command for record length
447   - BulkSetBuffer5200 *commandSetBuffer5200 = static_cast<BulkSetBuffer5200 *>(command[(uint8_t)BulkCode::DSETBUFFER]);
  446 + BulkSetBuffer5200 *commandSetBuffer5200 = modifyCommand<BulkSetBuffer5200>(BulkCode::DSETBUFFER);
448 447  
449 448 commandSetBuffer5200->setUsedPre(DTriggerPositionUsed::DTRIGGERPOSITION_ON);
450 449 commandSetBuffer5200->setUsedPost(DTriggerPositionUsed::DTRIGGERPOSITION_ON);
451 450 commandSetBuffer5200->setRecordLength(index);
452 451 }
453 452  
454   - commandPending[(uint8_t)BulkCode::DSETBUFFER] = true;
455   -
456 453 break;
457 454  
458 455 default:
... ... @@ -477,8 +474,7 @@ unsigned HantekDsoControl::updateRecordLength(unsigned index) {
477 474  
478 475 unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) {
479 476 // Get samplerate limits
480   - Hantek::ControlSamplerateLimits *limits =
481   - fastRate ? &specification.samplerate.multi : &specification.samplerate.single;
  477 + ControlSamplerateLimits *limits = fastRate ? &specification.samplerate.multi : &specification.samplerate.single;
482 478  
483 479 // Set the calculated samplerate
484 480 switch (specification.command.bulk.setSamplerate) {
... ... @@ -508,7 +504,7 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate)
508 504  
509 505 // Pointers to needed commands
510 506 BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate =
511   - static_cast<BulkSetTriggerAndSamplerate *>(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE]);
  507 + modifyCommand<BulkSetTriggerAndSamplerate>(BulkCode::SETTRIGGERANDSAMPLERATE);
512 508  
513 509 // Store if samplerate ID or downsampling factor is used
514 510 commandSetTriggerAndSamplerate->setDownsamplingMode(downsampling);
... ... @@ -519,8 +515,6 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate)
519 515 // Set fast rate when used
520 516 commandSetTriggerAndSamplerate->setFastRate(false /*fastRate*/);
521 517  
522   - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
523   -
524 518 break;
525 519 }
526 520 case BulkCode::CSETTRIGGERORSAMPLERATE: {
... ... @@ -531,9 +525,9 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate)
531 525  
532 526 // Pointers to needed commands
533 527 BulkSetSamplerate5200 *commandSetSamplerate5200 =
534   - static_cast<BulkSetSamplerate5200 *>(command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE]);
  528 + modifyCommand<BulkSetSamplerate5200>(BulkCode::CSETTRIGGERORSAMPLERATE);
535 529 BulkSetTrigger5200 *commandSetTrigger5200 =
536   - static_cast<BulkSetTrigger5200 *>(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE]);
  530 + modifyCommand<BulkSetTrigger5200>(BulkCode::ESETTRIGGERORSAMPLERATE);
537 531  
538 532 // Store samplerate fast value
539 533 commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
... ... @@ -542,15 +536,12 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate)
542 536 // Set fast rate when used
543 537 commandSetTrigger5200->setFastRate(fastRate);
544 538  
545   - commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true;
546   - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
547   -
548 539 break;
549 540 }
550 541 case BulkCode::ESETTRIGGERORSAMPLERATE: {
551 542 // Pointers to needed commands
552 543 BulkSetSamplerate2250 *commandSetSamplerate2250 =
553   - static_cast<BulkSetSamplerate2250 *>(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE]);
  544 + modifyCommand<BulkSetSamplerate2250>(BulkCode::ESETTRIGGERORSAMPLERATE);
554 545  
555 546 bool downsampling = downsampler >= 1;
556 547 // Store downsampler state value
... ... @@ -560,8 +551,6 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate)
560 551 // Set fast rate when used
561 552 commandSetSamplerate2250->setFastRate(fastRate);
562 553  
563   - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
564   -
565 554 break;
566 555 }
567 556 default:
... ... @@ -597,7 +586,7 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate)
597 586 }
598 587  
599 588 void HantekDsoControl::restoreTargets() {
600   - if (controlsettings.samplerate.target.samplerateSet)
  589 + if (controlsettings.samplerate.target.samplerateSet == ControlSettingsSamplerateTarget::Samplerrate)
601 590 this->setSamplerate();
602 591 else
603 592 this->setRecordTime();
... ... @@ -620,10 +609,10 @@ void HantekDsoControl::updateSamplerateLimits() {
620 609 Dso::ErrorCode HantekDsoControl::setRecordLength(unsigned index) {
621 610 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
622 611  
623   - if (!this->updateRecordLength(index)) return Dso::ErrorCode::PARAMETER;
  612 + if (!updateRecordLength(index)) return Dso::ErrorCode::PARAMETER;
624 613  
625   - this->restoreTargets();
626   - this->setPretriggerPosition(controlsettings.trigger.position);
  614 + restoreTargets();
  615 + setPretriggerPosition(controlsettings.trigger.position);
627 616  
628 617 emit recordLengthChanged(getRecordLength());
629 618 return Dso::ErrorCode::NONE;
... ... @@ -640,7 +629,7 @@ Dso::ErrorCode HantekDsoControl::setSamplerate(double samplerate) {
640 629 samplerate = controlsettings.samplerate.target.samplerate;
641 630 } else {
642 631 controlsettings.samplerate.target.samplerate = samplerate;
643   - controlsettings.samplerate.target.samplerateSet = true;
  632 + controlsettings.samplerate.target.samplerateSet = ControlSettingsSamplerateTarget::Samplerrate;
644 633 }
645 634  
646 635 if (!specification.isSoftwareTriggerDevice) {
... ... @@ -664,15 +653,14 @@ Dso::ErrorCode HantekDsoControl::setSamplerate(double samplerate) {
664 653 unsigned sampleId;
665 654 for (sampleId = 0; sampleId < specification.fixedSampleRates.size() - 1; ++sampleId)
666 655 if (specification.fixedSampleRates[sampleId].samplerate == samplerate) break;
667   - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
668   - static_cast<ControlSetTimeDIV *>(this->control[CONTROLINDEX_SETTIMEDIV])
  656 + modifyCommand<ControlSetTimeDIV>(ControlCode::CONTROL_SETTIMEDIV)
669 657 ->setDiv(specification.fixedSampleRates[sampleId].id);
670   - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
671 658 controlsettings.samplerate.current = samplerate;
672 659  
673 660 // Check for Roll mode
674 661 if (!isRollMode())
675   - emit recordTimeChanged((double)(getRecordLength() - controlsettings.swtriggerSampleMargin) / controlsettings.samplerate.current);
  662 + emit recordTimeChanged((double)(getRecordLength() - controlsettings.swtriggerSampleMargin) /
  663 + controlsettings.samplerate.current);
676 664 emit samplerateChanged(controlsettings.samplerate.current);
677 665  
678 666 return Dso::ErrorCode::NONE;
... ... @@ -690,7 +678,7 @@ Dso::ErrorCode HantekDsoControl::setRecordTime(double duration) {
690 678 duration = controlsettings.samplerate.target.duration;
691 679 } else {
692 680 controlsettings.samplerate.target.duration = duration;
693   - controlsettings.samplerate.target.samplerateSet = false;
  681 + controlsettings.samplerate.target.samplerateSet = ControlSettingsSamplerateTarget::Duration;
694 682 }
695 683  
696 684 if (!specification.isFixedSamplerateDevice) {
... ... @@ -715,21 +703,18 @@ Dso::ErrorCode HantekDsoControl::setRecordTime(double duration) {
715 703 return Dso::ErrorCode::NONE;
716 704 }
717 705 } else {
718   - // For now - we go for the 10240 size sampling - the other seems not to be
719   - // supported
720   - // Find highest samplerate using less than 10240 samples to obtain our
721   - // duration.
  706 + // For now - we go for the 10240 size sampling - the other seems not to be supported
  707 + // Find highest samplerate using less than 10240 samples to obtain our duration.
722 708 unsigned sampleCount = 10240;
723 709 unsigned sampleId;
724 710 for (sampleId = 0; sampleId < specification.fixedSampleRates.size(); ++sampleId) {
725 711 if (specification.fixedSampleRates[sampleId].samplerate * duration <
726   - (sampleCount - controlsettings.swtriggerSampleMargin))break;
  712 + (sampleCount - controlsettings.swtriggerSampleMargin))
  713 + break;
727 714 }
728 715 // Usable sample value
729   - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
730   - static_cast<ControlSetTimeDIV *>(this->control[CONTROLINDEX_SETTIMEDIV])
  716 + modifyCommand<ControlSetTimeDIV>(ControlCode::CONTROL_SETTIMEDIV)
731 717 ->setDiv(specification.fixedSampleRates[sampleId].id);
732   - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
733 718 controlsettings.samplerate.current = specification.fixedSampleRates[sampleId].samplerate;
734 719  
735 720 emit samplerateChanged(controlsettings.samplerate.current);
... ... @@ -741,15 +726,15 @@ Dso::ErrorCode HantekDsoControl::setRecordTime(double duration) {
741 726 /// \param channel The channel that should be set.
742 727 /// \param used true if the channel should be sampled.
743 728 /// \return See ::Dso::ErrorCode.
744   -Dso::ErrorCode HantekDsoControl::setChannelUsed(unsigned channel, bool used) {
  729 +Dso::ErrorCode HantekDsoControl::setChannelUsed(ChannelID channel, bool used) {
745 730 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
746 731  
747   - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER;
  732 + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER;
748 733  
749 734 // Update settings
750 735 controlsettings.voltage[channel].used = used;
751   - unsigned channelCount = 0;
752   - for (unsigned c = 0; c < HANTEK_CHANNELS; ++c) {
  736 + ChannelID channelCount = 0;
  737 + for (unsigned c = 0; c < specification.channels; ++c) {
753 738 if (controlsettings.voltage[c].used) ++channelCount;
754 739 }
755 740  
... ... @@ -771,22 +756,18 @@ Dso::ErrorCode HantekDsoControl::setChannelUsed(unsigned channel, bool used) {
771 756 switch (specification.command.bulk.setChannels) {
772 757 case BulkCode::SETTRIGGERANDSAMPLERATE: {
773 758 // SetTriggerAndSamplerate bulk command for trigger source
774   - static_cast<BulkSetTriggerAndSamplerate *>(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])
  759 + modifyCommand<BulkSetTriggerAndSamplerate>(BulkCode::SETTRIGGERANDSAMPLERATE)
775 760 ->setUsedChannels((uint8_t)usedChannels);
776   - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
777 761 break;
778 762 }
779 763 case BulkCode::BSETCHANNELS: {
780 764 // SetChannels2250 bulk command for active channels
781   - static_cast<BulkSetChannels2250 *>(command[(uint8_t)BulkCode::BSETCHANNELS])->setUsedChannels((uint8_t)usedChannels);
782   - commandPending[(uint8_t)BulkCode::BSETCHANNELS] = true;
783   -
  765 + modifyCommand<BulkSetChannels2250>(BulkCode::BSETCHANNELS)->setUsedChannels((uint8_t)usedChannels);
784 766 break;
785 767 }
786 768 case BulkCode::ESETTRIGGERORSAMPLERATE: {
787 769 // SetTrigger5200s bulk command for trigger source
788   - static_cast<BulkSetTrigger5200 *>(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE])->setUsedChannels((uint8_t)usedChannels);
789   - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
  770 + modifyCommand<BulkSetTrigger5200>(BulkCode::ESETTRIGGERORSAMPLERATE)->setUsedChannels((uint8_t)usedChannels);
790 771 break;
791 772 }
792 773 default:
... ... @@ -806,16 +787,15 @@ Dso::ErrorCode HantekDsoControl::setChannelUsed(unsigned channel, bool used) {
806 787 /// \param channel The channel that should be set.
807 788 /// \param coupling The new coupling for the channel.
808 789 /// \return See ::Dso::ErrorCode.
809   -Dso::ErrorCode HantekDsoControl::setCoupling(unsigned channel, Dso::Coupling coupling) {
  790 +Dso::ErrorCode HantekDsoControl::setCoupling(ChannelID channel, Dso::Coupling coupling) {
810 791 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
811 792  
812   - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER;
  793 + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER;
813 794  
814 795 // SetRelays control command for coupling relays
815 796 if (specification.supportsCouplingRelays) {
816   - static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS])
817   - ->setCoupling(channel, coupling != Dso::COUPLING_AC);
818   - this->controlPending[CONTROLINDEX_SETRELAYS] = true;
  797 + modifyCommand<ControlSetRelays>(ControlCode::CONTROL_SETRELAYS)
  798 + ->setCoupling(channel, coupling != Dso::Coupling::AC);
819 799 }
820 800  
821 801 return Dso::ErrorCode::NONE;
... ... @@ -826,10 +806,10 @@ Dso::ErrorCode HantekDsoControl::setCoupling(unsigned channel, Dso::Coupling cou
826 806 /// \param channel The channel that should be set.
827 807 /// \param gain The gain that should be met (V/div).
828 808 /// \return The gain that has been set, ::Dso::ErrorCode on error.
829   -Dso::ErrorCode HantekDsoControl::setGain(unsigned channel, double gain) {
  809 +Dso::ErrorCode HantekDsoControl::setGain(ChannelID channel, double gain) {
830 810 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
831 811  
832   - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER;
  812 + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER;
833 813  
834 814 // Find lowest gain voltage thats at least as high as the requested
835 815 unsigned gainID;
... ... @@ -838,25 +818,21 @@ Dso::ErrorCode HantekDsoControl::setGain(unsigned channel, double gain) {
838 818  
839 819 if (specification.useControlNoBulk) {
840 820 if (channel == 0) {
841   - static_cast<ControlSetVoltDIV_CH1 *>(this->control[CONTROLINDEX_SETVOLTDIV_CH1])
  821 + modifyCommand<ControlSetVoltDIV_CH1>(ControlCode::CONTROL_SETVOLTDIV_CH1)
842 822 ->setDiv(specification.gain[gainID].gainIndex);
843   - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true;
844 823 } else if (channel == 1) {
845   - static_cast<ControlSetVoltDIV_CH2 *>(this->control[CONTROLINDEX_SETVOLTDIV_CH2])
  824 + modifyCommand<ControlSetVoltDIV_CH2>(ControlCode::CONTROL_SETVOLTDIV_CH2)
846 825 ->setDiv(specification.gain[gainID].gainIndex);
847   - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true;
848 826 } else
849 827 qDebug("%s: Unsuported channel: %i\n", __func__, channel);
850 828 } else {
851 829 // SetGain bulk command for gain
852   - static_cast<BulkSetGain *>(command[(uint8_t)BulkCode::SETGAIN])->setGain(channel, specification.gain[gainID].gainIndex);
853   - commandPending[(uint8_t)BulkCode::SETGAIN] = true;
  830 + modifyCommand<BulkSetGain>(BulkCode::SETGAIN)->setGain(channel, specification.gain[gainID].gainIndex);
854 831  
855 832 // SetRelays control command for gain relays
856   - ControlSetRelays *controlSetRelays = static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS]);
  833 + ControlSetRelays *controlSetRelays = modifyCommand<ControlSetRelays>(ControlCode::CONTROL_SETRELAYS);
857 834 controlSetRelays->setBelow1V(channel, gainID < 3);
858 835 controlSetRelays->setBelow100mV(channel, gainID < 6);
859   - this->controlPending[CONTROLINDEX_SETRELAYS] = true;
860 836 }
861 837  
862 838 controlsettings.voltage[channel].gain = gainID;
... ... @@ -870,28 +846,27 @@ Dso::ErrorCode HantekDsoControl::setGain(unsigned channel, double gain) {
870 846 /// Get the actual offset for the channel from controlsettings.voltage[channel].offsetReal
871 847 /// \param channel The channel that should be set.
872 848 /// \param offset The new offset value (0.0 - 1.0).
873   -Dso::ErrorCode HantekDsoControl::setOffset(unsigned channel, double offset) {
  849 +Dso::ErrorCode HantekDsoControl::setOffset(ChannelID channel, const double offset) {
874 850 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
875 851  
876   - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER;
877   -
878   - Offset& channelOffLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain];
879   - // Calculate the offset value
880   - // The range is given by the calibration data (convert from big endian)
881   - unsigned short int minimum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.start)) << 8) +
882   - *((unsigned char *)&(channelOffLimit.start) + 1);
883   - unsigned short int maximum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.end)) << 8) +
884   - *((unsigned char *)&(channelOffLimit.end) + 1);
885   - unsigned short int offsetValue = offset * (maximum - minimum) + minimum + 0.5;
886   - double offsetReal = (double)(offsetValue - minimum) / (maximum - minimum);
  852 + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER;
887 853  
888 854 if (specification.supportsOffset) {
889   - static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])->setChannel(channel, offsetValue);
890   - this->controlPending[CONTROLINDEX_SETOFFSET] = true;
  855 + Offset &channelOffLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain];
  856 + // Calculate the offset value
  857 + // The range is given by the calibration data (convert from big endian)
  858 + unsigned short int minimum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.start)) << 8) +
  859 + *((unsigned char *)&(channelOffLimit.start) + 1);
  860 + unsigned short int maximum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.end)) << 8) +
  861 + *((unsigned char *)&(channelOffLimit.end) + 1);
  862 + unsigned short int offsetValue = offset * (maximum - minimum) + minimum + 0.5;
  863 + double offsetReal = (double)(offsetValue - minimum) / (maximum - minimum);
  864 +
  865 + modifyCommand<ControlSetOffset>(ControlCode::CONTROL_SETOFFSET)->setChannel(channel, offsetValue);
  866 + controlsettings.voltage[channel].offsetReal = offsetReal;
891 867 }
892 868  
893 869 controlsettings.voltage[channel].offset = offset;
894   - controlsettings.voltage[channel].offsetReal = offsetReal;
895 870  
896 871 this->setTriggerLevel(channel, controlsettings.trigger.level[channel]);
897 872  
... ... @@ -903,8 +878,6 @@ Dso::ErrorCode HantekDsoControl::setOffset(unsigned channel, double offset) {
903 878 Dso::ErrorCode HantekDsoControl::setTriggerMode(Dso::TriggerMode mode) {
904 879 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
905 880  
906   - if (mode < Dso::TRIGGERMODE_AUTO || mode >= Dso::TRIGGERMODE_COUNT) return Dso::ErrorCode::PARAMETER;
907   -
908 881 controlsettings.trigger.mode = mode;
909 882 return Dso::ErrorCode::NONE;
910 883 }
... ... @@ -917,34 +890,26 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) {
917 890 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
918 891 if (specification.isSoftwareTriggerDevice) return Dso::ErrorCode::UNSUPPORTED;
919 892  
920   - if (!special && id >= HANTEK_CHANNELS)
921   - return Dso::ErrorCode::PARAMETER;
  893 + if (!special && id >= specification.channels) return Dso::ErrorCode::PARAMETER;
922 894  
923   - if (special && id >= specification.specialTriggerChannels.size())
924   - return Dso::ErrorCode::PARAMETER;
  895 + if (special && id >= specification.specialTriggerChannels.size()) return Dso::ErrorCode::PARAMETER;
925 896  
926   - int hardwareID = special ? specification.specialTriggerChannels[id].hardwareID:(int)id;
  897 + int hardwareID = special ? specification.specialTriggerChannels[id].hardwareID : (int)id;
927 898  
928 899 switch (specification.command.bulk.setTrigger) {
929 900 case BulkCode::SETTRIGGERANDSAMPLERATE:
930 901 // SetTriggerAndSamplerate bulk command for trigger source
931   - static_cast<BulkSetTriggerAndSamplerate *>(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])
932   - ->setTriggerSource(1 - hardwareID);
933   - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
  902 + modifyCommand<BulkSetTriggerAndSamplerate>(BulkCode::SETTRIGGERANDSAMPLERATE)->setTriggerSource(1 - hardwareID);
934 903 break;
935 904  
936 905 case BulkCode::CSETTRIGGERORSAMPLERATE:
937 906 // SetTrigger2250 bulk command for trigger source
938   - static_cast<BulkSetTrigger2250 *>(command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE])
939   - ->setTriggerSource(2 + hardwareID);
940   - commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true;
  907 + modifyCommand<BulkSetTrigger2250>(BulkCode::CSETTRIGGERORSAMPLERATE)->setTriggerSource(2 + hardwareID);
941 908 break;
942 909  
943 910 case BulkCode::ESETTRIGGERORSAMPLERATE:
944 911 // SetTrigger5200 bulk command for trigger source
945   - static_cast<BulkSetTrigger5200 *>(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE])
946   - ->setTriggerSource(1 - hardwareID);
947   - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
  912 + modifyCommand<BulkSetTrigger5200>(BulkCode::ESETTRIGGERORSAMPLERATE)->setTriggerSource(1 - hardwareID);
948 913 break;
949 914  
950 915 default:
... ... @@ -952,8 +917,7 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) {
952 917 }
953 918  
954 919 // SetRelays control command for external trigger relay
955   - static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS])->setTrigger(special);
956   - this->controlPending[CONTROLINDEX_SETRELAYS] = true;
  920 + modifyCommand<ControlSetRelays>(ControlCode::CONTROL_SETRELAYS)->setTrigger(special);
957 921  
958 922 controlsettings.trigger.special = special;
959 923 controlsettings.trigger.source = id;
... ... @@ -961,8 +925,7 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) {
961 925 // Apply trigger level of the new source
962 926 if (special) {
963 927 // SetOffset control command for changed trigger level
964   - static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])->setTrigger(0x7f);
965   - this->controlPending[CONTROLINDEX_SETOFFSET] = true;
  928 + modifyCommand<ControlSetOffset>(ControlCode::CONTROL_SETOFFSET)->setTrigger(0x7f);
966 929 } else
967 930 this->setTriggerLevel(id, controlsettings.trigger.level[id]);
968 931  
... ... @@ -973,20 +936,23 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) {
973 936 /// \param channel The channel that should be set.
974 937 /// \param level The new trigger level (V).
975 938 /// \return The trigger level that has been set, ::Dso::ErrorCode on error.
976   -Dso::ErrorCode HantekDsoControl::setTriggerLevel(unsigned channel, double level) {
  939 +Dso::ErrorCode HantekDsoControl::setTriggerLevel(ChannelID channel, double level) {
977 940 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
978 941  
979   - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER;
  942 + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER;
  943 +
  944 + controlsettings.trigger.level[channel] = level;
  945 + if (!specification.supportsOffset) return Dso::ErrorCode::UNSUPPORTED;
980 946  
981 947 // Calculate the trigger level value
982 948 unsigned short minimum, maximum;
983 949 if (specification.sampleSize > 8) {
984   - Offset& offsetLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain];
  950 + Offset &offsetLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain];
985 951 // The range is the same as used for the offsets for 10 bit models
986 952 minimum = ((unsigned short)*((unsigned char *)&(offsetLimit.start)) << 8) +
987 953 *((unsigned char *)&(offsetLimit.start) + 1);
988   - maximum = ((unsigned short)*((unsigned char *)&(offsetLimit.end)) << 8) +
989   - *((unsigned char *)&(offsetLimit.end) + 1);
  954 + maximum =
  955 + ((unsigned short)*((unsigned char *)&(offsetLimit.end)) << 8) + *((unsigned char *)&(offsetLimit.end) + 1);
990 956 } else {
991 957 // It's from 0x00 to 0xfd for the 8 bit models
992 958 minimum = 0x00;
... ... @@ -997,19 +963,17 @@ Dso::ErrorCode HantekDsoControl::setTriggerLevel(unsigned channel, double level)
997 963 const unsigned gainID = controlsettings.voltage[channel].gain;
998 964 const double offsetReal = controlsettings.voltage[channel].offsetReal;
999 965 const double gainStep = specification.gain[gainID].gainSteps;
1000   - unsigned short levelValue = qBound(
  966 + const unsigned short levelValue = qBound(
1001 967 minimum, (unsigned short)(((offsetReal + level / gainStep) * (maximum - minimum) + 0.5) + minimum), maximum);
1002 968  
1003 969 // Check if the set channel is the trigger source
1004   - if (!controlsettings.trigger.special && channel == controlsettings.trigger.source && specification.supportsOffset) {
  970 + if (!controlsettings.trigger.special && channel == controlsettings.trigger.source) {
1005 971 // SetOffset control command for trigger level
1006   - static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])->setTrigger(levelValue);
1007   - this->controlPending[CONTROLINDEX_SETOFFSET] = true;
  972 + modifyCommand<ControlSetOffset>(ControlCode::CONTROL_SETOFFSET)->setTrigger(levelValue);
1008 973 }
1009 974  
1010 975 /// \todo Get alternating trigger in here
1011 976  
1012   - controlsettings.trigger.level[channel] = level;
1013 977 return Dso::ErrorCode::NONE;
1014 978 }
1015 979  
... ... @@ -1019,25 +983,20 @@ Dso::ErrorCode HantekDsoControl::setTriggerLevel(unsigned channel, double level)
1019 983 Dso::ErrorCode HantekDsoControl::setTriggerSlope(Dso::Slope slope) {
1020 984 if (!device->isConnected()) return Dso::ErrorCode::CONNECTION;
1021 985  
1022   - if (slope >= Dso::SLOPE_COUNT) return Dso::ErrorCode::PARAMETER;
1023   -
1024 986 switch (specification.command.bulk.setTrigger) {
1025 987 case BulkCode::SETTRIGGERANDSAMPLERATE: {
1026 988 // SetTriggerAndSamplerate bulk command for trigger slope
1027   - static_cast<BulkSetTriggerAndSamplerate *>(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])->setTriggerSlope(slope);
1028   - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
  989 + modifyCommand<BulkSetTriggerAndSamplerate>(BulkCode::SETTRIGGERANDSAMPLERATE)->setTriggerSlope((uint8_t)slope);
1029 990 break;
1030 991 }
1031 992 case BulkCode::CSETTRIGGERORSAMPLERATE: {
1032 993 // SetTrigger2250 bulk command for trigger slope
1033   - static_cast<BulkSetTrigger2250 *>(command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE])->setTriggerSlope(slope);
1034   - commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true;
  994 + modifyCommand<BulkSetTrigger2250>(BulkCode::CSETTRIGGERORSAMPLERATE)->setTriggerSlope((uint8_t)slope);
1035 995 break;
1036 996 }
1037 997 case BulkCode::ESETTRIGGERORSAMPLERATE: {
1038 998 // SetTrigger5200 bulk command for trigger slope
1039   - static_cast<BulkSetTrigger5200 *>(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE])->setTriggerSlope(slope);
1040   - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
  999 + modifyCommand<BulkSetTrigger5200>(BulkCode::ESETTRIGGERORSAMPLERATE)->setTriggerSlope((uint8_t)slope);
1041 1000 break;
1042 1001 }
1043 1002 default:
... ... @@ -1048,7 +1007,7 @@ Dso::ErrorCode HantekDsoControl::setTriggerSlope(Dso::Slope slope) {
1048 1007 return Dso::ErrorCode::NONE;
1049 1008 }
1050 1009  
1051   -void HantekDsoControl::forceTrigger() { commandPending[(uint8_t)BulkCode::FORCETRIGGER] = true; }
  1010 +void HantekDsoControl::forceTrigger() { modifyCommand<BulkCommand>(BulkCode::FORCETRIGGER); }
1052 1011  
1053 1012 /// \brief Set the trigger position.
1054 1013 /// \param position The new trigger position (in s).
... ... @@ -1060,17 +1019,16 @@ Dso::ErrorCode HantekDsoControl::setPretriggerPosition(double position) {
1060 1019 double positionSamples = position * controlsettings.samplerate.current;
1061 1020 unsigned recordLength = getRecordLength();
1062 1021 // Fast rate mode uses both channels
1063   - if (controlsettings.samplerate.limits == &specification.samplerate.multi) positionSamples /= HANTEK_CHANNELS;
  1022 + if (isFastRate()) positionSamples /= specification.channels;
1064 1023  
1065 1024 switch (specification.command.bulk.setPretrigger) {
1066 1025 case BulkCode::SETTRIGGERANDSAMPLERATE: {
1067 1026 // Calculate the position value (Start point depending on record length)
1068   - unsigned position = isRollMode() ? 0x1 : 0x7ffff - recordLength + (unsigned)positionSamples;
  1027 + unsigned triggerPosition = isRollMode() ? 0x1 : 0x7ffff - recordLength + (unsigned)positionSamples;
1069 1028  
1070 1029 // SetTriggerAndSamplerate bulk command for trigger position
1071   - static_cast<BulkSetTriggerAndSamplerate *>(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])->setTriggerPosition(position);
1072   - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
1073   -
  1030 + modifyCommand<BulkSetTriggerAndSamplerate>(BulkCode::SETTRIGGERANDSAMPLERATE)
  1031 + ->setTriggerPosition(triggerPosition);
1074 1032 break;
1075 1033 }
1076 1034 case BulkCode::FSETBUFFER: {
... ... @@ -1079,11 +1037,9 @@ Dso::ErrorCode HantekDsoControl::setPretriggerPosition(double position) {
1079 1037 unsigned positionPost = 0x7ffff - (unsigned)positionSamples;
1080 1038  
1081 1039 // SetBuffer2250 bulk command for trigger position
1082   - BulkSetBuffer2250 *commandSetBuffer2250 = static_cast<BulkSetBuffer2250 *>(command[(uint8_t)BulkCode::FSETBUFFER]);
  1040 + BulkSetBuffer2250 *commandSetBuffer2250 = modifyCommand<BulkSetBuffer2250>(BulkCode::FSETBUFFER);
1083 1041 commandSetBuffer2250->setTriggerPositionPre(positionPre);
1084 1042 commandSetBuffer2250->setTriggerPositionPost(positionPost);
1085   - commandPending[(uint8_t)BulkCode::FSETBUFFER] = true;
1086   -
1087 1043 break;
1088 1044 }
1089 1045 case BulkCode::ESETTRIGGERORSAMPLERATE: {
... ... @@ -1092,11 +1048,9 @@ Dso::ErrorCode HantekDsoControl::setPretriggerPosition(double position) {
1092 1048 unsigned positionPost = 0xffff - (unsigned)positionSamples;
1093 1049  
1094 1050 // SetBuffer5200 bulk command for trigger position
1095   - BulkSetBuffer5200 *commandSetBuffer5200 = static_cast<BulkSetBuffer5200 *>(command[(uint8_t)BulkCode::DSETBUFFER]);
  1051 + BulkSetBuffer5200 *commandSetBuffer5200 = modifyCommand<BulkSetBuffer5200>(BulkCode::DSETBUFFER);
1096 1052 commandSetBuffer5200->setTriggerPositionPre((unsigned short)positionPre);
1097 1053 commandSetBuffer5200->setTriggerPositionPost((unsigned short)positionPost);
1098   - commandPending[(uint8_t)BulkCode::DSETBUFFER] = true;
1099   -
1100 1054 break;
1101 1055 }
1102 1056 default:
... ... @@ -1113,83 +1067,90 @@ Dso::ErrorCode HantekDsoControl::stringCommand(const QString &amp;commandString) {
1113 1067 QStringList commandParts = commandString.split(' ', QString::SkipEmptyParts);
1114 1068  
1115 1069 if (commandParts.count() < 1) return Dso::ErrorCode::PARAMETER;
1116   -
1117 1070 if (commandParts[0] != "send") return Dso::ErrorCode::UNSUPPORTED;
1118   -
1119 1071 if (commandParts.count() < 2) return Dso::ErrorCode::PARAMETER;
1120 1072  
1121   - if (commandParts[1] == "bulk") {
1122   - QString data = commandString.section(' ', 2, -1, QString::SectionSkipEmpty);
1123   - unsigned char commandCode = 0;
  1073 + uint8_t codeIndex = 0;
  1074 + hexParse(commandParts[2], &codeIndex, 1);
  1075 + QString data = commandString.section(' ', 2, -1, QString::SectionSkipEmpty);
1124 1076  
1125   - // Read command code (First byte)
1126   - hexParse(commandParts[2], &commandCode, 1);
1127   - if (commandCode > (uint8_t)BulkCode::COUNT) return Dso::ErrorCode::UNSUPPORTED;
  1077 + if (commandParts[1] == "bulk") {
  1078 + if (!command[codeIndex]) return Dso::ErrorCode::UNSUPPORTED;
1128 1079  
1129   - // Update bulk command and mark as pending
1130   - hexParse(data, command[commandCode]->data(), command[commandCode]->getSize());
1131   - commandPending[commandCode] = true;
  1080 + BulkCommand *c = modifyCommand<BulkCommand>((BulkCode)codeIndex);
  1081 + hexParse(data, c->data(), c->getSize());
1132 1082 return Dso::ErrorCode::NONE;
1133 1083 } else if (commandParts[1] == "control") {
1134   - unsigned char controlCode = 0;
1135   -
1136   - // Read command code (First byte)
1137   - hexParse(commandParts[2], &controlCode, 1);
1138   - int cIndex;
1139   - for (cIndex = 0; cIndex < CONTROLINDEX_COUNT; ++cIndex) {
1140   - if (this->controlCode[cIndex] == controlCode) break;
1141   - }
1142   - if (cIndex >= CONTROLINDEX_COUNT) return Dso::ErrorCode::UNSUPPORTED;
  1084 + if (!control[codeIndex]) return Dso::ErrorCode::UNSUPPORTED;
1143 1085  
1144   - QString data = commandString.section(' ', 3, -1, QString::SectionSkipEmpty);
1145   -
1146   - // Update control command and mark as pending
1147   - hexParse(data, this->control[cIndex]->data(), this->control[cIndex]->getSize());
1148   - this->controlPending[cIndex] = true;
  1086 + ControlCommand *c = modifyCommand<ControlCommand>((ControlCode)codeIndex);
  1087 + hexParse(data, c->data(), c->getSize());
1149 1088 return Dso::ErrorCode::NONE;
1150 1089 } else
1151 1090 return Dso::ErrorCode::UNSUPPORTED;
1152 1091 }
1153 1092  
  1093 +void HantekDsoControl::addCommand(BulkCode code, BulkCommand *newCommand, bool pending) {
  1094 + newCommand->pending = pending;
  1095 + command[(uint8_t)code] = newCommand;
  1096 + newCommand->next = firstBulkCommand;
  1097 + firstBulkCommand = newCommand;
  1098 +}
  1099 +
  1100 +const BulkCommand *HantekDsoControl::getCommand(BulkCode code) const { return command[(uint8_t)code]; }
  1101 +
  1102 +void HantekDsoControl::addCommand(ControlCode code, ControlCommand *newCommand, bool pending) {
  1103 + newCommand->pending = pending;
  1104 + control[(uint8_t)code] = newCommand;
  1105 + newCommand->next = firstControlCommand;
  1106 + firstControlCommand = newCommand;
  1107 +}
  1108 +
  1109 +const ControlCommand *HantekDsoControl::getCommand(ControlCode code) const { return control[(uint8_t)code]; }
  1110 +
1154 1111 void HantekDsoControl::run() {
1155 1112 int errorCode = 0;
1156 1113  
1157 1114 // Send all pending bulk commands
1158   - for (int cIndex = 0; cIndex < (uint8_t)BulkCode::COUNT; ++cIndex) {
1159   - if (!commandPending[cIndex]) continue;
  1115 + BulkCommand *bulkCommand = firstBulkCommand;
  1116 + while (bulkCommand) {
  1117 + if (bulkCommand->pending) {
  1118 + timestampDebug(
  1119 + QString("Sending bulk command:%1").arg(hexDump(bulkCommand->data(), bulkCommand->getSize())));
1160 1120  
1161   - timestampDebug(
1162   - QString("Sending bulk command:%1").arg(hexDump(command[cIndex]->data(), command[cIndex]->getSize())));
1163   -
1164   - errorCode = device->bulkCommand(command[cIndex]);
1165   - if (errorCode < 0) {
1166   - qWarning("Sending bulk command %02x failed: %s", cIndex, libUsbErrorString(errorCode).toLocal8Bit().data());
1167   - emit communicationError();
1168   - return;
1169   - } else
1170   - commandPending[cIndex] = false;
  1121 + errorCode = device->bulkCommand(bulkCommand);
  1122 + if (errorCode < 0) {
  1123 + qWarning() << "Sending bulk command failed: " << libUsbErrorString(errorCode);
  1124 + emit communicationError();
  1125 + return;
  1126 + } else
  1127 + bulkCommand->pending = false;
  1128 + }
  1129 + bulkCommand = bulkCommand->next;
1171 1130 }
1172 1131  
1173 1132 // Send all pending control commands
1174   - for (int cIndex = 0; cIndex < CONTROLINDEX_COUNT; ++cIndex) {
1175   - if (!this->controlPending[cIndex]) continue;
1176   -
1177   - timestampDebug(QString("Sending control command %1:%2")
1178   - .arg(QString::number(this->controlCode[control], 16),
1179   - hexDump(this->control[control]->data(), this->control[control]->getSize())));
1180   -
1181   - errorCode = device->controlWrite(this->controlCode[cIndex], this->control[cIndex]->data(),
1182   - this->control[cIndex]->getSize());
1183   - if (errorCode < 0) {
1184   - qWarning("Sending control command %2x failed: %s", this->controlCode[cIndex],
1185   - libUsbErrorString(errorCode).toLocal8Bit().data());
  1133 + ControlCommand *controlCommand = firstControlCommand;
  1134 + while (controlCommand) {
  1135 + if (controlCommand->pending) {
  1136 + timestampDebug(QString("Sending control command %1:%2")
  1137 + .arg(QString::number(control[cIndex], 16),
  1138 + hexDump(this->control[control]->data(), this->control[control]->getSize())));
  1139 +
  1140 + errorCode =
  1141 + device->controlWrite((uint8_t)controlCommand->code, controlCommand->data(), controlCommand->getSize());
  1142 + if (errorCode < 0) {
  1143 + qWarning("Sending control command %2x failed: %s", (uint8_t)controlCommand->code,
  1144 + libUsbErrorString(errorCode).toLocal8Bit().data());
1186 1145  
1187   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1188   - emit communicationError();
1189   - return;
1190   - }
1191   - } else
1192   - this->controlPending[cIndex] = false;
  1146 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  1147 + emit communicationError();
  1148 + return;
  1149 + }
  1150 + } else
  1151 + controlCommand->pending = false;
  1152 + }
  1153 + controlCommand = controlCommand->next;
1193 1154 }
1194 1155  
1195 1156 // State machine for the device communication
... ... @@ -1207,9 +1168,9 @@ void HantekDsoControl::run() {
1207 1168 }
1208 1169  
1209 1170 // Sampling hasn't started, update the expected sample count
1210   - this->previousSampleCount = this->getSampleCount();
  1171 + expectedSampleCount = this->getSampleCount();
1211 1172  
1212   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::STARTSAMPLING]);
  1173 + errorCode = device->bulkCommand(getCommand(BulkCode::STARTSAMPLING));
1213 1174 if (errorCode < 0) {
1214 1175 if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1215 1176 emit communicationError();
... ... @@ -1225,7 +1186,7 @@ void HantekDsoControl::run() {
1225 1186 break;
1226 1187  
1227 1188 case RollState::ENABLETRIGGER:
1228   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::ENABLETRIGGER]);
  1189 + errorCode = device->bulkCommand(getCommand(BulkCode::ENABLETRIGGER));
1229 1190 if (errorCode < 0) {
1230 1191 if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1231 1192 emit communicationError();
... ... @@ -1239,7 +1200,7 @@ void HantekDsoControl::run() {
1239 1200 break;
1240 1201  
1241 1202 case RollState::FORCETRIGGER:
1242   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::FORCETRIGGER]);
  1203 + errorCode = device->bulkCommand(getCommand(BulkCode::FORCETRIGGER));
1243 1204 if (errorCode < 0) {
1244 1205 if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1245 1206 emit communicationError();
... ... @@ -1253,7 +1214,7 @@ void HantekDsoControl::run() {
1253 1214 break;
1254 1215  
1255 1216 case RollState::GETDATA: {
1256   - std::vector<unsigned char> rawData = this->getSamples(previousSampleCount);
  1217 + std::vector<unsigned char> rawData = this->getSamples(expectedSampleCount);
1257 1218 if (this->_samplingStarted) {
1258 1219 convertRawDataToSamples(rawData);
1259 1220 emit samplesAvailable();
... ... @@ -1261,7 +1222,8 @@ void HantekDsoControl::run() {
1261 1222 }
1262 1223  
1263 1224 // Check if we're in single trigger mode
1264   - if (controlsettings.trigger.mode == Dso::TRIGGERMODE_SINGLE && this->_samplingStarted) this->stopSampling();
  1225 + if (controlsettings.trigger.mode == Dso::TriggerMode::SINGLE && this->_samplingStarted)
  1226 + this->stopSampling();
1265 1227  
1266 1228 // Sampling completed, restart it when necessary
1267 1229 this->_samplingStarted = false;
... ... @@ -1293,7 +1255,7 @@ void HantekDsoControl::run() {
1293 1255 case CAPTURE_READY:
1294 1256 case CAPTURE_READY2250:
1295 1257 case CAPTURE_READY5200: {
1296   - std::vector<unsigned char> rawData = this->getSamples(previousSampleCount);
  1258 + std::vector<unsigned char> rawData = this->getSamples(expectedSampleCount);
1297 1259 if (this->_samplingStarted) {
1298 1260 convertRawDataToSamples(rawData);
1299 1261 emit samplesAvailable();
... ... @@ -1301,20 +1263,22 @@ void HantekDsoControl::run() {
1301 1263 }
1302 1264  
1303 1265 // Check if we're in single trigger mode
1304   - if (controlsettings.trigger.mode == Dso::TRIGGERMODE_SINGLE && this->_samplingStarted) this->stopSampling();
  1266 + if (controlsettings.trigger.mode == Dso::TriggerMode::SINGLE && this->_samplingStarted)
  1267 + this->stopSampling();
1305 1268  
1306 1269 // Sampling completed, restart it when necessary
1307 1270 this->_samplingStarted = false;
1308 1271  
1309 1272 // Start next capture if necessary by leaving out the break statement
1310   - if (!this->sampling) break;
1311 1273  
  1274 + if (!this->sampling) break;
1312 1275 #if __has_cpp_attribute(fallthrough) // Make compiler happy
1313   - [[fallthrough]];
  1276 + else
  1277 + [[fallthrough]];
1314 1278 #endif
1315 1279 case CAPTURE_WAITING:
1316 1280 // Sampling hasn't started, update the expected sample count
1317   - this->previousSampleCount = this->getSampleCount();
  1281 + expectedSampleCount = this->getSampleCount();
1318 1282  
1319 1283 if (this->_samplingStarted && this->lastTriggerMode == controlsettings.trigger.mode) {
1320 1284 ++this->cycleCounter;
... ... @@ -1322,7 +1286,7 @@ void HantekDsoControl::run() {
1322 1286 if (this->cycleCounter == this->startCycle && !isRollMode()) {
1323 1287 // Buffer refilled completely since start of sampling, enable the
1324 1288 // trigger now
1325   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::ENABLETRIGGER]);
  1289 + errorCode = device->bulkCommand(getCommand(BulkCode::ENABLETRIGGER));
1326 1290 if (errorCode < 0) {
1327 1291 if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1328 1292 emit communicationError();
... ... @@ -1333,9 +1297,9 @@ void HantekDsoControl::run() {
1333 1297  
1334 1298 timestampDebug("Enabling trigger");
1335 1299 } else if (this->cycleCounter >= 8 + this->startCycle &&
1336   - controlsettings.trigger.mode == Dso::TRIGGERMODE_AUTO) {
  1300 + controlsettings.trigger.mode == Dso::TriggerMode::AUTO) {
1337 1301 // Force triggering
1338   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::FORCETRIGGER]);
  1302 + errorCode = device->bulkCommand(getCommand(BulkCode::FORCETRIGGER));
1339 1303 if (errorCode < 0) {
1340 1304 if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1341 1305 emit communicationError();
... ... @@ -1351,7 +1315,7 @@ void HantekDsoControl::run() {
1351 1315 }
1352 1316  
1353 1317 // Start capturing
1354   - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::STARTSAMPLING]);
  1318 + errorCode = device->bulkCommand(getCommand(BulkCode::STARTSAMPLING));
1355 1319 if (errorCode < 0) {
1356 1320 if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1357 1321 emit communicationError();
... ...
openhantek/src/hantekdso/hantekdsocontrol.h
... ... @@ -2,14 +2,20 @@
2 2  
3 3 #pragma once
4 4  
  5 +#define NOMINMAX // disable windows.h min/max global methods
  6 +#include <limits>
  7 +
5 8 #include "errorcodes.h"
6 9 #include "dsosamples.h"
7 10 #include "states.h"
8 11 #include "controlspecification.h"
9 12 #include "controlsettings.h"
10   -#include "controlindexes.h"
11 13 #include "utils/printutils.h"
12 14  
  15 +#include "hantekprotocol/definitions.h"
  16 +#include "hantekprotocol/bulkStructs.h"
  17 +#include "hantekprotocol/controlStructs.h"
  18 +
13 19 #include <vector>
14 20  
15 21 #include <QMutex>
... ... @@ -52,6 +58,10 @@ class HantekDsoControl : public QObject {
52 58 /// \return The number of physical channels.
53 59 unsigned getChannelCount();
54 60  
  61 + /// Return the read-only device control settings. Use the set- Methods to change
  62 + /// device settings.
  63 + const Dso::ControlSettings *getDeviceSettings() const;
  64 +
55 65 /// \brief Get available record lengths for this oscilloscope.
56 66 /// \return The number of physical channels, empty list for continuous.
57 67 const std::vector<unsigned> &getAvailableRecordLengths();
... ... @@ -86,6 +96,19 @@ class HantekDsoControl : public QObject {
86 96 /// \return See ::Dso::ErrorCode.
87 97 Dso::ErrorCode stringCommand(const QString &commandString);
88 98  
  99 + void addCommand(Hantek::BulkCode code, Hantek::BulkCommand* newCommand, bool pending = true);
  100 + template<class T> T* modifyCommand(Hantek::BulkCode code) {
  101 + command[(uint8_t)code]->pending = true;
  102 + return static_cast<T*>(command[(uint8_t)code]);
  103 + }
  104 + const Hantek::BulkCommand* getCommand(Hantek::BulkCode code) const;
  105 +
  106 + void addCommand(Hantek::ControlCode code, Hantek::ControlCommand* newCommand, bool pending = true);
  107 + template<class T> T* modifyCommand(Hantek::ControlCode code) {
  108 + control[(uint8_t)code]->pending = true;
  109 + return static_cast<T*>(control[(uint8_t)code]);
  110 + }
  111 + const Hantek::ControlCommand* getCommand(Hantek::ControlCode code) const;
89 112 private:
90 113 bool isRollMode() const;
91 114 bool isFastRate() const;
... ... @@ -122,7 +145,7 @@ class HantekDsoControl : public QObject {
122 145 std::pair<int, unsigned> getCaptureState() const;
123 146  
124 147 /// \brief Gets sample data from the oscilloscope
125   - std::vector<unsigned char> getSamples(unsigned &previousSampleCount) const;
  148 + std::vector<unsigned char> getSamples(unsigned &expectedSampleCount) const;
126 149  
127 150 /// \brief Converts raw oscilloscope data to sample data
128 151 void convertRawDataToSamples(const std::vector<unsigned char> &rawData);
... ... @@ -130,7 +153,7 @@ class HantekDsoControl : public QObject {
130 153 /// \brief Sets the size of the sample buffer without updating dependencies.
131 154 /// \param index The record length index that should be set.
132 155 /// \return The record length that has been set, 0 on error.
133   - unsigned updateRecordLength(unsigned size);
  156 + unsigned updateRecordLength(RecordLengthID size);
134 157  
135 158 /// \brief Sets the samplerate based on the parameters calculated by
136 159 /// Control::getBestSamplerate.
... ... @@ -145,29 +168,24 @@ class HantekDsoControl : public QObject {
145 168 /// \brief Update the minimum and maximum supported samplerate.
146 169 void updateSamplerateLimits();
147 170  
148   - public: // TODO redo command queues
149   - /// Pointers to bulk commands, ready to be transmitted
150   - Hantek::BulkCommand *command[(uint8_t)Hantek::BulkCode::COUNT] = {0};
151   - /// true, when the command should be executed
152   - bool commandPending[(uint8_t)Hantek::BulkCode::COUNT] = {false};
153   - ///< Pointers to control commands
154   - Hantek::ControlCommand *control[Hantek::CONTROLINDEX_COUNT] = {0};
155   - ///< Request codes for control commands
156   - unsigned char controlCode[Hantek::CONTROLINDEX_COUNT];
157   - ///< true, when the control command should be executed
158   - bool controlPending[Hantek::CONTROLINDEX_COUNT] = {false};
159 171 private:
  172 + /// Pointers to bulk/control commands
  173 + Hantek::BulkCommand *command[255] = {0};
  174 + Hantek::BulkCommand* firstBulkCommand = nullptr;
  175 + Hantek::ControlCommand *control[255] = {0};
  176 + Hantek::ControlCommand* firstControlCommand = nullptr;
  177 +
160 178 // Communication with device
161 179 USBDevice *device; ///< The USB device for the oscilloscope
162 180 bool sampling = false; ///< true, if the oscilloscope is taking samples
163 181  
164 182 // Device setup
165   - Hantek::ControlSpecification specification; ///< The specifications of the device
166   - Hantek::ControlSettings controlsettings; ///< The current settings of the device
  183 + Dso::ControlSpecification specification; ///< The specifications of the device
  184 + Dso::ControlSettings controlsettings; ///< The current settings of the device
167 185  
168 186 // Results
169 187 DSOsamples result;
170   - unsigned previousSampleCount = 0; ///< The expected total number of samples at
  188 + unsigned expectedSampleCount = 0; ///< The expected total number of samples at
171 189 /// the last check before sampling started
172 190  
173 191 // State of the communication thread
... ... @@ -187,14 +205,14 @@ class HantekDsoControl : public QObject {
187 205 Dso::ErrorCode setSamplerate(double samplerate = 0.0);
188 206 Dso::ErrorCode setRecordTime(double duration = 0.0);
189 207  
190   - Dso::ErrorCode setChannelUsed(unsigned channel, bool used);
191   - Dso::ErrorCode setCoupling(unsigned channel, Dso::Coupling coupling);
192   - Dso::ErrorCode setGain(unsigned channel, double gain);
193   - Dso::ErrorCode setOffset(unsigned channel, double offset);
  208 + Dso::ErrorCode setChannelUsed(ChannelID channel, bool used);
  209 + Dso::ErrorCode setCoupling(ChannelID channel, Dso::Coupling coupling);
  210 + Dso::ErrorCode setGain(ChannelID channel, double gain);
  211 + Dso::ErrorCode setOffset(ChannelID channel, const double offset);
194 212  
195 213 Dso::ErrorCode setTriggerMode(Dso::TriggerMode mode);
196 214 Dso::ErrorCode setTriggerSource(bool special, unsigned id);
197   - Dso::ErrorCode setTriggerLevel(unsigned channel, double level);
  215 + Dso::ErrorCode setTriggerLevel(ChannelID channel, double level);
198 216 Dso::ErrorCode setTriggerSlope(Dso::Slope slope);
199 217 Dso::ErrorCode setPretriggerPosition(double position);
200 218 void forceTrigger();
... ...
openhantek/src/hantekdso/models/modelDSO2090.cpp
1 1 #include "modelDSO2090.h"
2 2 #include "hantekprotocol/bulkStructs.h"
  3 +#include "hantekprotocol/controlStructs.h"
3 4 #include "hantekdsocontrol.h"
4 5  
5 6 using namespace Hantek;
6 7  
7   -ModelDSO2090::ModelDSO2090() : DSOModel(ID, 0x04b5, 0x2090, 0x04b4, 0x2090, "dso2090x86", "DSO-2090", Hantek::ControlSpecification()) {
8   - specification.command.control.setOffset = CONTROL_SETOFFSET;
9   - specification.command.control.setRelays = CONTROL_SETRELAYS;
10   - specification.command.bulk.setGain = BulkCode::SETGAIN;
  8 +ModelDSO2090::ModelDSO2090() : DSOModel(ID, 0x04b5, 0x2090, 0x04b4, 0x2090, "dso2090x86", "DSO-2090", Dso::ControlSpecification()) {
11 9 specification.command.bulk.setRecordLength = BulkCode::SETTRIGGERANDSAMPLERATE;
12 10 specification.command.bulk.setChannels = BulkCode::SETTRIGGERANDSAMPLERATE;
13 11 specification.command.bulk.setSamplerate = BulkCode::SETTRIGGERANDSAMPLERATE;
... ... @@ -32,11 +30,9 @@ ModelDSO2090::ModelDSO2090() : DSOModel(ID, 0x04b5, 0x2090, 0x04b4, 0x2090, &quot;dso
32 30 }
33 31  
34 32 void ModelDSO2090::applyRequirements(HantekDsoControl *dsoControl) const {
35   - dsoControl->command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = new BulkSetTriggerAndSamplerate();
36   - dsoControl->commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
37   -
38   - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true;
39   - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true;
  33 + dsoControl->addCommand(BulkCode::SETTRIGGERANDSAMPLERATE, new BulkSetTriggerAndSamplerate());
  34 + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset());
  35 + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays());
40 36 }
41 37  
42 38 ModelDSO2090A::ModelDSO2090A() {
... ...
openhantek/src/hantekdso/models/modelDSO2150.cpp
1 1 #include "modelDSO2150.h"
2 2 #include "hantekprotocol/bulkStructs.h"
  3 +#include "hantekprotocol/controlStructs.h"
3 4 #include "hantekdsocontrol.h"
4 5  
5 6 using namespace Hantek;
6 7  
7   -ModelDSO2150::ModelDSO2150() : DSOModel(ID, 0x04b5, 0x2150, 0x04b4, 0x2150, "dso2150x86", "DSO-2150", Hantek::ControlSpecification()) {
8   - specification.command.control.setOffset = CONTROL_SETOFFSET;
9   - specification.command.control.setRelays = CONTROL_SETRELAYS;
10   - specification.command.bulk.setGain = BulkCode::SETGAIN;
  8 +ModelDSO2150::ModelDSO2150() : DSOModel(ID, 0x04b5, 0x2150, 0x04b4, 0x2150, "dso2150x86", "DSO-2150", Dso::ControlSpecification()) {
11 9 specification.command.bulk.setRecordLength = BulkCode::SETTRIGGERANDSAMPLERATE;
12 10 specification.command.bulk.setChannels = BulkCode::SETTRIGGERANDSAMPLERATE;
13 11 specification.command.bulk.setSamplerate = BulkCode::SETTRIGGERANDSAMPLERATE;
... ... @@ -32,8 +30,7 @@ ModelDSO2150::ModelDSO2150() : DSOModel(ID, 0x04b5, 0x2150, 0x04b4, 0x2150, &quot;dso
32 30 }
33 31  
34 32 void ModelDSO2150::applyRequirements(HantekDsoControl *dsoControl) const {
35   - dsoControl->command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = new BulkSetTriggerAndSamplerate();
36   - dsoControl->commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true;
37   - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true;
38   - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true;
  33 + dsoControl->addCommand(BulkCode::SETTRIGGERANDSAMPLERATE, new BulkSetTriggerAndSamplerate());
  34 + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset());
  35 + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays());
39 36 }
... ...
openhantek/src/hantekdso/models/modelDSO2250.cpp
1 1 #include "modelDSO2250.h"
2 2 #include "hantekprotocol/bulkStructs.h"
  3 +#include "hantekprotocol/controlStructs.h"
3 4 #include "hantekdsocontrol.h"
4 5  
5 6 using namespace Hantek;
6 7  
7   -ModelDSO2250::ModelDSO2250() : DSOModel(ID, 0x04b5, 0x2250, 0x04b4, 0x2250, "dso2250x86", "DSO-2250", Hantek::ControlSpecification()) {
8   - specification.command.control.setOffset = CONTROL_SETOFFSET;
9   - specification.command.control.setRelays = CONTROL_SETRELAYS;
10   - specification.command.bulk.setGain = BulkCode::SETGAIN;
  8 +ModelDSO2250::ModelDSO2250() : DSOModel(ID, 0x04b5, 0x2250, 0x04b4, 0x2250, "dso2250x86", "DSO-2250", Dso::ControlSpecification()) {
11 9 specification.command.bulk.setRecordLength = BulkCode::DSETBUFFER;
12 10 specification.command.bulk.setChannels = BulkCode::BSETCHANNELS;
13 11 specification.command.bulk.setSamplerate = BulkCode::ESETTRIGGERORSAMPLERATE;
... ... @@ -33,17 +31,11 @@ ModelDSO2250::ModelDSO2250() : DSOModel(ID, 0x04b5, 0x2250, 0x04b4, 0x2250, &quot;dso
33 31  
34 32 void ModelDSO2250::applyRequirements(HantekDsoControl *dsoControl) const {
35 33 // Instantiate additional commands for the DSO-2250
36   - dsoControl->command[(uint8_t)BulkCode::BSETCHANNELS] = new BulkSetChannels2250();
37   - dsoControl->command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = new BulkSetTrigger2250();
38   - dsoControl->command[(uint8_t)BulkCode::DSETBUFFER] = new BulkSetRecordLength2250();
39   - dsoControl->command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = new BulkSetSamplerate2250();
40   - dsoControl->command[(uint8_t)BulkCode::FSETBUFFER] = new BulkSetBuffer2250();
41   - dsoControl->commandPending[(uint8_t)BulkCode::BSETCHANNELS] = true;
42   - dsoControl->commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true;
43   - dsoControl->commandPending[(uint8_t)BulkCode::DSETBUFFER] = true;
44   - dsoControl->commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
45   - dsoControl->commandPending[(uint8_t)BulkCode::FSETBUFFER] = true;
46   -
47   - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true;
48   - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true;
  34 + dsoControl->addCommand(BulkCode::BSETCHANNELS, new BulkSetChannels2250());
  35 + dsoControl->addCommand(BulkCode::CSETTRIGGERORSAMPLERATE, new BulkSetTrigger2250());
  36 + dsoControl->addCommand(BulkCode::DSETBUFFER, new BulkSetRecordLength2250());
  37 + dsoControl->addCommand(BulkCode::ESETTRIGGERORSAMPLERATE, new BulkSetSamplerate2250());
  38 + dsoControl->addCommand(BulkCode::FSETBUFFER, new BulkSetBuffer2250());
  39 + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset());
  40 + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays());
49 41 }
... ...
openhantek/src/hantekdso/models/modelDSO5200.cpp
1 1 #include "modelDSO5200.h"
2 2 #include "hantekprotocol/bulkStructs.h"
  3 +#include "hantekprotocol/controlStructs.h"
3 4 #include "hantekdsocontrol.h"
4 5  
5 6 using namespace Hantek;
6 7  
7   -ModelDSO5200::ModelDSO5200() : DSOModel(ID, 0x04b5, 0x5200, 0x04b4, 0x5200, "dso5200x86", "DSO-5200", Hantek::ControlSpecification()) {
8   - specification.command.control.setOffset = CONTROL_SETOFFSET;
9   - specification.command.control.setRelays = CONTROL_SETRELAYS;
10   - specification.command.bulk.setGain = BulkCode::SETGAIN;
  8 +ModelDSO5200::ModelDSO5200() : DSOModel(ID, 0x04b5, 0x5200, 0x04b4, 0x5200, "dso5200x86", "DSO-5200", Dso::ControlSpecification()) {
11 9 specification.command.bulk.setRecordLength = BulkCode::DSETBUFFER;
12 10 specification.command.bulk.setChannels = BulkCode::ESETTRIGGERORSAMPLERATE;
13 11 specification.command.bulk.setSamplerate = BulkCode::CSETTRIGGERORSAMPLERATE;
... ... @@ -35,15 +33,11 @@ ModelDSO5200::ModelDSO5200() : DSOModel(ID, 0x04b5, 0x5200, 0x04b4, 0x5200, &quot;dso
35 33  
36 34 void ModelDSO5200::applyRequirements(HantekDsoControl *dsoControl) const {
37 35 // Instantiate additional commands for the DSO-5200
38   - dsoControl->command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = new BulkSetSamplerate5200();
39   - dsoControl->command[(uint8_t)BulkCode::DSETBUFFER] = new BulkSetBuffer5200();
40   - dsoControl->command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = new BulkSetTrigger5200();
41   - dsoControl->commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true;
42   - dsoControl->commandPending[(uint8_t)BulkCode::DSETBUFFER] = true;
43   - dsoControl->commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true;
44   -
45   - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true;
46   - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true;
  36 + dsoControl->addCommand(BulkCode::CSETTRIGGERORSAMPLERATE, new BulkSetSamplerate5200());
  37 + dsoControl->addCommand(BulkCode::DSETBUFFER, new BulkSetBuffer5200());
  38 + dsoControl->addCommand(BulkCode::ESETTRIGGERORSAMPLERATE, new BulkSetTrigger5200());
  39 + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset());
  40 + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays());
47 41 }
48 42  
49 43 ModelDSO5200A::ModelDSO5200A() {
... ...
openhantek/src/hantekdso/models/modelDSO6022.cpp
1 1 #include "modelDSO6022.h"
2 2 #include "usb/usbdevice.h"
3 3 #include "hantekprotocol/controlStructs.h"
4   -#include "controlindexes.h"
5 4 #include "hantekdsocontrol.h"
6 5  
7 6 using namespace Hantek;
8 7  
9   -ModelDSO6022BE::ModelDSO6022BE() : DSOModel(ID, 0x04b5, 0x6022, 0x04b4, 0x6022, "dso6022be", "DSO-6022BE", Hantek::ControlSpecification()) {
  8 +ModelDSO6022BE::ModelDSO6022BE() : DSOModel(ID, 0x04b5, 0x6022, 0x04b4, 0x6022, "dso6022be", "DSO-6022BE", Dso::ControlSpecification()) {
10 9 // 6022BE do not support any bulk commands
11 10 specification.useControlNoBulk = true;
12 11 specification.isSoftwareTriggerDevice = true;
... ... @@ -33,29 +32,17 @@ ModelDSO6022BE::ModelDSO6022BE() : DSOModel(ID, 0x04b5, 0x6022, 0x04b4, 0x6022,
33 32 specification.fixedSampleRates = { {10,1e5} , {20,2e5} , {50,5e5} , {1,1e6} , {2,2e6} , {4,4e6} , {8,8e6} ,
34 33 {16,16e6} , {24,24e6} , {48,48e6} };
35 34 specification.sampleSize = 8;
  35 +
  36 + specification.couplings = {Dso::Coupling::DC};
36 37 }
37 38  
38 39 void ModelDSO6022BE::applyRequirements(HantekDsoControl *dsoControl) const {
39 40 dsoControl->getDevice()->overwriteInPacketLength(16384);
40 41  
41   - dsoControl->control[CONTROLINDEX_SETVOLTDIV_CH1] = new ControlSetVoltDIV_CH1();
42   - dsoControl->controlCode[CONTROLINDEX_SETVOLTDIV_CH1] = CONTROL_SETVOLTDIV_CH1;
43   - dsoControl->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true;
44   -
45   - dsoControl->control[CONTROLINDEX_SETVOLTDIV_CH2] = new ControlSetVoltDIV_CH2();
46   - dsoControl->controlCode[CONTROLINDEX_SETVOLTDIV_CH2] = CONTROL_SETVOLTDIV_CH2;
47   - dsoControl->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true;
48   -
49   - dsoControl->control[CONTROLINDEX_SETTIMEDIV] = new ControlSetTimeDIV();
50   - dsoControl->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
51   - dsoControl->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
52   -
53   - dsoControl->control[CONTROLINDEX_ACQUIIRE_HARD_DATA] = new ControlAcquireHardData();
54   - dsoControl->controlCode[CONTROLINDEX_ACQUIIRE_HARD_DATA] = CONTROL_ACQUIIRE_HARD_DATA;
55   - dsoControl->controlPending[CONTROLINDEX_ACQUIIRE_HARD_DATA] = true;
56   -
57   - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = false;
58   - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = false;
  42 + dsoControl->addCommand(ControlCode::CONTROL_ACQUIIRE_HARD_DATA, new ControlAcquireHardData());
  43 + dsoControl->addCommand(ControlCode::CONTROL_SETTIMEDIV, new ControlSetTimeDIV());
  44 + dsoControl->addCommand(ControlCode::CONTROL_SETVOLTDIV_CH2, new ControlSetVoltDIV_CH2());
  45 + dsoControl->addCommand(ControlCode::CONTROL_SETVOLTDIV_CH1, new ControlSetVoltDIV_CH1());
59 46 }
60 47  
61 48 ModelDSO6022LE::ModelDSO6022LE() {
... ...
openhantek/src/hantekdso/softwaretrigger.cpp 0 → 100644
  1 +#include "softwaretrigger.h"
  2 +#include "analyse/dataanalyzerresult.h"
  3 +#include "settings.h"
  4 +#include "viewconstants.h"
  5 +#include "utils/printutils.h"
  6 +
  7 +SoftwareTrigger::PrePostStartTriggerSamples SoftwareTrigger::computeTY(const DataAnalyzerResult *result,
  8 + const DsoSettingsScope *scope,
  9 + unsigned physicalChannels)
  10 +{
  11 + unsigned int preTrigSamples = 0;
  12 + unsigned int postTrigSamples = 0;
  13 + unsigned int swTriggerStart = 0;
  14 + unsigned int channel = scope->trigger.source;
  15 +
  16 + // check trigger point for software trigger
  17 + if (scope->trigger.mode != Dso::TriggerMode::SOFTWARE || channel >= physicalChannels)
  18 + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
  19 +
  20 + // Trigger channel not in use
  21 + if (!scope->voltage[channel].used || !result->data(channel) ||
  22 + result->data(channel)->voltage.sample.empty())
  23 + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
  24 +
  25 + const std::vector<double>& samples = result->data(channel)->voltage.sample;
  26 + double level = scope->voltage[channel].trigger;
  27 + size_t sampleCount = samples.size();
  28 + double timeDisplay = scope->horizontal.timebase * DIVS_TIME;
  29 + double samplesDisplay = timeDisplay * scope->horizontal.samplerate;
  30 +
  31 + if (samplesDisplay >= sampleCount) {
  32 + // For sure not enough samples to adjust for jitter.
  33 + // Following options exist:
  34 + // 1: Decrease sample rate
  35 + // 2: Change trigger mode to auto
  36 + // 3: Ignore samples
  37 + // For now #3 is chosen
  38 + timestampDebug(QString("Too few samples to make a steady "
  39 + "picture. Decrease sample rate"));
  40 + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
  41 + }
  42 + preTrigSamples = (unsigned)(scope->trigger.position * samplesDisplay);
  43 + postTrigSamples = (unsigned)sampleCount - ((unsigned)samplesDisplay - preTrigSamples);
  44 +
  45 + const int swTriggerThreshold = 7;
  46 + const int swTriggerSampleSet = 11;
  47 + double prev;
  48 + bool (*opcmp)(double,double,double);
  49 + bool (*smplcmp)(double,double);
  50 + if (scope->trigger.slope == Dso::Slope::Positive) {
  51 + prev = INT_MAX;
  52 + opcmp = [](double value, double level, double prev) { return value > level && prev <= level;};
  53 + smplcmp = [](double sampleK, double value) { return sampleK >= value;};
  54 + } else {
  55 + prev = INT_MIN;
  56 + opcmp = [](double value, double level, double prev) { return value < level && prev >= level;};
  57 + smplcmp = [](double sampleK, double value) { return sampleK < value;};
  58 + }
  59 +
  60 + for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) {
  61 + double value = samples[i];
  62 + if (opcmp(value, level, prev)) {
  63 + int rising = 0;
  64 + for (unsigned int k = i + 1; k < i + swTriggerSampleSet && k < sampleCount; k++) {
  65 + if (smplcmp(samples[k], value)) { rising++; }
  66 + }
  67 + if (rising > swTriggerThreshold) {
  68 + swTriggerStart = i;
  69 + break;
  70 + }
  71 + }
  72 + prev = value;
  73 + }
  74 + if (swTriggerStart == 0) {
  75 + timestampDebug(QString("Trigger not asserted. Data ignored"));
  76 + preTrigSamples = 0; // preTrigSamples may never be greater than swTriggerStart
  77 + postTrigSamples = 0;
  78 + }
  79 + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart);
  80 +}
... ...
openhantek/src/hantekdso/softwaretrigger.h 0 → 100644
  1 +#pragma once
  2 +#include <tuple>
  3 +struct DsoSettingsScope;
  4 +class DataAnalyzerResult;
  5 +
  6 +class SoftwareTrigger
  7 +{
  8 +public:
  9 + typedef std::tuple<unsigned, unsigned, unsigned> PrePostStartTriggerSamples;
  10 + static PrePostStartTriggerSamples computeTY(const DataAnalyzerResult *result,
  11 + const DsoSettingsScope *scope,
  12 + unsigned physicalChannels);
  13 +};
... ...
openhantek/src/hantekprotocol/bulkStructs.h
... ... @@ -16,6 +16,9 @@ namespace Hantek {
16 16 class BulkCommand : public DataArray<uint8_t> {
17 17 protected:
18 18 BulkCommand(unsigned size): DataArray<uint8_t>(size) {}
  19 +public:
  20 + bool pending = false;
  21 + BulkCommand* next = nullptr;
19 22 };
20 23  
21 24 //////////////////////////////////////////////////////////////////////////////
... ...
openhantek/src/hantekprotocol/bulkcode.h
... ... @@ -4,482 +4,460 @@
4 4  
5 5 namespace Hantek {
6 6  
7   -//////////////////////////////////////////////////////////////////////////////
8   -/// \enum BulkCode hantek/types.h
9 7 /// \brief All supported bulk commands.
10 8 /// Indicies given in square brackets specify byte numbers in little endian
11 9 /// format.
  10 +/// SETFILTER [<em>MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO5200, MODEL_DSO5200A</em>]
  11 +/// <p>
  12 +/// This command sets channel and trigger filter:
  13 +/// <table>
  14 +/// <tr>
  15 +/// <td>0x00</td>
  16 +/// <td>0x00</td>
  17 +/// <td>FilterBits</td>
  18 +/// <td>0x00</td>
  19 +/// <td>0x00</td>
  20 +/// <td>0x00</td>
  21 +/// <td>0x00</td>
  22 +/// <td>0x00</td>
  23 +/// </tr>
  24 +/// </table>
  25 +/// </p>
  26 +///
  27 +/// This command is used by the official %Hantek software, but doesn't seem
  28 +/// to be used by the device.
  29 +///
  30 +///
  31 +/// SETTRIGGERANDSAMPLERATE [<em>::MODEL_DSO2090, ::MODEL_DSO2150</em>]
  32 +/// <p>
  33 +/// This command sets trigger and timebase:
  34 +/// <table>
  35 +/// <tr>
  36 +/// <td>0x01</td>
  37 +/// <td>0x00</td>
  38 +/// <td>Tsr1Bits</td>
  39 +/// <td>Tsr2Bits</td>
  40 +/// <td>Downsampler[0]</td>
  41 +/// <td>Downsampler[1]</td>
  42 +/// </tr>
  43 +/// </table>
  44 +/// <table>
  45 +/// <tr>
  46 +/// <td>TriggerPosition[0]</td>
  47 +/// <td>TriggerPosition[1]</td>
  48 +/// <td>0x00</td>
  49 +/// <td>0x00</td>
  50 +/// <td>TriggerPosition[2]</td>
  51 +/// <td>0x00</td>
  52 +/// </tr>
  53 +/// </table>
  54 +/// </p>
  55 +/// <p>
  56 +/// The samplerate is set relative to the base samplerate by a divider or to
  57 +/// a maximum samplerate.<br />
  58 +/// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to
  59 +/// the following values:
  60 +/// <table>
  61 +/// <tr>
  62 +/// <td><b>Tsr1Bits.samplerateId</b></td><td>0</td><td>1</td><td>2</td><td>3</td>
  63 +/// </tr>
  64 +/// <tr>
  65 +/// <td><b>Samplerate</b></td><td>Max</td><td>Base</td><td>Base /
  66 +/// 2</td><td>Base / 5</td>
  67 +/// </tr>
  68 +/// </table>
  69 +/// For higher divider values, the value can be set using the 16-bit value
  70 +/// in the two Downsampler bytes. The value of Downsampler is given by:<br
  71 +/// />
  72 +/// <i>Downsampler = 1comp((Base / Samplerate / 2) - 2)</i><br />
  73 +/// The Base samplerate is 50 MS/s for the DSO-2090 and DSO-2150. The Max
  74 +/// samplerate is also 50 MS/s for the DSO-2090 and 75 MS/s for the
  75 +/// DSO-2150.<br />
  76 +/// When using fast rate mode the Base and Max samplerate is twice as fast.
  77 +/// When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided
  78 +/// by 1000.
  79 +/// </p>
  80 +/// <p>
  81 +/// The TriggerPosition sets the position of the pretrigger in samples. The
  82 +/// left side (0 %) is 0x77660 when using the small buffer and 0x78000 when
  83 +/// using the large buffer.
  84 +/// </p>
  85 +///
  86 +/// FORCETRIGGER [<em>MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A</em>]
  87 +/// <p>
  88 +/// This command forces triggering:
  89 +/// <table>
  90 +/// <tr>
  91 +/// <td>0x02</td>
  92 +/// <td>0x00</td>
  93 +/// </tr>
  94 +/// </table>
  95 +/// </p>
  96 +///
  97 +///
  98 +/// STARTSAMPLING [<em>MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A</em>]
  99 +/// <p>
  100 +/// This command starts to capture data:
  101 +/// <table>
  102 +/// <tr>
  103 +/// <td>0x03</td>
  104 +/// <td>0x00</td>
  105 +/// </tr>
  106 +/// </table>
  107 +/// </p>
  108 +///
  109 +///
  110 +/// ENABLETRIGGER [<em>MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A</em>]
  111 +/// <p>
  112 +/// This command sets the trigger:
  113 +/// <table>
  114 +/// <tr>
  115 +/// <td>0x04</td>
  116 +/// <td>0x00</td>
  117 +/// </tr>
  118 +/// </table>
  119 +/// </p>
  120 +///
  121 +///
  122 +/// GETDATA [<em>MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A</em>]
  123 +/// <p>
  124 +/// This command reads data from the hardware:
  125 +/// <table>
  126 +/// <tr>
  127 +/// <td>0x05</td>
  128 +/// <td>0x00</td>
  129 +/// </tr>
  130 +/// </table>
  131 +/// </p>
  132 +/// <p>
  133 +/// The oscilloscope returns the sample data, that will be split if it's
  134 +/// larger than the IN endpoint packet length:
  135 +/// <table>
  136 +/// <tr>
  137 +/// <td>Sample[0]</td>
  138 +/// <td>...</td>
  139 +/// <td>Sample[511]</td>
  140 +/// </tr>
  141 +/// <tr>
  142 +/// <td>Sample[512]</td>
  143 +/// <td>...</td>
  144 +/// <td>Sample[1023]</td>
  145 +/// </tr>
  146 +/// <tr>
  147 +/// <td>Sample[1024]</td>
  148 +/// <td colspan="2">...</td>
  149 +/// </tr>
  150 +/// </table>
  151 +/// Because of the 10 bit data model, the DSO-5200 transmits the two extra
  152 +/// bits for each sample afterwards:
  153 +/// <table>
  154 +/// <tr>
  155 +/// <td>Extra[0] << 2 | Extra[1]</td>
  156 +/// <td>0</td>
  157 +/// <td>Extra[2] << 2 | Extra[3]</td>
  158 +/// <td>0</td>
  159 +/// <td>...</td>
  160 +/// <td>Extra[510] << 2 | Extra[511]</td>
  161 +/// <td>0</td>
  162 +/// </tr>
  163 +/// <tr>
  164 +/// <td>Extra[512] << 2 | Extra[513]</td>
  165 +/// <td colspan="6">...</td>
  166 +/// </tr>
  167 +/// </table>
  168 +/// </p>
  169 +///
  170 +/// GETCAPTURESTATE [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  171 +/// <p>
  172 +/// This command checks the capture state:
  173 +/// <table>
  174 +/// <tr>
  175 +/// <td>0x06</td>
  176 +/// <td>0x00</td>
  177 +/// </tr>
  178 +/// </table>
  179 +/// </p>
  180 +/// <p>
  181 +/// The oscilloscope returns it's capture state and the trigger point. Not
  182 +/// sure about this, looks like 248 16-bit words with nearly constant
  183 +/// values. These can be converted to the start address of the data in the
  184 +/// buffer (See Hantek::Control::calculateTriggerPoint):
  185 +/// <table>
  186 +/// <tr>
  187 +/// <td>::CaptureState</td>
  188 +/// <td>0x00</td>
  189 +/// <td>TriggerPoint[0]</td>
  190 +/// <td>TriggerPoint[1]</td>
  191 +/// <td>...</td>
  192 +/// </tr>
  193 +/// </table>
  194 +/// </p>
  195 +///
  196 +/// SETGAIN [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  197 +/// <p>
  198 +/// This command sets the gain:
  199 +/// <table>
  200 +/// <tr>
  201 +/// <td>0x07</td>
  202 +/// <td>0x00</td>
  203 +/// <td>GainBits</td>
  204 +/// <td>0x00</td>
  205 +/// <td>0x00</td>
  206 +/// <td>0x00</td>
  207 +/// <td>0x00</td>
  208 +/// <td>0x00</td>
  209 +/// </tr>
  210 +/// </table>
  211 +/// It is usually used in combination with ::CONTROL_SETRELAYS.
  212 +/// </p>
  213 +///
  214 +/// SETLOGICALDATA [<em></em>]
  215 +/// <p>
  216 +/// This command sets the logical data (Not used in official %Hantek software):
  217 +/// <table>
  218 +/// <tr>
  219 +/// <td>0x08</td>
  220 +/// <td>0x00</td>
  221 +/// <td>Data | 0x01</td>
  222 +/// <td>0x00</td>
  223 +/// <td>0x00</td>
  224 +/// <td>0x00</td>
  225 +/// <td>0x00</td>
  226 +/// <td>0x00</td>
  227 +/// </tr>
  228 +/// </table>
  229 +/// </p>
  230 +///
  231 +/// GETLOGICALDATA [<em></em>]
  232 +/// <p>
  233 +/// This command reads the logical data (Not used in official %Hantek
  234 +/// software):
  235 +/// <table>
  236 +/// <tr>
  237 +/// <td>0x09</td>
  238 +/// <td>0x00</td>
  239 +/// </tr>
  240 +/// </table>
  241 +/// </p>
  242 +/// <p>
  243 +/// The oscilloscope returns the logical data, which contains valid data in
  244 +/// the first byte although it is 64 or 512 bytes long:
  245 +/// <table>
  246 +/// <tr>
  247 +/// <td>Data</td>
  248 +/// <td>...</td>
  249 +/// </tr>
  250 +/// </table>
  251 +/// </p>
  252 +///
  253 +/// BSETCHANNELS BulkSetChannels2250 [<em>::MODEL_DSO2250</em>]
  254 +/// <p>
  255 +/// This command sets the activated channels for the DSO-2250:
  256 +/// <table>
  257 +/// <tr>
  258 +/// <td>0x0b</td>
  259 +/// <td>0x00</td>
  260 +/// <td>BUsedChannels</td>
  261 +/// <td>0x00</td>
  262 +/// </tr>
  263 +/// </table>
  264 +/// </p>
  265 +///
  266 +/// CSETTRIGGERORSAMPLERATE BulkSetTrigger2250 [<em>::MODEL_DSO2250</em>]
  267 +/// <p>
  268 +/// This command sets the trigger source for the DSO-2250:
  269 +/// <table>
  270 +/// <tr>
  271 +/// <td>0x0c</td>
  272 +/// <td>0x00</td>
  273 +/// <td>CTriggerBits</td>
  274 +/// <td>0x00</td>
  275 +/// <td>0x00</td>
  276 +/// <td>0x00</td>
  277 +/// <td>0x00</td>
  278 +/// <td>0x00</td>
  279 +/// </tr>
  280 +/// </table>
  281 +/// </p>
  282 +///
  283 +/// BulkSetSamplerate5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  284 +/// <p>
  285 +/// This command sets the sampling rate for the DSO-5200:
  286 +/// <table>
  287 +/// <tr>
  288 +/// <td>0x0c</td>
  289 +/// <td>0x00</td>
  290 +/// <td>SamplerateSlow[0]</td>
  291 +/// <td>SamplerateSlow[1]</td>
  292 +/// <td>SamplerateFast</td>
  293 +/// <td>0x00</td>
  294 +/// </tr>
  295 +/// </table>
  296 +/// </p>
  297 +/// <p>
  298 +/// The samplerate is set relative to the maximum sample rate by a divider
  299 +/// that is set in SamplerateFast and the 16-bit value in the two
  300 +/// SamplerateSlow bytes.<br />
  301 +/// Without using fast rate mode, the samplerate is:<br />
  302 +/// <i>Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 -
  303 +/// SamplerateFast)</i><br />
  304 +/// SamplerateBase is 100 MS/s for the DSO-5200 in normal mode and 200 MS/s
  305 +/// in fast rate mode, the modifications regarding record length are the the
  306 +/// same that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
  307 +/// normal mode and 250 MS/s in fast rate mode, and is reached by setting
  308 +/// SamplerateSlow = 0 and SamplerateFast = 4.
  309 +/// </p>
  310 +///
  311 +/// DSETBUFFER BulkSetRecordLength2250 [<em>::MODEL_DSO2250</em>]
  312 +/// <p>
  313 +/// This command sets the record length for the DSO-2250:
  314 +/// <table>
  315 +/// <tr>
  316 +/// <td>0x0d</td>
  317 +/// <td>0x00</td>
  318 +/// <td>::RecordLengthId</td>
  319 +/// <td>0x00</td>
  320 +/// </tr>
  321 +/// </table>
  322 +/// </p>
  323 +///
  324 +/// BulkSetBuffer5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  325 +/// <p>
  326 +/// This command sets the trigger position and record length for the
  327 +/// DSO-5200:
  328 +/// <table>
  329 +/// <tr>
  330 +/// <td>0x0d</td>
  331 +/// <td>0x00</td>
  332 +/// <td>TriggerPositionPre[0]</td>
  333 +/// <td>TriggerPositionPre[1]</td>
  334 +/// <td>::DTriggerPositionUsed</td>
  335 +/// </tr>
  336 +/// </table>
  337 +/// <table>
  338 +/// <tr>
  339 +/// <td>0xff</td>
  340 +/// <td>TriggerPositionPost[0]</td>
  341 +/// <td>TriggerPositionPost[1]</td>
  342 +/// <td>DBufferBits</td>
  343 +/// <td>0xff</td>
  344 +/// </tr>
  345 +/// </table>
  346 +/// </p>
  347 +/// <p>
  348 +/// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
  349 +/// position. Both values have a range from 0xd7ff (0xc7ff for 14 kiS
  350 +/// buffer) to 0xfffe. On the left side (0 %) the TriggerPositionPre value
  351 +/// is minimal, on the right side (100 %) it is maximal. The
  352 +/// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
  353 +/// </p>
  354 +///
  355 +/// ESETTRIGGERORSAMPLERATE BulkSetSamplerate2250 [<em>::MODEL_DSO2250</em>]
  356 +/// <p>
  357 +/// This command sets the samplerate:
  358 +/// <table>
  359 +/// <tr>
  360 +/// <td>0x0e</td>
  361 +/// <td>0x00</td>
  362 +/// <td>ESamplerateBits</td>
  363 +/// <td>0x00</td>
  364 +/// <td>Samplerate[0]</td>
  365 +/// <td>Samplerate[1]</td>
  366 +/// <td>0x00</td>
  367 +/// <td>0x00</td>
  368 +/// </tr>
  369 +/// </table>
  370 +/// </p>
  371 +/// <p>
  372 +/// The downsampler can be activated by setting ESamplerateBits.downsampling
  373 +/// = 1. If this is the case, the value of Downsampler is given by:<br />
  374 +/// <i>Downsampler = 1comp((Base / Samplerate) - 2)</i><br />
  375 +/// Base is 100 MS/s for the DSO-2250 in standard mode and 200 MS/s in fast
  376 +/// rate mode, the modifications regarding record length are the the same
  377 +/// that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
  378 +/// standard mode and 250 MS/s in fast rate mode and is achieved by setting
  379 +/// ESamplerateBits.downsampling = 0.
  380 +/// </p>
  381 +///
  382 +/// ESETTRIGGERORSAMPLERATE BulkSetTrigger5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  383 +/// <p>
  384 +/// This command sets the channel and trigger settings:
  385 +/// <table>
  386 +/// <tr>
  387 +/// <td>0x0e</td>
  388 +/// <td>0x00</td>
  389 +/// <td>ETsrBits</td>
  390 +/// <td>0x00</td>
  391 +/// <td>0x00</td>
  392 +/// <td>0x00</td>
  393 +/// <td>0x00</td>
  394 +/// <td>0x00</td>
  395 +/// </tr>
  396 +/// </table>
  397 +/// </p>
  398 +///
  399 +/// FSETBUFFER BulkSetBuffer2250 [<em>::MODEL_DSO2250</em>]
  400 +/// <p>
  401 +/// This command sets the trigger position and buffer configuration for the
  402 +/// DSO-2250:
  403 +/// <table>
  404 +/// <tr>
  405 +/// <td>0x0f</td>
  406 +/// <td>0x00</td>
  407 +/// <td>TriggerPositionPost[0]</td>
  408 +/// <td>TriggerPositionPost[1]</td>
  409 +/// <td>TriggerPositionPost[2]</td>
  410 +/// <td>0x00</td>
  411 +/// </tr>
  412 +/// </table>
  413 +/// <table>
  414 +/// <tr>
  415 +/// <td>TriggerPositionPre[0]</td>
  416 +/// <td>TriggerPositionPre[1]</td>
  417 +/// <td>TriggerPositionPre[2]</td>
  418 +/// <td>0x00</td>
  419 +/// <td>0x00</td>
  420 +/// <td>0x00</td>
  421 +/// </tr>
  422 +/// </table>
  423 +/// </p>
  424 +/// <p>
  425 +/// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
  426 +/// position. Both values have a range from 0x7d800 (0x00000 for 512 kiS
  427 +/// buffer) to 0x7ffff. On the left side (0 %) the TriggerPositionPre value
  428 +/// is minimal, on the right side (100 %) it is maximal. The
  429 +/// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
  430 +/// </p>
  431 +///
  432 +/// AUNKNOWN [<em></em>]
  433 +/// <p>
  434 +/// This command isn't used for any supported model:
  435 +/// <table>
  436 +/// <tr>
  437 +/// <td>0x0a</td>
  438 +/// <td>...</td>
  439 +/// </tr>
  440 +/// </table>
  441 +/// </p>
  442 +/// <p><br /></p>
12 443 enum class BulkCode : uint8_t {
13   - /// BulkSetFilter [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO5200,
14   - /// ::MODEL_DSO5200A</em>]
15   - /// <p>
16   - /// This command sets channel and trigger filter:
17   - /// <table>
18   - /// <tr>
19   - /// <td>0x00</td>
20   - /// <td>0x00</td>
21   - /// <td>FilterBits</td>
22   - /// <td>0x00</td>
23   - /// <td>0x00</td>
24   - /// <td>0x00</td>
25   - /// <td>0x00</td>
26   - /// <td>0x00</td>
27   - /// </tr>
28   - /// </table>
29   - /// </p>
30   - /// <p>
31   - /// This command is used by the official %Hantek software, but doesn't seem
32   - /// to be used by the device.
33   - /// <p><br /></p>
34   - SETFILTER,
35   -
36   - /// BulkSetTriggerAndSamplerate [<em>::MODEL_DSO2090, ::MODEL_DSO2150</em>]
37   - /// <p>
38   - /// This command sets trigger and timebase:
39   - /// <table>
40   - /// <tr>
41   - /// <td>0x01</td>
42   - /// <td>0x00</td>
43   - /// <td>Tsr1Bits</td>
44   - /// <td>Tsr2Bits</td>
45   - /// <td>Downsampler[0]</td>
46   - /// <td>Downsampler[1]</td>
47   - /// </tr>
48   - /// </table>
49   - /// <table>
50   - /// <tr>
51   - /// <td>TriggerPosition[0]</td>
52   - /// <td>TriggerPosition[1]</td>
53   - /// <td>0x00</td>
54   - /// <td>0x00</td>
55   - /// <td>TriggerPosition[2]</td>
56   - /// <td>0x00</td>
57   - /// </tr>
58   - /// </table>
59   - /// </p>
60   - /// <p>
61   - /// The samplerate is set relative to the base samplerate by a divider or to
62   - /// a maximum samplerate.<br />
63   - /// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to
64   - /// the following values:
65   - /// <table>
66   - /// <tr>
67   - /// <td><b>Tsr1Bits.samplerateId</b></td><td>0</td><td>1</td><td>2</td><td>3</td>
68   - /// </tr>
69   - /// <tr>
70   - /// <td><b>Samplerate</b></td><td>Max</td><td>Base</td><td>Base /
71   - /// 2</td><td>Base / 5</td>
72   - /// </tr>
73   - /// </table>
74   - /// For higher divider values, the value can be set using the 16-bit value
75   - /// in the two Downsampler bytes. The value of Downsampler is given by:<br
76   - /// />
77   - /// <i>Downsampler = 1comp((Base / Samplerate / 2) - 2)</i><br />
78   - /// The Base samplerate is 50 MS/s for the DSO-2090 and DSO-2150. The Max
79   - /// samplerate is also 50 MS/s for the DSO-2090 and 75 MS/s for the
80   - /// DSO-2150.<br />
81   - /// When using fast rate mode the Base and Max samplerate is twice as fast.
82   - /// When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided
83   - /// by 1000.
84   - /// </p>
85   - /// <p>
86   - /// The TriggerPosition sets the position of the pretrigger in samples. The
87   - /// left side (0 %) is 0x77660 when using the small buffer and 0x78000 when
88   - /// using the large buffer.
89   - /// </p>
90   - /// <p><br /></p>
91   - SETTRIGGERANDSAMPLERATE,
92   -
93   - /// BulkForceTrigger [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
94   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
95   - /// <p>
96   - /// This command forces triggering:
97   - /// <table>
98   - /// <tr>
99   - /// <td>0x02</td>
100   - /// <td>0x00</td>
101   - /// </tr>
102   - /// </table>
103   - /// </p>
104   - /// <p><br /></p>
105   - FORCETRIGGER,
106   -
107   - /// BulkCaptureStart [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
108   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
109   - /// <p>
110   - /// This command starts to capture data:
111   - /// <table>
112   - /// <tr>
113   - /// <td>0x03</td>
114   - /// <td>0x00</td>
115   - /// </tr>
116   - /// </table>
117   - /// </p>
118   - /// <p><br /></p>
119   - STARTSAMPLING,
120   -
121   - /// BulkTriggerEnabled [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
122   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
123   - /// <p>
124   - /// This command sets the trigger:
125   - /// <table>
126   - /// <tr>
127   - /// <td>0x04</td>
128   - /// <td>0x00</td>
129   - /// </tr>
130   - /// </table>
131   - /// </p>
132   - /// <p><br /></p>
133   - ENABLETRIGGER,
134   -
135   - /// BulkGetData [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
136   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
137   - /// <p>
138   - /// This command reads data from the hardware:
139   - /// <table>
140   - /// <tr>
141   - /// <td>0x05</td>
142   - /// <td>0x00</td>
143   - /// </tr>
144   - /// </table>
145   - /// </p>
146   - /// <p>
147   - /// The oscilloscope returns the sample data, that will be split if it's
148   - /// larger than the IN endpoint packet length:
149   - /// <table>
150   - /// <tr>
151   - /// <td>Sample[0]</td>
152   - /// <td>...</td>
153   - /// <td>Sample[511]</td>
154   - /// </tr>
155   - /// <tr>
156   - /// <td>Sample[512]</td>
157   - /// <td>...</td>
158   - /// <td>Sample[1023]</td>
159   - /// </tr>
160   - /// <tr>
161   - /// <td>Sample[1024]</td>
162   - /// <td colspan="2">...</td>
163   - /// </tr>
164   - /// </table>
165   - /// Because of the 10 bit data model, the DSO-5200 transmits the two extra
166   - /// bits for each sample afterwards:
167   - /// <table>
168   - /// <tr>
169   - /// <td>Extra[0] << 2 | Extra[1]</td>
170   - /// <td>0</td>
171   - /// <td>Extra[2] << 2 | Extra[3]</td>
172   - /// <td>0</td>
173   - /// <td>...</td>
174   - /// <td>Extra[510] << 2 | Extra[511]</td>
175   - /// <td>0</td>
176   - /// </tr>
177   - /// <tr>
178   - /// <td>Extra[512] << 2 | Extra[513]</td>
179   - /// <td colspan="6">...</td>
180   - /// </tr>
181   - /// </table>
182   - /// </p>
183   - /// <p><br /></p>
184   - GETDATA,
185   -
186   - /// BulkGetCaptureState [<em>::MODEL_DSO2090, ::MODEL_DSO2150,
187   - /// ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
188   - /// <p>
189   - /// This command checks the capture state:
190   - /// <table>
191   - /// <tr>
192   - /// <td>0x06</td>
193   - /// <td>0x00</td>
194   - /// </tr>
195   - /// </table>
196   - /// </p>
197   - /// <p>
198   - /// The oscilloscope returns it's capture state and the trigger point. Not
199   - /// sure about this, looks like 248 16-bit words with nearly constant
200   - /// values. These can be converted to the start address of the data in the
201   - /// buffer (See Hantek::Control::calculateTriggerPoint):
202   - /// <table>
203   - /// <tr>
204   - /// <td>::CaptureState</td>
205   - /// <td>0x00</td>
206   - /// <td>TriggerPoint[0]</td>
207   - /// <td>TriggerPoint[1]</td>
208   - /// <td>...</td>
209   - /// </tr>
210   - /// </table>
211   - /// </p>
212   - /// <p><br /></p>
213   - GETCAPTURESTATE,
214   -
215   - /// BulkSetGain [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
216   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
217   - /// <p>
218   - /// This command sets the gain:
219   - /// <table>
220   - /// <tr>
221   - /// <td>0x07</td>
222   - /// <td>0x00</td>
223   - /// <td>GainBits</td>
224   - /// <td>0x00</td>
225   - /// <td>0x00</td>
226   - /// <td>0x00</td>
227   - /// <td>0x00</td>
228   - /// <td>0x00</td>
229   - /// </tr>
230   - /// </table>
231   - /// It is usually used in combination with ::CONTROL_SETRELAYS.
232   - /// </p>
233   - /// <p><br /></p>
234   - SETGAIN,
235   -
236   - /// BulkSetLogicalData [<em></em>]
237   - /// <p>
238   - /// This command sets the logical data (Not used in official %Hantek
239   - /// software):
240   - /// <table>
241   - /// <tr>
242   - /// <td>0x08</td>
243   - /// <td>0x00</td>
244   - /// <td>Data | 0x01</td>
245   - /// <td>0x00</td>
246   - /// <td>0x00</td>
247   - /// <td>0x00</td>
248   - /// <td>0x00</td>
249   - /// <td>0x00</td>
250   - /// </tr>
251   - /// </table>
252   - /// </p>
253   - /// <p><br /></p>
254   - SETLOGICALDATA,
255   -
256   - /// BulkGetLogicalData [<em></em>]
257   - /// <p>
258   - /// This command reads the logical data (Not used in official %Hantek
259   - /// software):
260   - /// <table>
261   - /// <tr>
262   - /// <td>0x09</td>
263   - /// <td>0x00</td>
264   - /// </tr>
265   - /// </table>
266   - /// </p>
267   - /// <p>
268   - /// The oscilloscope returns the logical data, which contains valid data in
269   - /// the first byte although it is 64 or 512 bytes long:
270   - /// <table>
271   - /// <tr>
272   - /// <td>Data</td>
273   - /// <td>...</td>
274   - /// </tr>
275   - /// </table>
276   - /// </p>
277   - /// <p><br /></p>
278   - GETLOGICALDATA,
279   -
280   - /// [<em></em>]
281   - /// <p>
282   - /// This command isn't used for any supported model:
283   - /// <table>
284   - /// <tr>
285   - /// <td>0x0a</td>
286   - /// <td>...</td>
287   - /// </tr>
288   - /// </table>
289   - /// </p>
290   - /// <p><br /></p>
291   - AUNKNOWN,
292   -
293   - /// BulkSetChannels2250 [<em>::MODEL_DSO2250</em>]
294   - /// <p>
295   - /// This command sets the activated channels for the DSO-2250:
296   - /// <table>
297   - /// <tr>
298   - /// <td>0x0b</td>
299   - /// <td>0x00</td>
300   - /// <td>BUsedChannels</td>
301   - /// <td>0x00</td>
302   - /// </tr>
303   - /// </table>
304   - /// </p>
305   - /// <p><br /></p>
306   - BSETCHANNELS,
307   -
308   - /// BulkSetTrigger2250 [<em>::MODEL_DSO2250</em>]
309   - /// <p>
310   - /// This command sets the trigger source for the DSO-2250:
311   - /// <table>
312   - /// <tr>
313   - /// <td>0x0c</td>
314   - /// <td>0x00</td>
315   - /// <td>CTriggerBits</td>
316   - /// <td>0x00</td>
317   - /// <td>0x00</td>
318   - /// <td>0x00</td>
319   - /// <td>0x00</td>
320   - /// <td>0x00</td>
321   - /// </tr>
322   - /// </table>
323   - /// </p>
324   - /// <p><br /></p>
325   - /// BulkSetSamplerate5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
326   - /// <p>
327   - /// This command sets the sampling rate for the DSO-5200:
328   - /// <table>
329   - /// <tr>
330   - /// <td>0x0c</td>
331   - /// <td>0x00</td>
332   - /// <td>SamplerateSlow[0]</td>
333   - /// <td>SamplerateSlow[1]</td>
334   - /// <td>SamplerateFast</td>
335   - /// <td>0x00</td>
336   - /// </tr>
337   - /// </table>
338   - /// </p>
339   - /// <p>
340   - /// The samplerate is set relative to the maximum sample rate by a divider
341   - /// that is set in SamplerateFast and the 16-bit value in the two
342   - /// SamplerateSlow bytes.<br />
343   - /// Without using fast rate mode, the samplerate is:<br />
344   - /// <i>Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 -
345   - /// SamplerateFast)</i><br />
346   - /// SamplerateBase is 100 MS/s for the DSO-5200 in normal mode and 200 MS/s
347   - /// in fast rate mode, the modifications regarding record length are the the
348   - /// same that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
349   - /// normal mode and 250 MS/s in fast rate mode, and is reached by setting
350   - /// SamplerateSlow = 0 and SamplerateFast = 4.
351   - /// </p>
352   - /// <p><br /></p>
353   - CSETTRIGGERORSAMPLERATE,
354   -
355   - /// BulkSetRecordLength2250 [<em>::MODEL_DSO2250</em>]
356   - /// <p>
357   - /// This command sets the record length for the DSO-2250:
358   - /// <table>
359   - /// <tr>
360   - /// <td>0x0d</td>
361   - /// <td>0x00</td>
362   - /// <td>::RecordLengthId</td>
363   - /// <td>0x00</td>
364   - /// </tr>
365   - /// </table>
366   - /// </p>
367   - /// <p><br /></p>
368   - /// BulkSetBuffer5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
369   - /// <p>
370   - /// This command sets the trigger position and record length for the
371   - /// DSO-5200:
372   - /// <table>
373   - /// <tr>
374   - /// <td>0x0d</td>
375   - /// <td>0x00</td>
376   - /// <td>TriggerPositionPre[0]</td>
377   - /// <td>TriggerPositionPre[1]</td>
378   - /// <td>::DTriggerPositionUsed</td>
379   - /// </tr>
380   - /// </table>
381   - /// <table>
382   - /// <tr>
383   - /// <td>0xff</td>
384   - /// <td>TriggerPositionPost[0]</td>
385   - /// <td>TriggerPositionPost[1]</td>
386   - /// <td>DBufferBits</td>
387   - /// <td>0xff</td>
388   - /// </tr>
389   - /// </table>
390   - /// </p>
391   - /// <p>
392   - /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
393   - /// position. Both values have a range from 0xd7ff (0xc7ff for 14 kiS
394   - /// buffer) to 0xfffe. On the left side (0 %) the TriggerPositionPre value
395   - /// is minimal, on the right side (100 %) it is maximal. The
396   - /// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
397   - /// </p>
398   - /// <p><br /></p>
399   - DSETBUFFER,
400   -
401   - /// BulkSetSamplerate2250 [<em>::MODEL_DSO2250</em>]
402   - /// <p>
403   - /// This command sets the samplerate:
404   - /// <table>
405   - /// <tr>
406   - /// <td>0x0e</td>
407   - /// <td>0x00</td>
408   - /// <td>ESamplerateBits</td>
409   - /// <td>0x00</td>
410   - /// <td>Samplerate[0]</td>
411   - /// <td>Samplerate[1]</td>
412   - /// <td>0x00</td>
413   - /// <td>0x00</td>
414   - /// </tr>
415   - /// </table>
416   - /// </p>
417   - /// <p>
418   - /// The downsampler can be activated by setting ESamplerateBits.downsampling
419   - /// = 1. If this is the case, the value of Downsampler is given by:<br />
420   - /// <i>Downsampler = 1comp((Base / Samplerate) - 2)</i><br />
421   - /// Base is 100 MS/s for the DSO-2250 in standard mode and 200 MS/s in fast
422   - /// rate mode, the modifications regarding record length are the the same
423   - /// that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
424   - /// standard mode and 250 MS/s in fast rate mode and is achieved by setting
425   - /// ESamplerateBits.downsampling = 0.
426   - /// </p>
427   - /// <p><br /></p>
428   - /// BulkSetTrigger5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
429   - /// <p>
430   - /// This command sets the channel and trigger settings:
431   - /// <table>
432   - /// <tr>
433   - /// <td>0x0e</td>
434   - /// <td>0x00</td>
435   - /// <td>ETsrBits</td>
436   - /// <td>0x00</td>
437   - /// <td>0x00</td>
438   - /// <td>0x00</td>
439   - /// <td>0x00</td>
440   - /// <td>0x00</td>
441   - /// </tr>
442   - /// </table>
443   - /// </p>
444   - /// <p><br /></p>
445   - ESETTRIGGERORSAMPLERATE,
446   -
447   - /// BulkSetBuffer2250 [<em>::MODEL_DSO2250</em>]
448   - /// <p>
449   - /// This command sets the trigger position and buffer configuration for the
450   - /// DSO-2250:
451   - /// <table>
452   - /// <tr>
453   - /// <td>0x0f</td>
454   - /// <td>0x00</td>
455   - /// <td>TriggerPositionPost[0]</td>
456   - /// <td>TriggerPositionPost[1]</td>
457   - /// <td>TriggerPositionPost[2]</td>
458   - /// <td>0x00</td>
459   - /// </tr>
460   - /// </table>
461   - /// <table>
462   - /// <tr>
463   - /// <td>TriggerPositionPre[0]</td>
464   - /// <td>TriggerPositionPre[1]</td>
465   - /// <td>TriggerPositionPre[2]</td>
466   - /// <td>0x00</td>
467   - /// <td>0x00</td>
468   - /// <td>0x00</td>
469   - /// </tr>
470   - /// </table>
471   - /// </p>
472   - /// <p>
473   - /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
474   - /// position. Both values have a range from 0x7d800 (0x00000 for 512 kiS
475   - /// buffer) to 0x7ffff. On the left side (0 %) the TriggerPositionPre value
476   - /// is minimal, on the right side (100 %) it is maximal. The
477   - /// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
478   - /// </p>
479   - /// <p><br /></p>
480   - FSETBUFFER,
481   -
482   - COUNT
  444 + SETFILTER = 0x00,
  445 + SETTRIGGERANDSAMPLERATE = 0x01,
  446 + FORCETRIGGER = 0x02,
  447 + STARTSAMPLING = 0x03,
  448 + ENABLETRIGGER = 0x04,
  449 + GETDATA = 0x05,
  450 + GETCAPTURESTATE = 0x06,
  451 + SETGAIN = 0x07,
  452 + SETLOGICALDATA = 0x08,
  453 + GETLOGICALDATA = 0x09,
  454 + AUNKNOWN = 0x0a,
  455 + BSETCHANNELS = 0x0b,
  456 + CSETTRIGGERORSAMPLERATE = 0x0c,
  457 + DSETBUFFER = 0x0d,
  458 + ESETTRIGGERORSAMPLERATE = 0x0e,
  459 + FSETBUFFER = 0x0f,
  460 + INVALID=0xff
483 461 };
484 462  
485 463 }
... ...
openhantek/src/hantekprotocol/controlStructs.cpp
... ... @@ -6,9 +6,9 @@
6 6  
7 7 namespace Hantek {
8 8  
9   -ControlSetOffset::ControlSetOffset() : ControlCommand(17) {}
  9 +ControlSetOffset::ControlSetOffset() : ControlCommand(ControlCode::CONTROL_SETOFFSET, 17) {}
10 10  
11   -ControlSetOffset::ControlSetOffset(uint16_t channel1, uint16_t channel2, uint16_t trigger) : ControlCommand(17) {
  11 +ControlSetOffset::ControlSetOffset(uint16_t channel1, uint16_t channel2, uint16_t trigger) : ControlCommand(ControlCode::CONTROL_SETOFFSET, 17) {
12 12 this->setChannel(0, channel1);
13 13 this->setChannel(1, channel2);
14 14 this->setTrigger(trigger);
... ... @@ -40,7 +40,7 @@ void ControlSetOffset::setTrigger(uint16_t level) {
40 40  
41 41 ControlSetRelays::ControlSetRelays(bool ch1Below1V, bool ch1Below100mV, bool ch1CouplingDC, bool ch2Below1V,
42 42 bool ch2Below100mV, bool ch2CouplingDC, bool triggerExt)
43   - : ControlCommand(17) {
  43 + : ControlCommand(ControlCode::CONTROL_SETRELAYS,17) {
44 44 this->setBelow1V(0, ch1Below1V);
45 45 this->setBelow100mV(0, ch1Below100mV);
46 46 this->setCoupling(0, ch1CouplingDC);
... ... @@ -96,17 +96,17 @@ bool ControlSetRelays::getTrigger() { return (this-&gt;array[7] &amp; 0x01) == 0x00; }
96 96  
97 97 void ControlSetRelays::setTrigger(bool ext) { this->array[7] = ext ? 0xfe : 0x01; }
98 98  
99   -ControlSetVoltDIV_CH1::ControlSetVoltDIV_CH1() : ControlCommand(1) { this->setDiv(5); }
  99 +ControlSetVoltDIV_CH1::ControlSetVoltDIV_CH1() : ControlCommand(ControlCode::CONTROL_SETVOLTDIV_CH1,1) { this->setDiv(5); }
100 100  
101 101 void ControlSetVoltDIV_CH1::setDiv(uint8_t val) { this->array[0] = val; }
102 102  
103   -ControlSetVoltDIV_CH2::ControlSetVoltDIV_CH2() : ControlCommand(1) { this->setDiv(5); }
  103 +ControlSetVoltDIV_CH2::ControlSetVoltDIV_CH2() : ControlCommand(ControlCode::CONTROL_SETVOLTDIV_CH2,1) { this->setDiv(5); }
104 104  
105 105 void ControlSetVoltDIV_CH2::setDiv(uint8_t val) { this->array[0] = val; }
106 106  
107   -ControlSetTimeDIV::ControlSetTimeDIV() : ControlCommand(1) { this->setDiv(1); }
  107 +ControlSetTimeDIV::ControlSetTimeDIV() : ControlCommand(ControlCode::CONTROL_SETTIMEDIV,1) { this->setDiv(1); }
108 108  
109 109 void ControlSetTimeDIV::setDiv(uint8_t val) { this->array[0] = val; }
110 110  
111   -ControlAcquireHardData::ControlAcquireHardData() : ControlCommand(1) { this->array[0] = 0x01; }
  111 +ControlAcquireHardData::ControlAcquireHardData() : ControlCommand(ControlCode::CONTROL_ACQUIIRE_HARD_DATA,1) { this->array[0] = 0x01; }
112 112 }
... ...
openhantek/src/hantekprotocol/controlStructs.h
... ... @@ -3,11 +3,16 @@
3 3 #include "definitions.h"
4 4 #include "usb/usbdevicedefinitions.h"
5 5 #include "utils/dataarray.h"
  6 +#include "controlcode.h"
6 7  
7 8 namespace Hantek {
8 9 class ControlCommand : public DataArray<uint8_t> {
9 10 protected:
10   - ControlCommand(unsigned size): DataArray<uint8_t>(size) {}
  11 + ControlCommand(ControlCode code, unsigned size): DataArray<uint8_t>(size), code(code) {}
  12 +public:
  13 + bool pending = false;
  14 + ControlCode code;
  15 + ControlCommand* next = nullptr;
11 16 };
12 17  
13 18 struct ControlSetOffset : public ControlCommand {
... ...
openhantek/src/hantekprotocol/controlcode.h
1 1 #pragma once
2 2  
  3 +#include <inttypes.h>
  4 +
  5 +namespace Hantek {
3 6  
4   -//////////////////////////////////////////////////////////////////////////////
5   -/// \enum ControlCode hantek/types.h
6 7 /// \brief All supported control commands.
7   -enum ControlCode {
8   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
9   - /// ::MODEL_DSO5200A, MODEL_DSO6022]</em>
10   - /// <p>
11   - /// The 0xa2 control read/write command gives access to a ::ControlValue.
12   - /// </p>
13   - /// <p><br /></p>
14   - CONTROL_VALUE = 0xa2,
15 8  
16   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
17   - /// ::MODEL_DSO5200A, MODEL_DSO6022]</em>
18   - /// <p>
19   - /// The 0xb2 control read command gets the speed level of the USB
20   - /// connection:
21   - /// <table>
22   - /// <tr>
23   - /// <td>::ConnectionSpeed</td>
24   - /// <td>0x00</td>
25   - /// <td>0x00</td>
26   - /// <td>0x00</td>
27   - /// <td>0x00</td>
28   - /// <td>0x00</td>
29   - /// <td>0x00</td>
30   - /// <td>0x00</td>
31   - /// <td>0x00</td>
32   - /// <td>0x00</td>
33   - /// </tr>
34   - /// </table>
35   - /// </p>
36   - /// <p><br /></p>
  9 +/// CONTROL_VALUE <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A, MODEL_DSO6022]</em>
  10 +/// <p>
  11 +/// The 0xa2 control read/write command gives access to a ControlValue.
  12 +/// </p>
  13 +///
  14 +/// CONTROL_GETSPEED <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A, MODEL_DSO6022]</em>
  15 +/// <p>
  16 +/// The 0xb2 control read command gets the speed level of the USB
  17 +/// connection:
  18 +/// <table>
  19 +/// <tr>
  20 +/// <td>ConnectionSpeed</td>
  21 +/// <td>0x00</td>
  22 +/// <td>0x00</td>
  23 +/// <td>0x00</td>
  24 +/// <td>0x00</td>
  25 +/// <td>0x00</td>
  26 +/// <td>0x00</td>
  27 +/// <td>0x00</td>
  28 +/// <td>0x00</td>
  29 +/// <td>0x00</td>
  30 +/// </tr>
  31 +/// </table>
  32 +/// </p>
  33 +///
  34 +/// CONTROL_BEGINCOMMAND <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A]</em>
  35 +/// <p>
  36 +/// The 0xb3 control write command is sent before any bulk command:
  37 +/// <table>
  38 +/// <tr>
  39 +/// <td>0x0f</td>
  40 +/// <td>BulkIndex</td>
  41 +/// <td>BulkIndex</td>
  42 +/// <td>BulkIndex</td>
  43 +/// <td>0x00</td>
  44 +/// <td>0x00</td>
  45 +/// <td>0x00</td>
  46 +/// <td>0x00</td>
  47 +/// <td>0x00</td>
  48 +/// <td>0x00</td>
  49 +/// </tr>
  50 +/// </table>
  51 +/// </p>
  52 +///
  53 +/// CONTROL_SETOFFSET <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A]</em>
  54 +/// <p>
  55 +/// The 0xb4 control write command sets the channel offsets:
  56 +/// <table>
  57 +/// <tr>
  58 +/// <td>Ch1Offset[1]</td>
  59 +/// <td>Ch1Offset[0]</td>
  60 +/// <td>Ch2Offset[1]</td>
  61 +/// <td>Ch2Offset[0]</td>
  62 +/// <td>TriggerOffset[1]</td>
  63 +/// <td>TriggerOffset[0]</td>
  64 +/// </tr>
  65 +/// </table>
  66 +/// <table>
  67 +/// <tr>
  68 +/// <td>0x00</td>
  69 +/// <td>0x00</td>
  70 +/// <td>0x00</td>
  71 +/// <td>0x00</td>
  72 +/// <td>0x00</td>
  73 +/// <td>0x00</td>
  74 +/// <td>0x00</td>
  75 +/// <td>0x00</td>
  76 +/// <td>0x00</td>
  77 +/// <td>0x00</td>
  78 +/// <td>0x00</td>
  79 +/// </tr>
  80 +/// </table>
  81 +/// </p>
  82 +///
  83 +/// CONTROL_SETRELAYS <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A]</em>
  84 +/// <p>
  85 +/// The 0xb5 control write command sets the internal relays:
  86 +/// <table>
  87 +/// <tr>
  88 +/// <td>0x00</td>
  89 +/// <td>0x04 ^ (Ch1Gain < 1 V)</td>
  90 +/// <td>0x08 ^ (Ch1Gain < 100 mV)</td>
  91 +/// <td>0x02 ^ (Ch1Coupling == DC)</td>
  92 +/// </tr>
  93 +/// </table>
  94 +/// <table>
  95 +/// <tr>
  96 +/// <td>0x20 ^ (Ch2Gain < 1 V)</td>
  97 +/// <td>0x40 ^ (Ch2Gain < 100 mV)</td>
  98 +/// <td>0x10 ^ (Ch2Coupling == DC)</td>
  99 +/// <td>0x01 ^ (Trigger == EXT)</td>
  100 +/// </tr>
  101 +/// </table>
  102 +/// <table>
  103 +/// <tr>
  104 +/// <td>0x00</td>
  105 +/// <td>0x00</td>
  106 +/// <td>0x00</td>
  107 +/// <td>0x00</td>
  108 +/// <td>0x00</td>
  109 +/// <td>0x00</td>
  110 +/// <td>0x00</td>
  111 +/// <td>0x00</td>
  112 +/// <td>0x00</td>
  113 +/// </tr>
  114 +/// </table>
  115 +/// </p>
  116 +/// <p>
  117 +/// The limits are <= instead of < for the 10 bit models, since those
  118 +/// support voltages up to 10 V.
  119 +/// </p>
  120 +///
  121 +/// CONTROL_SETVOLTDIV_CH1 CH1 voltage div setting (6022BE/BL)
  122 +///
  123 +/// CONTROL_SETVOLTDIV_CH2 CH2 voltage div setting (6022BE/BL)
  124 +///
  125 +/// CONTROL_SETTIMEDIV Time divisor setting (6022BE/BL)
  126 +///
  127 +/// CONTROL_ACQUIIRE_HARD_DATA Request sample data (6022BE/BL)
  128 +enum class ControlCode : uint8_t {
  129 + CONTROL_VALUE = 0xa2,
37 130 CONTROL_GETSPEED = 0xb2,
38   -
39   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
40   - /// ::MODEL_DSO5200A]</em>
41   - /// <p>
42   - /// The 0xb3 control write command is sent before any bulk command:
43   - /// <table>
44   - /// <tr>
45   - /// <td>0x0f</td>
46   - /// <td>::BulkIndex</td>
47   - /// <td>::BulkIndex</td>
48   - /// <td>::BulkIndex</td>
49   - /// <td>0x00</td>
50   - /// <td>0x00</td>
51   - /// <td>0x00</td>
52   - /// <td>0x00</td>
53   - /// <td>0x00</td>
54   - /// <td>0x00</td>
55   - /// </tr>
56   - /// </table>
57   - /// </p>
58   - /// <p><br /></p>
59 131 CONTROL_BEGINCOMMAND = 0xb3,
60   -
61   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
62   - /// ::MODEL_DSO5200A]</em>
63   - /// <p>
64   - /// The 0xb4 control write command sets the channel offsets:
65   - /// <table>
66   - /// <tr>
67   - /// <td>Ch1Offset[1]</td>
68   - /// <td>Ch1Offset[0]</td>
69   - /// <td>Ch2Offset[1]</td>
70   - /// <td>Ch2Offset[0]</td>
71   - /// <td>TriggerOffset[1]</td>
72   - /// <td>TriggerOffset[0]</td>
73   - /// </tr>
74   - /// </table>
75   - /// <table>
76   - /// <tr>
77   - /// <td>0x00</td>
78   - /// <td>0x00</td>
79   - /// <td>0x00</td>
80   - /// <td>0x00</td>
81   - /// <td>0x00</td>
82   - /// <td>0x00</td>
83   - /// <td>0x00</td>
84   - /// <td>0x00</td>
85   - /// <td>0x00</td>
86   - /// <td>0x00</td>
87   - /// <td>0x00</td>
88   - /// </tr>
89   - /// </table>
90   - /// </p>
91   - /// <p><br /></p>
92 132 CONTROL_SETOFFSET = 0xb4,
93   -
94   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
95   - /// ::MODEL_DSO5200A]</em>
96   - /// <p>
97   - /// The 0xb5 control write command sets the internal relays:
98   - /// <table>
99   - /// <tr>
100   - /// <td>0x00</td>
101   - /// <td>0x04 ^ (Ch1Gain < 1 V)</td>
102   - /// <td>0x08 ^ (Ch1Gain < 100 mV)</td>
103   - /// <td>0x02 ^ (Ch1Coupling == DC)</td>
104   - /// </tr>
105   - /// </table>
106   - /// <table>
107   - /// <tr>
108   - /// <td>0x20 ^ (Ch2Gain < 1 V)</td>
109   - /// <td>0x40 ^ (Ch2Gain < 100 mV)</td>
110   - /// <td>0x10 ^ (Ch2Coupling == DC)</td>
111   - /// <td>0x01 ^ (Trigger == EXT)</td>
112   - /// </tr>
113   - /// </table>
114   - /// <table>
115   - /// <tr>
116   - /// <td>0x00</td>
117   - /// <td>0x00</td>
118   - /// <td>0x00</td>
119   - /// <td>0x00</td>
120   - /// <td>0x00</td>
121   - /// <td>0x00</td>
122   - /// <td>0x00</td>
123   - /// <td>0x00</td>
124   - /// <td>0x00</td>
125   - /// </tr>
126   - /// </table>
127   - /// </p>
128   - /// <p>
129   - /// The limits are <= instead of < for the 10 bit models, since those
130   - /// support voltages up to 10 V.
131   - /// </p>
132   - /// <p><br /></p>
133 133 CONTROL_SETRELAYS = 0xb5,
134   -
135   - /// CH1 voltage div setting (6022BE/BL)
136 134 CONTROL_SETVOLTDIV_CH1 = 0xe0,
137   - /// CH2 voltage div setting (6022BE/BL)
138 135 CONTROL_SETVOLTDIV_CH2 = 0xe1,
139   - /// Time divisor setting (6022BE/BL)
140 136 CONTROL_SETTIMEDIV = 0xe2,
141   - /// Request sample data (6022BE/BL)
142 137 CONTROL_ACQUIIRE_HARD_DATA = 0xe3
143 138 };
144 139  
  140 +}
... ...
openhantek/src/hantekprotocol/controlvalue.h
1 1 #pragma once
2 2  
3   -namespace Hantek {
  3 +#include <inttypes.h>
4 4  
  5 +namespace Hantek {
5 6  
6   -//////////////////////////////////////////////////////////////////////////////
7   -/// \enum ControlValue hantek/types.h
8 7 /// \brief All supported values for control commands.
9   -enum ControlValue {
10   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
11   - /// ::MODEL_DSO5200A]</em>
12   - /// <p>
13   - /// Value 0x08 is the calibration data for the channels offsets. It holds the
14   - /// offset value for the top and bottom of the scope screen for every gain
15   - /// step on every channel. The data is stored as a three-dimensional array:<br
16   - /// />
17   - /// <i>channelLevels[channel][GainId][::LevelOffset]</i>
18   - /// </p>
19   - /// <p><br /></p>
  8 +/// VALUE_OFFSETLIMITS <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A]</em>
  9 +/// <p>
  10 +/// Value 0x08 is the calibration data for the channels offsets. It holds the
  11 +/// offset value for the top and bottom of the scope screen for every gain
  12 +/// step on every channel. The data is stored as a three-dimensional array:<br
  13 +/// />
  14 +/// <i>channelLevels[channel][GainId][LevelOffset]</i>
  15 +/// </p>
  16 +/// <p><br /></p>
  17 +///
  18 +/// VALUE_DEVICEADDRESS <em>[MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A]</em>
  19 +/// <p>
  20 +/// Value 0x0a is the address of the device. It has a length of one byte.
  21 +/// </p>
  22 +/// <p><br /></p>
  23 +///
  24 +/// VALUE_FASTRATECALIBRATION <em>[MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A]</em>
  25 +/// <p>
  26 +/// Value 0x60 is the calibration data for the fast rate mode on the DSO-2250,
  27 +/// DSO-5200 and DSO-5200A. It's used to correct the level differences between
  28 +/// the two merged channels to avoid deterministic noise.
  29 +/// </p>
  30 +/// <p><br /></p>
  31 +///
  32 +/// VALUE_ETSCORRECTION <em>[MODEL_DSO5200, MODEL_DSO5200A]</em>
  33 +/// <p>
  34 +/// Value 0x70 contains correction values for the ETS functionality of the
  35 +/// DSO-5200 and DSO-5200A.
  36 +/// </p>
  37 +/// <p><br /></p>
  38 +enum class ControlValue : uint8_t {
20 39 VALUE_OFFSETLIMITS = 0x08,
21   -
22   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
23   - /// ::MODEL_DSO5200A]</em>
24   - /// <p>
25   - /// Value 0x0a is the address of the device. It has a length of one byte.
26   - /// </p>
27   - /// <p><br /></p>
28 40 VALUE_DEVICEADDRESS = 0x0a,
29   -
30   - /// <em>[::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A]</em>
31   - /// <p>
32   - /// Value 0x60 is the calibration data for the fast rate mode on the DSO-2250,
33   - /// DSO-5200 and DSO-5200A. It's used to correct the level differences between
34   - /// the two merged channels to avoid deterministic noise.
35   - /// </p>
36   - /// <p><br /></p>
37 41 VALUE_FASTRATECALIBRATION = 0x60,
38   -
39   - /// <em>[::MODEL_DSO5200, ::MODEL_DSO5200A]</em>
40   - /// <p>
41   - /// Value 0x70 contains correction values for the ETS functionality of the
42   - /// DSO-5200 and DSO-5200A.
43   - /// </p>
44   - /// <p><br /></p>
45 42 VALUE_ETSCORRECTION = 0x70
46 43 };
47 44  
... ...
openhantek/src/hantekprotocol/definitions.h
... ... @@ -9,6 +9,9 @@
9 9 #define HANTEK_GAIN_STEPS 9
10 10 #define HANTEK_CHANNELS 2 ///< Number of physical channels
11 11  
  12 +typedef unsigned RecordLengthID;
  13 +typedef unsigned ChannelID;
  14 +
12 15 namespace Hantek {
13 16 /// \enum UsedChannels
14 17 /// \brief The enabled channels.
... ...
openhantek/src/main.cpp
... ... @@ -16,7 +16,7 @@
16 16 #include "settings.h"
17 17 #include "usb/usbdevice.h"
18 18 #include "dsomodel.h"
19   -#include "selectdevice/selectdevice.h"
  19 +#include "selectdevice/selectsupporteddevice.h"
20 20  
21 21 using namespace Hantek;
22 22  
... ... @@ -45,10 +45,10 @@ int main(int argc, char *argv[]) {
45 45 libusb_context *context = nullptr;
46 46 int error = libusb_init(&context);
47 47 if (error) {
48   - SelectDevice().showLibUSBFailedDialogModel(error);
  48 + SelectSupportedDevice().showLibUSBFailedDialogModel(error);
49 49 return -1;
50 50 }
51   - std::unique_ptr<USBDevice> device = SelectDevice().showSelectDeviceModal(context);
  51 + std::unique_ptr<USBDevice> device = SelectSupportedDevice().showSelectDeviceModal(context);
52 52  
53 53 QString errorMessage;
54 54 if (device == nullptr || !device->connectDevice(errorMessage)) {
... ... @@ -76,8 +76,8 @@ int main(int argc, char *argv[]) {
76 76 QObject::connect(&dsoControl, &HantekDsoControl::samplesAvailable, &dataAnalyser, &DataAnalyzer::samplesAvailable);
77 77  
78 78 //////// Create settings object ////////
79   - DsoSettings settings(dsoControl.getChannelCount());
80   - dataAnalyser.applySettings(&settings.scope);
  79 + DsoSettings settings(dsoControl.getDeviceSettings(), &device->getModel()->specification);
  80 + dataAnalyser.applySettings(&settings);
81 81  
82 82 //////// Create main window ////////
83 83 OpenHantekMainWindow *openHantekMainWindow = new OpenHantekMainWindow(&dsoControl, &dataAnalyser, &settings);
... ...
openhantek/src/mainwindow.cpp
... ... @@ -291,8 +291,6 @@ void OpenHantekMainWindow::connectSignals() {
291 291 connect(horizontalDock, &HorizontalDock::timebaseChanged, this, &OpenHantekMainWindow::timebaseSelected);
292 292 connect(horizontalDock, &HorizontalDock::frequencybaseChanged, dsoWidget, &DsoWidget::updateFrequencybase);
293 293 connect(horizontalDock, &HorizontalDock::recordLengthChanged, this, &OpenHantekMainWindow::recordLengthSelected);
294   - // connect(horizontalDock, SIGNAL(formatChanged(HorizontalFormat)),
295   - // dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
296 294  
297 295 connect(triggerDock, &TriggerDock::modeChanged, dsoControl, &HantekDsoControl::setTriggerMode);
298 296 connect(triggerDock, &TriggerDock::modeChanged, dsoWidget, &DsoWidget::updateTriggerMode);
... ... @@ -332,13 +330,13 @@ void OpenHantekMainWindow::connectSignals() {
332 330  
333 331 /// \brief Initialize the device with the current settings.
334 332 void OpenHantekMainWindow::applySettingsToDevice() {
335   - for (unsigned int channel = 0; channel < settings->scope.physicalChannels; ++channel) {
336   - dsoControl->setCoupling(channel, settings->scope.voltage[channel].coupling);
  333 + for (unsigned int channel = 0; channel < settings->deviceSpecification->channels; ++channel) {
  334 + dsoControl->setCoupling(channel, settings->coupling(channel));
337 335 updateVoltageGain(channel);
338 336 updateOffset(channel);
339 337 dsoControl->setTriggerLevel(channel, settings->scope.voltage[channel].trigger);
340 338 }
341   - updateUsed(settings->scope.physicalChannels);
  339 + updateUsed(settings->deviceSpecification->channels);
342 340 if (settings->scope.horizontal.samplerateSet)
343 341 samplerateSelected();
344 342 else
... ... @@ -468,7 +466,7 @@ void OpenHantekMainWindow::timebaseSelected() {
468 466 /// \brief Sets the offset of the oscilloscope for the given channel.
469 467 /// \param channel The channel that got a new offset.
470 468 void OpenHantekMainWindow::updateOffset(unsigned int channel) {
471   - if (channel >= settings->scope.physicalChannels) return;
  469 + if (channel >= settings->deviceSpecification->channels) return;
472 470  
473 471 dsoControl->setOffset(channel, (settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
474 472 }
... ... @@ -478,16 +476,16 @@ void OpenHantekMainWindow::updateOffset(unsigned int channel) {
478 476 void OpenHantekMainWindow::updateUsed(unsigned int channel) {
479 477 if (channel >= (unsigned int)settings->scope.voltage.size()) return;
480 478  
481   - bool mathUsed = settings->scope.voltage[settings->scope.physicalChannels].used |
482   - settings->scope.spectrum[settings->scope.physicalChannels].used;
  479 + bool mathUsed = settings->scope.voltage[settings->deviceSpecification->channels].used |
  480 + settings->scope.spectrum[settings->deviceSpecification->channels].used;
483 481  
484 482 // Normal channel, check if voltage/spectrum or math channel is used
485   - if (channel < settings->scope.physicalChannels)
  483 + if (channel < settings->deviceSpecification->channels)
486 484 dsoControl->setChannelUsed(
487 485 channel, mathUsed | settings->scope.voltage[channel].used | settings->scope.spectrum[channel].used);
488 486 // Math channel, update all channels
489   - else if (channel == settings->scope.physicalChannels) {
490   - for (unsigned int channelCounter = 0; channelCounter < settings->scope.physicalChannels; ++channelCounter)
  487 + else if (channel == settings->deviceSpecification->channels) {
  488 + for (unsigned int channelCounter = 0; channelCounter < settings->deviceSpecification->channels; ++channelCounter)
491 489 dsoControl->setChannelUsed(channelCounter,
492 490 mathUsed | settings->scope.voltage[channelCounter].used |
493 491 settings->scope.spectrum[channelCounter].used);
... ... @@ -497,7 +495,7 @@ void OpenHantekMainWindow::updateUsed(unsigned int channel) {
497 495 /// \brief Sets the gain of the oscilloscope for the given channel.
498 496 /// \param channel The channel that got a new gain value.
499 497 void OpenHantekMainWindow::updateVoltageGain(unsigned int channel) {
500   - if (channel >= settings->scope.physicalChannels) return;
  498 + if (channel >= settings->deviceSpecification->channels) return;
501 499  
502   - dsoControl->setGain(channel, settings->scope.voltage[channel].gain * DIVS_VOLTAGE);
  500 + dsoControl->setGain(channel, settings->scope.gain(channel) * DIVS_VOLTAGE);
503 501 }
... ...
openhantek/src/scopesettings.h
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
1 3 #pragma once
2 4  
3   -#include <vector>
  5 +#include <QString>
  6 +
4 7 #include "analyse/enums.h"
5 8 #include "hantekdso/enums.h"
  9 +#include "hantekprotocol/definitions.h"
  10 +#include <vector>
6 11  
7 12 #define MARKER_COUNT 2 ///< Number of markers
8 13  
9   -////////////////////////////////////////////////////////////////////////////////
10   -/// \struct DsoSettingsScopeHorizontal settings.h
11 14 /// \brief Holds the settings for the horizontal axis.
12 15 struct DsoSettingsScopeHorizontal {
13   - Dso::GraphFormat format = Dso::GRAPHFORMAT_TY; ///< Graph drawing mode of the scope
  16 + Dso::GraphFormat format = Dso::GraphFormat::TY; ///< Graph drawing mode of the scope
14 17 double frequencybase = 1e3; ///< Frequencybase in Hz/div
15 18 double marker[MARKER_COUNT] = {-1.0, 1.0}; ///< Marker positions in div
16 19 bool marker_visible[MARKER_COUNT];
... ... @@ -20,57 +23,53 @@ struct DsoSettingsScopeHorizontal {
20 23 bool samplerateSet = false; ///< The samplerate was set by the user, not the timebase
21 24 };
22 25  
23   -////////////////////////////////////////////////////////////////////////////////
24   -/// \struct DsoSettingsScopeTrigger settings.h
25 26 /// \brief Holds the settings for the trigger.
26 27 struct DsoSettingsScopeTrigger {
27 28 bool filter = true; ///< Not sure what this is good for...
28   - Dso::TriggerMode mode = Dso::TRIGGERMODE_NORMAL; ///< Automatic, normal or single trigger
  29 + Dso::TriggerMode mode = Dso::TriggerMode::NORMAL; ///< Automatic, normal or single trigger
29 30 double position = 0.0; ///< Horizontal position for pretrigger
30   - Dso::Slope slope = Dso::SLOPE_POSITIVE; ///< Rising or falling edge causes trigger
  31 + Dso::Slope slope = Dso::Slope::Positive; ///< Rising or falling edge causes trigger
31 32 unsigned int source = 0; ///< Channel that is used as trigger source
32 33 bool special = false; ///< true if the trigger source is not a standard channel
33 34 };
34 35  
35   -////////////////////////////////////////////////////////////////////////////////
36   -/// \struct DsoSettingsScopeSpectrum settings.h
37 36 /// \brief Holds the settings for the spectrum analysis.
38 37 struct DsoSettingsScopeSpectrum {
39   - unsigned channel;
40   - double magnitude = 20.0; ///< The vertical resolution in dB/div
41   - QString name; ///< Name of this channel
42   - double offset = 0.0; ///< Vertical offset in divs
43   - bool used = false; ///< true if the spectrum is turned on
  38 + ChannelID channel;
  39 + double magnitude = 20.0; ///< The vertical resolution in dB/div
  40 + QString name; ///< Name of this channel
  41 + double offset = 0.0; ///< Vertical offset in divs
  42 + bool used = false; ///< true if the spectrum is turned on
44 43 };
45 44  
46   -////////////////////////////////////////////////////////////////////////////////
47   -/// \struct DsoSettingsScopeVoltage settings.h
48 45 /// \brief Holds the settings for the normal voltage graphs.
49 46 struct DsoSettingsScopeVoltage {
50   - double gain = 1.0; ///< The vertical resolution in V/div
51   - bool inverted = false; ///< true if the channel is inverted (mirrored on cross-axis)
52   - union { ///< Different enums, coupling for real- and mode for math-channels
  47 + unsigned gainStepIndex = 6; ///< The vertical resolution in V/div (default = 1.0)
  48 + bool inverted = false; ///< true if the channel is inverted (mirrored on cross-axis)
  49 + union { ///< Different enums, coupling for real- and mode for math-channels
53 50 Dso::MathMode math;
54   - Dso::Coupling coupling;
  51 + unsigned couplingIndex = 0;
55 52 int rawValue;
56 53 };
57   - QString name; ///< Name of this channel
58   - double offset = 0.0; ///< Vertical offset in divs
59   - double trigger = 0.0; ///< Trigger level in V
60   - bool used = false; ///< true if this channel is enabled
  54 + QString name; ///< Name of this channel
  55 + double offset = 0.0; ///< Vertical offset in divs
  56 + double trigger = 0.0; ///< Trigger level in V
  57 + bool used = false; ///< true if this channel is enabled
61 58 };
62 59  
63   -////////////////////////////////////////////////////////////////////////////////
64   -/// \struct DsoSettingsScope settings.h
65 60 /// \brief Holds the settings for the oscilloscope.
66 61 struct DsoSettingsScope {
67   - DsoSettingsScopeHorizontal horizontal; ///< Settings for the horizontal axis
68   - DsoSettingsScopeTrigger trigger; ///< Settings for the trigger
69   - std::vector<DsoSettingsScopeSpectrum> spectrum; ///< Spectrum analysis settings
70   - std::vector<DsoSettingsScopeVoltage> voltage; ///< Settings for the normal graphs
71   -
72   - unsigned int physicalChannels = 0; ///< Number of real channels (No math etc.)
  62 + std::vector<double> gainSteps = {1e-2, 2e-2, 5e-2, 1e-1, 2e-1,
  63 + 5e-1, 1e0, 2e0, 5e0}; ///< The selectable voltage gain steps in V/div
73 64 Dso::WindowFunction spectrumWindow = Dso::WindowFunction::HANN; ///< Window function for DFT
74   - double spectrumReference = 0.0; ///< Reference level for spectrum in dBm
75   - double spectrumLimit = -20.0; ///< Minimum magnitude of the spectrum (Avoids peaks)
  65 + std::vector<DsoSettingsScopeSpectrum> spectrum; ///< Spectrum analysis settings
  66 + std::vector<DsoSettingsScopeVoltage> voltage; ///< Settings for the normal graphs
  67 + DsoSettingsScopeHorizontal horizontal; ///< Settings for the horizontal axis
  68 + DsoSettingsScopeTrigger trigger; ///< Settings for the trigger
  69 + double spectrumReference = 0.0; ///< Reference level for spectrum in dBm
  70 + double spectrumLimit = -20.0; ///< Minimum magnitude of the spectrum (Avoids peaks)
  71 +
  72 + double gain(unsigned channel) const {
  73 + return gainSteps[voltage[channel].gainStepIndex];
  74 + }
76 75 };
... ...
openhantek/src/selectdevice/devicelistentry.h
  1 +// SPDX-License-Identifier: GPL-2.0+
1 2 #pragma once
2 3  
3 4 #include <QString>
... ...
openhantek/src/selectdevice/deviceslistmodel.cpp
... ... @@ -8,10 +8,10 @@ DevicesListModel::DevicesListModel(FindDevices *findDevices) :findDevices(findDe
8 8  
9 9 int DevicesListModel::rowCount(const QModelIndex &) const
10 10 {
11   - return entries.size();
  11 + return (int)entries.size();
12 12 }
13 13  
14   -int DevicesListModel::columnCount(const QModelIndex &parent) const
  14 +int DevicesListModel::columnCount(const QModelIndex &) const
15 15 {
16 16 return 2;
17 17 }
... ... @@ -33,21 +33,22 @@ QVariant DevicesListModel::headerData(int section, Qt::Orientation orientation,
33 33 QVariant DevicesListModel::data(const QModelIndex &index, int role) const
34 34 {
35 35 if (!index.isValid()) return QVariant();
36   - if (role==Qt::UserRole) return QVariant::fromValue(entries[index.row()].id);
37   - else if (role==Qt::UserRole+1) return QVariant::fromValue(entries[index.row()].canConnect);
38   - else if (role==Qt::UserRole+2) return QVariant::fromValue(entries[index.row()].needFirmware);
  36 + const unsigned row = (unsigned)index.row();
  37 + if (role==Qt::UserRole) return QVariant::fromValue(entries[row].id);
  38 + else if (role==Qt::UserRole+1) return QVariant::fromValue(entries[row].canConnect);
  39 + else if (role==Qt::UserRole+2) return QVariant::fromValue(entries[row].needFirmware);
39 40  
40 41 if (role == Qt::DisplayRole) {
41 42 if (index.column() == 0) {
42   - return entries[index.row()].name;
  43 + return entries[row].name;
43 44 } else if (index.column() == 1) {
44   - return entries[index.row()].getStatus();
  45 + return entries[row].getStatus();
45 46 }
46 47 }
47 48  
48 49 if (role == Qt::BackgroundRole) {
49   - if (entries[index.row()].canConnect) return QColor(Qt::darkGreen).lighter();
50   - else if (entries[index.row()].needFirmware) return QColor(Qt::yellow).lighter();
  50 + if (entries[row].canConnect) return QColor(Qt::darkGreen).lighter();
  51 + else if (entries[row].needFirmware) return QColor(Qt::yellow).lighter();
51 52 }
52 53  
53 54 return QVariant();
... ... @@ -59,7 +60,7 @@ void DevicesListModel::updateDeviceList()
59 60 entries.clear();
60 61 endResetModel();
61 62 const FindDevices::DeviceList* devices = findDevices->getDevices();
62   - beginInsertRows(QModelIndex(),0,devices->size());
  63 + beginInsertRows(QModelIndex(),0,(int)devices->size());
63 64 for (auto &i : *devices) {
64 65 DeviceListEntry entry;
65 66 entry.name= QString::fromStdString(i.second->getModel()->name);
... ...
openhantek/src/selectdevice/deviceslistmodel.h
  1 +// SPDX-License-Identifier: GPL-2.0+
1 2 #pragma once
2 3  
3 4 #include <QAbstractTableModel>
... ...
openhantek/src/selectdevice/newdevicemodelfromexisting.cpp 0 → 100644
  1 +#include "newdevicemodelfromexisting.h"
  2 +
  3 +#include "dsomodel.h"
  4 +#include "models.h"
  5 +#include "rawdeviceslistmodel.h"
  6 +
  7 +#include <QDebug>
  8 +#include <QPushButton>
  9 +#include <QStringListModel>
  10 +#include <QMessageBox>
  11 +
  12 +NewDeviceModelFromExisting::NewDeviceModelFromExisting(QWidget *parent) :
  13 + QDialog(parent),
  14 + ui(new Ui::NewDeviceModelFromExisting)
  15 +{
  16 + ui->setupUi(this);
  17 + connect(ui->checkBox, &QCheckBox::stateChanged,[this](int state) {
  18 + ui->stackedWidget->setCurrentIndex(state==Qt::Checked ? 0: 1);
  19 + });
  20 + ui->checkBox->setCheckState(Qt::Checked);
  21 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  22 +
  23 + QStringList supportedModelsList;
  24 + for (const DSOModel* model: supportedModels) {
  25 + supportedModelsList.append(QString::fromStdString(model->name));
  26 + }
  27 +
  28 + QStringListModel* model = new QStringListModel(this);
  29 + model->setStringList(supportedModelsList);
  30 + ui->cmbTemplateModel->setModel(model);
  31 +
  32 + RawDevicesListModel* deviceListModel = new RawDevicesListModel(context, this);
  33 + ui->cmbUSBdevices->setModel(deviceListModel);
  34 + deviceListModel->updateDeviceList();
  35 +
  36 + connect(ui->btnRefresh, &QPushButton::clicked, [this,deviceListModel] {
  37 + deviceListModel->updateDeviceList();
  38 + });
  39 +
  40 + connect(ui->cmbUSBdevices, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this](int index) {
  41 + if (index == -1) {
  42 + ui->stackedWidget->setCurrentIndex(2);
  43 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  44 + ui->checkBox->setEnabled(false);
  45 + return;
  46 + }
  47 + if (ui->cmbUSBdevices->currentData(RawDevicesListModel::AccessRole).toBool()) {
  48 + ui->checkBox->setEnabled(true);
  49 + ui->modelname->setText(ui->cmbUSBdevices->currentData(RawDevicesListModel::DeviceNameRole).toString());
  50 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->modelname->text().size());
  51 + ui->stackedWidget->setCurrentIndex(ui->checkBox->isChecked() ? 0: 1);
  52 + } else {
  53 + ui->checkBox->setEnabled(false);
  54 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  55 + ui->stackedWidget->setCurrentIndex(3);
  56 + }
  57 + });
  58 +
  59 + if (deviceListModel->rowCount(QModelIndex())) {
  60 + ui->cmbUSBdevices->setCurrentIndex(0);
  61 + }
  62 +}
  63 +
  64 +void NewDeviceModelFromExisting::setUSBcontext(libusb_context *context)
  65 +{
  66 + this->context = context;
  67 +}
  68 +
  69 +RawDeviceListEntry *NewDeviceModelFromExisting::getSelectedEntry()
  70 +{
  71 + return (RawDeviceListEntry*) ui->cmbUSBdevices->currentData(RawDevicesListModel::EntryPointerRole).value<void*>();
  72 +}
  73 +
  74 +void NewDeviceModelFromExisting::accept()
  75 +{
  76 + QMessageBox::information(this,tr("Sorry"),tr("This is not yet implemented!"));
  77 + QDialog::accept();
  78 +}
... ...
openhantek/src/selectdevice/newdevicemodelfromexisting.h 0 → 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +#pragma once
  3 +
  4 +#include <QDialog>
  5 +#include <memory>
  6 +#include "ui_newdevicemodelfromexisting.h"
  7 +#include "rawdevicelistentry.h"
  8 +
  9 +namespace Ui {
  10 +class NewDeviceModelFromExisting;
  11 +}
  12 +
  13 +struct libusb_context;
  14 +
  15 +class NewDeviceModelFromExisting : public QDialog
  16 +{
  17 + Q_OBJECT
  18 +
  19 +public:
  20 + explicit NewDeviceModelFromExisting(QWidget *parent = 0);
  21 + void setUSBcontext(libusb_context* context);
  22 + RawDeviceListEntry* getSelectedEntry();
  23 +private:
  24 + std::unique_ptr<Ui::NewDeviceModelFromExisting> ui;
  25 + libusb_context* context = nullptr;
  26 +
  27 + // QDialog interface
  28 +public slots:
  29 + virtual void accept() override;
  30 +};
... ...
openhantek/src/selectdevice/newdevicemodelfromexisting.ui 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<ui version="4.0">
  3 + <class>NewDeviceModelFromExisting</class>
  4 + <widget class="QDialog" name="NewDeviceModelFromExisting">
  5 + <property name="geometry">
  6 + <rect>
  7 + <x>0</x>
  8 + <y>0</y>
  9 + <width>442</width>
  10 + <height>437</height>
  11 + </rect>
  12 + </property>
  13 + <property name="windowTitle">
  14 + <string>New device from template</string>
  15 + </property>
  16 + <layout class="QVBoxLayout" name="verticalLayout_6">
  17 + <item>
  18 + <widget class="QGroupBox" name="groupBox">
  19 + <property name="title">
  20 + <string>Select USB device</string>
  21 + </property>
  22 + <layout class="QVBoxLayout" name="verticalLayout">
  23 + <property name="sizeConstraint">
  24 + <enum>QLayout::SetMinimumSize</enum>
  25 + </property>
  26 + <item>
  27 + <widget class="QComboBox" name="cmbUSBdevices"/>
  28 + </item>
  29 + <item>
  30 + <widget class="QPushButton" name="btnRefresh">
  31 + <property name="text">
  32 + <string>Refresh</string>
  33 + </property>
  34 + </widget>
  35 + </item>
  36 + <item>
  37 + <widget class="QCheckBox" name="checkBox">
  38 + <property name="toolTip">
  39 + <string>This is usually indicated by a light (red flashing)</string>
  40 + </property>
  41 + <property name="whatsThis">
  42 + <string>This is usually indicated by a light (red flashing)</string>
  43 + </property>
  44 + <property name="text">
  45 + <string>Firmware is uploaded already*</string>
  46 + </property>
  47 + </widget>
  48 + </item>
  49 + </layout>
  50 + </widget>
  51 + </item>
  52 + <item>
  53 + <widget class="QStackedWidget" name="stackedWidget">
  54 + <property name="lineWidth">
  55 + <number>0</number>
  56 + </property>
  57 + <property name="currentIndex">
  58 + <number>1</number>
  59 + </property>
  60 + <widget class="QWidget" name="page">
  61 + <layout class="QVBoxLayout" name="verticalLayout_4">
  62 + <item>
  63 + <widget class="QGroupBox" name="groupTemplate">
  64 + <property name="sizePolicy">
  65 + <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
  66 + <horstretch>0</horstretch>
  67 + <verstretch>0</verstretch>
  68 + </sizepolicy>
  69 + </property>
  70 + <property name="title">
  71 + <string>Template selection</string>
  72 + </property>
  73 + <layout class="QVBoxLayout" name="verticalLayout_2">
  74 + <item>
  75 + <widget class="QLabel" name="label_2">
  76 + <property name="sizePolicy">
  77 + <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
  78 + <horstretch>0</horstretch>
  79 + <verstretch>0</verstretch>
  80 + </sizepolicy>
  81 + </property>
  82 + <property name="text">
  83 + <string>Select the existing model that should be used as template for your device. You may need to restart OpenHantek and try different models until it works for you.</string>
  84 + </property>
  85 + <property name="wordWrap">
  86 + <bool>true</bool>
  87 + </property>
  88 + </widget>
  89 + </item>
  90 + <item>
  91 + <widget class="QComboBox" name="cmbTemplateModel"/>
  92 + </item>
  93 + <item>
  94 + <widget class="QLineEdit" name="modelname">
  95 + <property name="placeholderText">
  96 + <string>Please enter a model name</string>
  97 + </property>
  98 + </widget>
  99 + </item>
  100 + </layout>
  101 + </widget>
  102 + </item>
  103 + </layout>
  104 + </widget>
  105 + <widget class="QWidget" name="page_2">
  106 + <layout class="QVBoxLayout" name="verticalLayout_5">
  107 + <item>
  108 + <widget class="QGroupBox" name="groupFirmware">
  109 + <property name="title">
  110 + <string>Firmware files</string>
  111 + </property>
  112 + <layout class="QVBoxLayout" name="verticalLayout_3">
  113 + <item>
  114 + <widget class="QLabel" name="label_3">
  115 + <property name="text">
  116 + <string>Please select the firmware files in hex format, extracted from the windows driver for example. You need to open this dialog again after the firmware has been uploaded.</string>
  117 + </property>
  118 + <property name="wordWrap">
  119 + <bool>true</bool>
  120 + </property>
  121 + </widget>
  122 + </item>
  123 + <item>
  124 + <layout class="QGridLayout" name="gridLayout">
  125 + <property name="sizeConstraint">
  126 + <enum>QLayout::SetMinimumSize</enum>
  127 + </property>
  128 + <item row="1" column="0">
  129 + <widget class="QLabel" name="label_5">
  130 + <property name="text">
  131 + <string>Firmware</string>
  132 + </property>
  133 + </widget>
  134 + </item>
  135 + <item row="0" column="0">
  136 + <widget class="QLabel" name="label_4">
  137 + <property name="text">
  138 + <string>Loader</string>
  139 + </property>
  140 + </widget>
  141 + </item>
  142 + <item row="1" column="1">
  143 + <widget class="QLineEdit" name="lineFirmware"/>
  144 + </item>
  145 + <item row="0" column="1">
  146 + <widget class="QLineEdit" name="lineLoader"/>
  147 + </item>
  148 + <item row="0" column="2">
  149 + <widget class="QPushButton" name="btnSelectLoader">
  150 + <property name="sizePolicy">
  151 + <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
  152 + <horstretch>0</horstretch>
  153 + <verstretch>0</verstretch>
  154 + </sizepolicy>
  155 + </property>
  156 + <property name="text">
  157 + <string>...</string>
  158 + </property>
  159 + <property name="flat">
  160 + <bool>false</bool>
  161 + </property>
  162 + </widget>
  163 + </item>
  164 + <item row="1" column="2">
  165 + <widget class="QPushButton" name="btnSelectFirmware">
  166 + <property name="sizePolicy">
  167 + <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
  168 + <horstretch>0</horstretch>
  169 + <verstretch>0</verstretch>
  170 + </sizepolicy>
  171 + </property>
  172 + <property name="text">
  173 + <string>...</string>
  174 + </property>
  175 + </widget>
  176 + </item>
  177 + </layout>
  178 + </item>
  179 + </layout>
  180 + </widget>
  181 + </item>
  182 + </layout>
  183 + </widget>
  184 + <widget class="QWidget" name="page_3">
  185 + <layout class="QVBoxLayout" name="verticalLayout_7">
  186 + <item>
  187 + <widget class="QLabel" name="label_6">
  188 + <property name="text">
  189 + <string>No USB devices found or your operating system prohibited enumerating devices.</string>
  190 + </property>
  191 + <property name="wordWrap">
  192 + <bool>true</bool>
  193 + </property>
  194 + </widget>
  195 + </item>
  196 + </layout>
  197 + </widget>
  198 + <widget class="QWidget" name="page_4">
  199 + <layout class="QVBoxLayout" name="verticalLayout_8">
  200 + <item>
  201 + <widget class="QLabel" name="label_7">
  202 + <property name="text">
  203 + <string>No access granted for the selected USB device. Your operating system may prohibit access. On Windows you might need to install a generic driver first. On Linux you need to install an udev rule to grant access to your currently logged in user.</string>
  204 + </property>
  205 + <property name="wordWrap">
  206 + <bool>true</bool>
  207 + </property>
  208 + </widget>
  209 + </item>
  210 + </layout>
  211 + </widget>
  212 + </widget>
  213 + </item>
  214 + <item>
  215 + <spacer name="verticalSpacer">
  216 + <property name="orientation">
  217 + <enum>Qt::Vertical</enum>
  218 + </property>
  219 + <property name="sizeHint" stdset="0">
  220 + <size>
  221 + <width>20</width>
  222 + <height>40</height>
  223 + </size>
  224 + </property>
  225 + </spacer>
  226 + </item>
  227 + <item>
  228 + <widget class="QDialogButtonBox" name="buttonBox">
  229 + <property name="orientation">
  230 + <enum>Qt::Horizontal</enum>
  231 + </property>
  232 + <property name="standardButtons">
  233 + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
  234 + </property>
  235 + </widget>
  236 + </item>
  237 + </layout>
  238 + </widget>
  239 + <resources/>
  240 + <connections>
  241 + <connection>
  242 + <sender>buttonBox</sender>
  243 + <signal>accepted()</signal>
  244 + <receiver>NewDeviceModelFromExisting</receiver>
  245 + <slot>accept()</slot>
  246 + <hints>
  247 + <hint type="sourcelabel">
  248 + <x>227</x>
  249 + <y>324</y>
  250 + </hint>
  251 + <hint type="destinationlabel">
  252 + <x>157</x>
  253 + <y>274</y>
  254 + </hint>
  255 + </hints>
  256 + </connection>
  257 + <connection>
  258 + <sender>buttonBox</sender>
  259 + <signal>rejected()</signal>
  260 + <receiver>NewDeviceModelFromExisting</receiver>
  261 + <slot>reject()</slot>
  262 + <hints>
  263 + <hint type="sourcelabel">
  264 + <x>260</x>
  265 + <y>337</y>
  266 + </hint>
  267 + <hint type="destinationlabel">
  268 + <x>286</x>
  269 + <y>274</y>
  270 + </hint>
  271 + </hints>
  272 + </connection>
  273 + </connections>
  274 +</ui>
... ...
openhantek/src/selectdevice/rawdevicelistentry.h 0 → 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +#pragma once
  3 +
  4 +#include <QString>
  5 +#include "usb/usbdevice.h"
  6 +#include "dsomodel.h"
  7 +/**
  8 + * Represents an entry in the {@link DevicesListModel}.
  9 + */
  10 +struct RawDeviceListEntry {
  11 + long productId;
  12 + long vendorId;
  13 + bool access;
  14 + DSOModel* baseModel=nullptr;
  15 + QString devicename;
  16 + QString deviceinfo;
  17 +};
... ...
openhantek/src/selectdevice/rawdeviceslistmodel.cpp 0 → 100644
  1 +#include "rawdeviceslistmodel.h"
  2 +#include "usb/finddevices.h"
  3 +#include "usb/uploadFirmware.h"
  4 +#include "dsomodel.h"
  5 +#include <QColor>
  6 +
  7 +RawDevicesListModel::RawDevicesListModel(libusb_context *context, QObject *parent) : QAbstractTableModel(parent), context(context) {}
  8 +
  9 +int RawDevicesListModel::rowCount(const QModelIndex &) const
  10 +{
  11 + return (int)entries.size();
  12 +}
  13 +
  14 +int RawDevicesListModel::columnCount(const QModelIndex &) const
  15 +{
  16 + return 1;
  17 +}
  18 +
  19 +QVariant RawDevicesListModel::data(const QModelIndex &index, int role) const
  20 +{
  21 + if (!index.isValid()) return QVariant();
  22 + const unsigned row = (unsigned)index.row();
  23 + if (role==ProductIDRole) return QVariant::fromValue(entries[row].productId);
  24 + else if (role==VendorIDRole) return QVariant::fromValue(entries[row].vendorId);
  25 + else if (role==AccessRole) return QVariant::fromValue(entries[row].access);
  26 + else if (role==DeviceNameRole) return QVariant::fromValue(entries[row].devicename);
  27 + else if (role==EntryPointerRole) return QVariant::fromValue((void*)&entries[row]);
  28 + else if (role==Qt::DisplayRole) return QVariant::fromValue(entries[row].deviceinfo);
  29 +
  30 + return QVariant();
  31 +}
  32 +
  33 +QString readUSBdescriptor(libusb_device_handle *handle, uint8_t index) {
  34 + unsigned char string[255];
  35 + int ret = libusb_get_string_descriptor_ascii(handle, index, string, sizeof(string));
  36 + if (ret > 0)
  37 + return QString::fromLatin1((char*)string, ret).trimmed();
  38 + else
  39 + return QString();
  40 +}
  41 +
  42 +void RawDevicesListModel::updateDeviceList()
  43 +{
  44 + beginResetModel();
  45 + entries.clear();
  46 + endResetModel();
  47 +
  48 + libusb_device **deviceList;
  49 + ssize_t deviceCount = libusb_get_device_list(context, &deviceList);
  50 + beginInsertRows(QModelIndex(),0,(int)deviceCount);
  51 +
  52 + for (ssize_t deviceIterator = 0; deviceIterator < deviceCount; ++deviceIterator) {
  53 + libusb_device *device = deviceList[deviceIterator];
  54 + RawDeviceListEntry entry;
  55 + // Get device descriptor
  56 + struct libusb_device_descriptor descriptor;
  57 + libusb_get_device_descriptor(device, &descriptor);
  58 +
  59 + entry.productId = descriptor.idProduct;
  60 + entry.vendorId = descriptor.idVendor;
  61 + libusb_device_handle *handle = NULL;
  62 + int ret = libusb_open(device, &handle);
  63 + if (ret != LIBUSB_SUCCESS) {
  64 + entry.access = false;
  65 + entry.deviceinfo = tr("%1:%2 - No access").arg(entry.vendorId,0,16).arg(entry.productId,0,16);
  66 + } else {
  67 + entry.access = true;
  68 + entry.devicename = readUSBdescriptor(handle, descriptor.iProduct);
  69 + entry.deviceinfo = tr("%1:%2 (%3 - %4)").arg(entry.vendorId,0,16).arg(entry.productId,0,16)
  70 + .arg(entry.devicename).arg(readUSBdescriptor(handle, descriptor.iManufacturer));
  71 + libusb_close(handle);
  72 + }
  73 +
  74 + entries.push_back(entry);
  75 + }
  76 +
  77 + libusb_free_device_list(deviceList, true);
  78 +
  79 + endInsertRows();
  80 +}
... ...
openhantek/src/selectdevice/rawdeviceslistmodel.h 0 → 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +#pragma once
  3 +
  4 +#include <QAbstractTableModel>
  5 +#include "rawdevicelistentry.h"
  6 +#include "usb/usbdevice.h"
  7 +
  8 +/**
  9 + * Provides a Model for the Qt Model/View concept. The {@see FindDevices} is required
  10 + * to update the list of available devices.
  11 + */
  12 +class RawDevicesListModel: public QAbstractTableModel {
  13 +public:
  14 + RawDevicesListModel(libusb_context *context, QObject *parent = 0);
  15 + // QAbstractItemModel interface
  16 + virtual int rowCount(const QModelIndex &parent) const override;
  17 + virtual int columnCount(const QModelIndex &parent) const override;
  18 + virtual QVariant data(const QModelIndex &index, int role) const override;
  19 + void updateDeviceList();
  20 +
  21 + enum Roles {
  22 + ProductIDRole = Qt::UserRole+0,
  23 + VendorIDRole = Qt::UserRole+1,
  24 + AccessRole = Qt::UserRole+2,
  25 + DeviceNameRole = Qt::UserRole+3,
  26 + EntryPointerRole = Qt::UserRole+4
  27 + };
  28 +private:
  29 + std::vector<RawDeviceListEntry> entries;
  30 + libusb_context *context;
  31 +};
... ...
openhantek/src/selectdevice/selectdevice.cpp deleted
1   -#include <libusb-1.0/libusb.h>
2   -
3   -#include "utils/printutils.h"
4   -#include "selectdevice.h"
5   -#include "usb/uploadFirmware.h"
6   -#include "usb/finddevices.h"
7   -#include "dsomodel.h"
8   -#include <QApplication>
9   -#include <QTimer>
10   -#include <QAbstractTableModel>
11   -#include <QHeaderView>
12   -#include <QFile>
13   -
14   -#include "devicelistentry.h"
15   -#include "deviceslistmodel.h"
16   -
17   -SelectDevice::SelectDevice() {
18   - btn = new QPushButton(this);
19   - w = new QTableView(this);
20   - label = new QLabel();
21   - label->setWordWrap(true);
22   - move(QApplication::desktop()->screen()->rect().center() - w->rect().center());
23   - setWindowTitle(tr("Select device"));
24   - setLayout(new QVBoxLayout());
25   - layout()->addWidget(w);
26   - layout()->addWidget(label);
27   - layout()->addWidget(btn);
28   - qRegisterMetaType<UniqueUSBid>();
29   - connect(btn, &QPushButton::clicked, [this]() {
30   - if (w->currentIndex().isValid()) {
31   - selectedDevice = w->currentIndex().data(Qt::UserRole).value<UniqueUSBid>();
32   - }
33   - QCoreApplication::instance()->quit();
34   - });
35   -}
36   -
37   -std::unique_ptr<USBDevice> SelectDevice::showSelectDeviceModal(libusb_context *&context)
38   -{
39   -
40   - std::unique_ptr<FindDevices> findDevices = std::unique_ptr<FindDevices>(new FindDevices(context));
41   - std::unique_ptr<DevicesListModel> model = std::unique_ptr<DevicesListModel>(new DevicesListModel(findDevices.get()));
42   - w->setModel(model.get());
43   - w->verticalHeader()->hide();
44   - w->horizontalHeader()->hide();
45   - w->setSelectionBehavior(QAbstractItemView::SelectRows);
46   - // w->setColumnWidth(1,60);
47   - w->horizontalHeader()->setStretchLastSection(true);
48   - connect(w->selectionModel(), &QItemSelectionModel::currentChanged, this, &SelectDevice::currentChanged);
49   -
50   - QTimer timer;
51   - timer.setInterval(1000);
52   - connect(&timer, &QTimer::timeout, [this, &model, &findDevices]() {
53   - if (findDevices->updateDeviceList())
54   - model->updateDeviceList();
55   - if (model->rowCount(QModelIndex())) {
56   - w->setVisible(true);
57   - label->setVisible(false);
58   - currentChanged(w->currentIndex(),QModelIndex());
59   - } else {
60   - QString generalMessage = tr("<p>OpenHantek did not find any compatible devices.</p>"
61   - "<p><img align='right' height='150' src='qrc:///switch.png'>"
62   - "Don't forget to switch your device into oscilloscope mode if it has multiple modes.</p>"
63   - );
64   -#if defined(Q_OS_WIN)
65   - generalMessage = generalMessage.arg("Please make sure you have installed the windows usb driver correctly");
66   -#elif defined(Q_OS_LINUX)
67   - QFile file("/lib/udev/rules.d/60-hantek.rules");
68   - if (!file.exists()) {
69   - generalMessage += tr("<p>Please make sure you have copied the udev rules file to <b>%1</b> for correct USB access permissions.</p>").arg(file.fileName());
70   - }
71   -#else
72   -#endif
73   - generalMessage += tr("<p>Visit the build and run instruction "
74   - "<a href='https://github.com/OpenHantek/openhantek/blob/master/docs/build.md'>website</a> for help.</p>");
75   - makeErrorDialog(generalMessage);
76   - }
77   - if (!w->currentIndex().isValid()) {
78   - currentChanged(QModelIndex(),QModelIndex());
79   - }
80   - });
81   - timer.start();
82   - QCoreApplication::sendEvent(&timer, new QTimerEvent(timer.timerId())); // immediate timer event
83   -
84   - show();
85   - QCoreApplication::instance()->exec();
86   - timer.stop();
87   - close();
88   -
89   - return findDevices->takeDevice(selectedDevice);
90   -}
91   -
92   -void SelectDevice::showLibUSBFailedDialogModel(int error)
93   -{
94   - makeErrorDialog(tr("Can't initalize USB: %1").arg(libUsbErrorString(error)));
95   - show();
96   - QCoreApplication::instance()->exec();
97   - close();
98   -}
99   -
100   -void SelectDevice::makeErrorDialog(const QString &message)
101   -{
102   - w->setVisible(false);
103   - label->setText(message);
104   - label->setVisible(true);
105   -}
106   -
107   -void SelectDevice::currentChanged(const QModelIndex &current, const QModelIndex &)
108   -{
109   - if (!current.isValid()) {
110   - btn->setText(tr("Quit application"));
111   - btn->setEnabled(true);
112   - return;
113   - }
114   - if (current.data(Qt::UserRole+1).toBool()) {
115   - btn->setText(tr("Use device %1").arg(current.sibling(current.row(),0).data(Qt::DisplayRole).toString()));
116   - btn->setEnabled(true);
117   - } else {
118   - btn->setEnabled(false);
119   - if (current.data(Qt::UserRole+2).toBool()) {
120   - btn->setText(tr("Upload in progress..."));
121   - } else {
122   - btn->setText(tr("Connection failed!"));
123   - }
124   - }
125   -}
openhantek/src/selectdevice/selectsupporteddevice.cpp 0 → 100644
  1 +#include "selectsupporteddevice.h"
  2 +
  3 +#include <QTimer>
  4 +#include <QDesktopServices>
  5 +#include <QFile>
  6 +#include <QUrl>
  7 +
  8 +#include "utils/printutils.h"
  9 +#include "usb/uploadFirmware.h"
  10 +#include "usb/finddevices.h"
  11 +#include "dsomodel.h"
  12 +#include "devicelistentry.h"
  13 +#include "deviceslistmodel.h"
  14 +#include "newdevicemodelfromexisting.h"
  15 +#include "models.h"
  16 +
  17 +SelectSupportedDevice::SelectSupportedDevice(QWidget *parent) :
  18 + QDialog(parent),
  19 + ui(new Ui::SelectSupportedDevice)
  20 +{
  21 + ui->setupUi(this);
  22 + newDeviceFromExistingDialog = new NewDeviceModelFromExisting(this);
  23 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  24 + qRegisterMetaType<UniqueUSBid>();
  25 + connect(ui->buttonBox, &QDialogButtonBox::accepted, [this]() {
  26 + if (ui->cmbDevices->currentIndex()!=-1) {
  27 + selectedDevice = ui->cmbDevices->currentData(Qt::UserRole).value<UniqueUSBid>();
  28 + }
  29 + QCoreApplication::instance()->quit();
  30 + });
  31 + connect(ui->buttonBox, &QDialogButtonBox::helpRequested, [this]() {
  32 + QDesktopServices::openUrl(QUrl("https://github.com/OpenHantek/openhantek#openhantek--"));
  33 + });
  34 + connect(ui->btnAddDevice, &QPushButton::clicked, [this]() {
  35 + newDeviceFromExistingDialog->setModal(true);
  36 + newDeviceFromExistingDialog->show();
  37 + });
  38 +}
  39 +
  40 +std::unique_ptr<USBDevice> SelectSupportedDevice::showSelectDeviceModal(libusb_context *context)
  41 +{
  42 + newDeviceFromExistingDialog->setUSBcontext(context);
  43 + std::unique_ptr<FindDevices> findDevices = std::unique_ptr<FindDevices>(new FindDevices(context));
  44 + std::unique_ptr<DevicesListModel> model = std::unique_ptr<DevicesListModel>(new DevicesListModel(findDevices.get()));
  45 + ui->cmbDevices->setModel(model.get());
  46 + connect(ui->cmbDevices, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this](int index) {
  47 + if (index == -1) {
  48 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  49 + return;
  50 + }
  51 + if (ui->cmbDevices->currentData(Qt::UserRole+1).toBool()) {
  52 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
  53 + ui->labelReadyState->setText(tr("Device ready to use"));
  54 + } else {
  55 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  56 + if (ui->cmbDevices->currentData(Qt::UserRole+2).toBool()) {
  57 + ui->labelReadyState->setText(tr("Upload in progress..."));
  58 + } else {
  59 + ui->labelReadyState->setText(tr("Connection failed!"));
  60 + }
  61 + }
  62 + });
  63 +
  64 + QString messageNoDevices = tr("<p>OpenHantek did not find any compatible devices.</p>"
  65 + "<p><img align='right' height='150' src='qrc:///switch.png'>"
  66 + "Don't forget to switch your device into oscilloscope mode if it has multiple modes.</p>"
  67 + );
  68 + #if defined(Q_OS_WIN)
  69 + messageNoDevices += tr("<p>Please make sure you have installed the windows usb driver correctly</p>");
  70 + #elif defined(Q_OS_LINUX)
  71 + QFile file("/lib/udev/rules.d/60-hantek.rules");
  72 + if (!file.exists()) {
  73 + messageNoDevices += tr("<p>Please make sure you have copied the udev rules file to <b>%1</b> for correct USB access permissions.</p>").arg(file.fileName());
  74 + }
  75 + #else
  76 + #endif
  77 + messageNoDevices += tr("<p>Visit the build and run instruction "
  78 + "<a href='https://github.com/OpenHantek/openhantek/blob/master/docs/build.md'>website</a> for help.</p>");
  79 +
  80 + updateSupportedDevices();
  81 +
  82 + QTimer timer;
  83 + timer.setInterval(1000);
  84 + connect(&timer, &QTimer::timeout, [this, &model, &findDevices, &messageNoDevices]() {
  85 + if (findDevices->updateDeviceList())
  86 + model->updateDeviceList();
  87 + if (model->rowCount(QModelIndex())) {
  88 + ui->cmbDevices->setCurrentIndex(0);
  89 + } else {
  90 + ui->labelReadyState->setText(messageNoDevices);
  91 + }
  92 + });
  93 + timer.start();
  94 + QCoreApplication::sendEvent(&timer, new QTimerEvent(timer.timerId())); // immediate timer event
  95 +
  96 + show();
  97 + QCoreApplication::instance()->exec();
  98 + timer.stop();
  99 + close();
  100 +
  101 + return findDevices->takeDevice(selectedDevice);
  102 +}
  103 +
  104 +void SelectSupportedDevice::showLibUSBFailedDialogModel(int error)
  105 +{
  106 + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
  107 + ui->btnAddDevice->setEnabled(false);
  108 + ui->labelReadyState->setText(tr("Can't initalize USB: %1").arg(libUsbErrorString(error)));
  109 + show();
  110 + QCoreApplication::instance()->exec();
  111 + close();
  112 +}
  113 +
  114 +void SelectSupportedDevice::updateSupportedDevices()
  115 +{
  116 + QString devices;
  117 + for (const DSOModel* model: supportedModels) {
  118 + devices.append(QString::fromStdString(model->name)).append(" ");
  119 + }
  120 + ui->labelSupportedDevices->setText(devices);
  121 +}
... ...
openhantek/src/selectdevice/selectdevice.h renamed to openhantek/src/selectdevice/selectsupporteddevice.h
  1 +// SPDX-License-Identifier: GPL-2.0+
1 2 #pragma once
2 3  
3   -#include <QTableView>
4   -#include <QPushButton>
5   -#include <QVBoxLayout>
6   -#include <QDesktopWidget>
  4 +#include "ui_selectsupporteddevice.h"
  5 +
7 6 #include <QDialog>
8   -#include <QLabel>
  7 +
9 8 #include <memory>
10 9 #include "usb/usbdevice.h"
11 10  
12 11 struct libusb_context;
  12 +class NewDeviceModelFromExisting;
13 13  
14 14 /**
15   - * Offers the user a selection dialog. If you call any of the -Modal methods,
  15 + * Offers the user a device selection dialog. If you call any of the -Modal methods,
16 16 * the method will block and show a dialog for selection or for a usb error
17 17 * message. The method returns as soon as the user closes the dialog.
18 18 *
19   - * An example to get a device:
  19 + * An example to get a user selected device:
20 20 * std::unique_ptr<USBDevice> device = SelectDevice().showSelectDeviceModal(context);
21 21 */
22   -class SelectDevice: public QDialog {
  22 +class SelectSupportedDevice : public QDialog
  23 +{
  24 + Q_OBJECT
  25 +
23 26 public:
24   - SelectDevice();
25   - std::unique_ptr<USBDevice> showSelectDeviceModal(libusb_context *&context);
  27 + explicit SelectSupportedDevice(QWidget *parent = 0);
  28 + std::unique_ptr<USBDevice> showSelectDeviceModal(libusb_context *context);
26 29 void showLibUSBFailedDialogModel(int error);
27 30 private:
28   - void makeErrorDialog(const QString& message);
29 31 void updateDeviceList();
30   - void currentChanged(const QModelIndex &current, const QModelIndex &previous);
31   - QTableView *w;
32   - QLabel *label;
33   - QPushButton *btn;
  32 + void updateSupportedDevices();
  33 + std::unique_ptr<Ui::SelectSupportedDevice> ui;
34 34 UniqueUSBid selectedDevice = 0;
  35 + NewDeviceModelFromExisting* newDeviceFromExistingDialog;
35 36 };
... ...
openhantek/src/selectdevice/selectsupporteddevice.ui 0 → 100644
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<ui version="4.0">
  3 + <class>SelectSupportedDevice</class>
  4 + <widget class="QDialog" name="SelectSupportedDevice">
  5 + <property name="geometry">
  6 + <rect>
  7 + <x>0</x>
  8 + <y>0</y>
  9 + <width>381</width>
  10 + <height>266</height>
  11 + </rect>
  12 + </property>
  13 + <property name="windowTitle">
  14 + <string>Select device</string>
  15 + </property>
  16 + <layout class="QVBoxLayout" name="verticalLayout">
  17 + <item>
  18 + <widget class="QTabWidget" name="tabWidget">
  19 + <property name="tabShape">
  20 + <enum>QTabWidget::Rounded</enum>
  21 + </property>
  22 + <property name="currentIndex">
  23 + <number>0</number>
  24 + </property>
  25 + <widget class="QWidget" name="tab">
  26 + <attribute name="title">
  27 + <string>Supported device</string>
  28 + </attribute>
  29 + <layout class="QGridLayout" name="gridLayout">
  30 + <item row="0" column="0">
  31 + <widget class="QLabel" name="label">
  32 + <property name="sizePolicy">
  33 + <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
  34 + <horstretch>0</horstretch>
  35 + <verstretch>0</verstretch>
  36 + </sizepolicy>
  37 + </property>
  38 + <property name="text">
  39 + <string>Devices:</string>
  40 + </property>
  41 + </widget>
  42 + </item>
  43 + <item row="0" column="1">
  44 + <widget class="QLabel" name="labelSupportedDevices">
  45 + <property name="text">
  46 + <string>...</string>
  47 + </property>
  48 + <property name="wordWrap">
  49 + <bool>true</bool>
  50 + </property>
  51 + </widget>
  52 + </item>
  53 + <item row="1" column="1">
  54 + <widget class="QComboBox" name="cmbDevices"/>
  55 + </item>
  56 + <item row="2" column="1">
  57 + <widget class="QLabel" name="labelReadyState">
  58 + <property name="text">
  59 + <string>...</string>
  60 + </property>
  61 + <property name="wordWrap">
  62 + <bool>true</bool>
  63 + </property>
  64 + </widget>
  65 + </item>
  66 + <item row="3" column="1">
  67 + <spacer name="verticalSpacer">
  68 + <property name="orientation">
  69 + <enum>Qt::Vertical</enum>
  70 + </property>
  71 + <property name="sizeHint" stdset="0">
  72 + <size>
  73 + <width>20</width>
  74 + <height>40</height>
  75 + </size>
  76 + </property>
  77 + </spacer>
  78 + </item>
  79 + </layout>
  80 + </widget>
  81 + <widget class="QWidget" name="tab_2">
  82 + <attribute name="title">
  83 + <string>Try unsupported</string>
  84 + </attribute>
  85 + <layout class="QVBoxLayout" name="verticalLayout_2">
  86 + <item>
  87 + <widget class="QLabel" name="label_2">
  88 + <property name="text">
  89 + <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Your device might not directly be supported by OpenHantek. But it might be compatible to one of the existing devices. Help us to identify those devices and report back on our &lt;a href=&quot;https://github.com/OpenHantek/openhantek/issues&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;issue tracker&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
  90 + </property>
  91 + <property name="textFormat">
  92 + <enum>Qt::AutoText</enum>
  93 + </property>
  94 + <property name="wordWrap">
  95 + <bool>true</bool>
  96 + </property>
  97 + <property name="openExternalLinks">
  98 + <bool>true</bool>
  99 + </property>
  100 + </widget>
  101 + </item>
  102 + <item>
  103 + <widget class="QPushButton" name="btnAddDevice">
  104 + <property name="text">
  105 + <string>Add new device from template</string>
  106 + </property>
  107 + </widget>
  108 + </item>
  109 + </layout>
  110 + </widget>
  111 + </widget>
  112 + </item>
  113 + <item>
  114 + <widget class="QDialogButtonBox" name="buttonBox">
  115 + <property name="orientation">
  116 + <enum>Qt::Horizontal</enum>
  117 + </property>
  118 + <property name="standardButtons">
  119 + <set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
  120 + </property>
  121 + </widget>
  122 + </item>
  123 + </layout>
  124 + </widget>
  125 + <resources/>
  126 + <connections>
  127 + <connection>
  128 + <sender>buttonBox</sender>
  129 + <signal>accepted()</signal>
  130 + <receiver>SelectSupportedDevice</receiver>
  131 + <slot>accept()</slot>
  132 + <hints>
  133 + <hint type="sourcelabel">
  134 + <x>257</x>
  135 + <y>302</y>
  136 + </hint>
  137 + <hint type="destinationlabel">
  138 + <x>157</x>
  139 + <y>274</y>
  140 + </hint>
  141 + </hints>
  142 + </connection>
  143 + <connection>
  144 + <sender>buttonBox</sender>
  145 + <signal>rejected()</signal>
  146 + <receiver>SelectSupportedDevice</receiver>
  147 + <slot>reject()</slot>
  148 + <hints>
  149 + <hint type="sourcelabel">
  150 + <x>312</x>
  151 + <y>302</y>
  152 + </hint>
  153 + <hint type="destinationlabel">
  154 + <x>286</x>
  155 + <y>274</y>
  156 + </hint>
  157 + </hints>
  158 + </connection>
  159 + </connections>
  160 +</ui>
... ...
openhantek/src/settings.cpp
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// settings.cpp
5   -//
6   -// Copyright (C) 2010, 2011 Oliver Haag
7   -// oliver.haag@gmail.com
8   -//
9   -// This program is free software: you can redistribute it and/or modify it
10   -// under the terms of the GNU General Public License as published by the Free
11   -// Software Foundation, either version 3 of the License, or (at your option)
12   -// any later version.
13   -//
14   -// This program is distributed in the hope that it will be useful, but WITHOUT
15   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17   -// more details.
18   -//
19   -// You should have received a copy of the GNU General Public License along with
20   -// this program. If not, see <http://www.gnu.org/licenses/>.
21   -//
22   -////////////////////////////////////////////////////////////////////////////////
  1 +// SPDX-License-Identifier: GPL-2.0+
23 2  
24 3 #include <QApplication>
25 4 #include <QColor>
... ... @@ -32,8 +11,26 @@
32 11  
33 12 /// \brief Set the number of channels.
34 13 /// \param channels The new channel count, that will be applied to lists.
35   -DsoSettings::DsoSettings(unsigned int channels) {
36   - scope.physicalChannels = channels;
  14 +DsoSettings::DsoSettings(const Dso::ControlSettings* deviceSettings, const Dso::ControlSpecification* deviceSpecification)
  15 + : deviceSettings(deviceSettings), deviceSpecification(deviceSpecification) {
  16 +
  17 + // Add new channels to the list
  18 + while (scope.spectrum.size() < deviceSpecification->channels) {
  19 + // Spectrum
  20 + DsoSettingsScopeSpectrum newSpectrum;
  21 + newSpectrum.name = QApplication::tr("SP%1").arg(scope.spectrum.size()+1);
  22 + scope.spectrum.push_back(newSpectrum);
  23 +
  24 + // Voltage
  25 + DsoSettingsScopeVoltage newVoltage;
  26 + newVoltage.name = QApplication::tr("CH%1").arg(scope.voltage.size()+1);
  27 + scope.voltage.push_back(newVoltage);
  28 +
  29 + view.screen.voltage.push_back(QColor::fromHsv((int)(scope.spectrum.size()-1) * 60, 0xff, 0xff));
  30 + view.screen.spectrum.push_back(view.screen.voltage.back().lighter());
  31 + view.print.voltage.push_back(view.screen.voltage.back().darker(120));
  32 + view.print.spectrum.push_back(view.screen.voltage.back().darker());
  33 + }
37 34  
38 35 DsoSettingsScopeSpectrum newSpectrum;
39 36 newSpectrum.name = QApplication::tr("SPM");
... ... @@ -49,24 +46,6 @@ DsoSettings::DsoSettings(unsigned int channels) {
49 46 view.print.voltage.push_back(view.screen.voltage.back());
50 47 view.print.spectrum.push_back(view.print.voltage.back().darker());
51 48  
52   - // Add new channels to the list
53   - while (scope.spectrum.size() <= channels) {
54   - // Spectrum
55   - DsoSettingsScopeSpectrum newSpectrum;
56   - newSpectrum.name = QApplication::tr("SP%1").arg(scope.spectrum.size());
57   - scope.spectrum.insert(scope.spectrum.end()-1, newSpectrum);
58   -
59   - // Voltage
60   - DsoSettingsScopeVoltage newVoltage;
61   - newVoltage.coupling = Dso::COUPLING_DC;
62   - newVoltage.name = QApplication::tr("CH%1").arg(scope.voltage.size());
63   - scope.voltage.insert(scope.voltage.end()-1, newVoltage);
64   -
65   - view.screen.voltage.insert(view.screen.voltage.end()-1, QColor::fromHsv((int)(view.screen.voltage.size()-1) * 60, 0xff, 0xff));
66   - view.screen.spectrum.insert(view.screen.spectrum.end()-1, view.screen.voltage.back().lighter());
67   - view.print.voltage.insert(view.print.voltage.end()-1, view.screen.voltage.back().darker(120));
68   - view.print.spectrum.insert(view.print.spectrum.end()-1, view.screen.voltage.back().darker());
69   - }
70 49  
71 50 load();
72 51 }
... ... @@ -110,14 +89,14 @@ void DsoSettings::load() {
110 89 // Trigger
111 90 store->beginGroup("trigger");
112 91 if (store->contains("filter")) scope.trigger.filter = store->value("filter").toBool();
113   - if (store->contains("mode")) scope.trigger.mode = (Dso::TriggerMode)store->value("mode").toInt();
  92 + if (store->contains("mode")) scope.trigger.mode = (Dso::TriggerMode)store->value("mode").toUInt();
114 93 if (store->contains("position")) scope.trigger.position = store->value("position").toDouble();
115   - if (store->contains("slope")) scope.trigger.slope = (Dso::Slope)store->value("slope").toInt();
116   - if (store->contains("source")) scope.trigger.source = store->value("source").toInt();
  94 + if (store->contains("slope")) scope.trigger.slope = (Dso::Slope)store->value("slope").toUInt();
  95 + if (store->contains("source")) scope.trigger.source = store->value("source").toUInt();
117 96 if (store->contains("special")) scope.trigger.special = store->value("special").toInt();
118 97 store->endGroup();
119 98 // Spectrum
120   - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) {
  99 + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) {
121 100 store->beginGroup(QString("spectrum%1").arg(channel));
122 101 if (store->contains("magnitude"))
123 102 scope.spectrum[channel].magnitude = store->value("magnitude").toDouble();
... ... @@ -126,9 +105,10 @@ void DsoSettings::load() {
126 105 store->endGroup();
127 106 }
128 107 // Vertical axis
129   - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) {
  108 + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) {
130 109 store->beginGroup(QString("vertical%1").arg(channel));
131   - if (store->contains("gain")) scope.voltage[channel].gain = store->value("gain").toDouble();
  110 + if (store->contains("gainStepIndex")) scope.voltage[channel].gainStepIndex = store->value("gainStepIndex").toUInt();
  111 + if (store->contains("couplingIndex")) scope.voltage[channel].couplingIndex = store->value("couplingIndex").toUInt();
132 112 if (store->contains("inverted")) scope.voltage[channel].inverted = store->value("inverted").toBool();
133 113 if (store->contains("misc")) scope.voltage[channel].rawValue = store->value("misc").toInt();
134 114 if (store->contains("offset")) scope.voltage[channel].offset = store->value("offset").toDouble();
... ... @@ -162,12 +142,12 @@ void DsoSettings::load() {
162 142 if (store->contains("border")) colors->border = store->value("border").value<QColor>();
163 143 if (store->contains("grid")) colors->grid = store->value("grid").value<QColor>();
164 144 if (store->contains("markers")) colors->markers = store->value("markers").value<QColor>();
165   - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) {
  145 + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) {
166 146 QString key = QString("spectrum%1").arg(channel);
167 147 if (store->contains(key)) colors->spectrum[channel] = store->value(key).value<QColor>();
168 148 }
169 149 if (store->contains("text")) colors->text = store->value("text").value<QColor>();
170   - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) {
  150 + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) {
171 151 QString key = QString("voltage%1").arg(channel);
172 152 if (store->contains(key)) colors->voltage[channel] = store->value(key).value<QColor>();
173 153 }
... ... @@ -211,14 +191,14 @@ void DsoSettings::save() {
211 191 // Trigger
212 192 store->beginGroup("trigger");
213 193 store->setValue("filter", scope.trigger.filter);
214   - store->setValue("mode", scope.trigger.mode);
  194 + store->setValue("mode", (unsigned)scope.trigger.mode);
215 195 store->setValue("position", scope.trigger.position);
216   - store->setValue("slope", scope.trigger.slope);
  196 + store->setValue("slope", (unsigned)scope.trigger.slope);
217 197 store->setValue("source", scope.trigger.source);
218 198 store->setValue("special", scope.trigger.special);
219 199 store->endGroup();
220 200 // Spectrum
221   - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) {
  201 + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) {
222 202 store->beginGroup(QString("spectrum%1").arg(channel));
223 203 store->setValue("magnitude", scope.spectrum[channel].magnitude);
224 204 store->setValue("offset", scope.spectrum[channel].offset);
... ... @@ -226,9 +206,10 @@ void DsoSettings::save() {
226 206 store->endGroup();
227 207 }
228 208 // Vertical axis
229   - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) {
  209 + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) {
230 210 store->beginGroup(QString("vertical%1").arg(channel));
231   - store->setValue("gain", scope.voltage[channel].gain);
  211 + store->setValue("gainStepIndex", scope.voltage[channel].gainStepIndex);
  212 + store->setValue("couplingIndex", scope.voltage[channel].couplingIndex);
232 213 store->setValue("inverted", scope.voltage[channel].inverted);
233 214 store->setValue("misc", scope.voltage[channel].rawValue);
234 215 store->setValue("offset", scope.voltage[channel].offset);
... ... @@ -261,10 +242,10 @@ void DsoSettings::save() {
261 242 store->setValue("border", colors->border.name(QColor::HexArgb));
262 243 store->setValue("grid", colors->grid.name(QColor::HexArgb));
263 244 store->setValue("markers", colors->markers.name(QColor::HexArgb));
264   - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel)
  245 + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel)
265 246 store->setValue(QString("spectrum%1").arg(channel), colors->spectrum[channel].name(QColor::HexArgb));
266 247 store->setValue("text", colors->text.name(QColor::HexArgb));
267   - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel)
  248 + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel)
268 249 store->setValue(QString("voltage%1").arg(channel), colors->voltage[channel].name(QColor::HexArgb));
269 250 store->endGroup();
270 251 }
... ...
openhantek/src/settings.h
... ... @@ -9,6 +9,8 @@
9 9  
10 10 #include "scopesettings.h"
11 11 #include "viewsettings.h"
  12 +#include "hantekdso/controlspecification.h"
  13 +#include "hantekdso/controlsettings.h"
12 14  
13 15 ////////////////////////////////////////////////////////////////////////////////
14 16 /// \struct DsoSettingsOptions
... ... @@ -23,13 +25,21 @@ struct DsoSettingsOptions {
23 25 /// \brief Holds the settings of the program.
24 26 class DsoSettings {
25 27 public:
26   - explicit DsoSettings(unsigned int channels);
  28 + explicit DsoSettings(const Dso::ControlSettings* deviceSettings, const Dso::ControlSpecification* deviceSpecification);
27 29 bool setFilename(const QString &filename);
28 30  
29 31 DsoSettingsOptions options; ///< General options of the program
30 32 DsoSettingsScope scope; ///< All oscilloscope related settings
31 33 DsoSettingsView view; ///< All view related settings
32 34  
  35 + // Read only access to device settings and device specification
  36 + const Dso::ControlSettings* deviceSettings;
  37 + const Dso::ControlSpecification* deviceSpecification;
  38 +
  39 + Dso::Coupling coupling(ChannelID channel) {
  40 + return deviceSpecification->couplings[scope.voltage[channel].couplingIndex];
  41 + }
  42 +
33 43 QByteArray mainWindowGeometry; ///< Geometry of the main window
34 44 QByteArray mainWindowState; ///< State of docking windows and toolbars
35 45  
... ...
openhantek/src/usb/ezusb.cpp
... ... @@ -333,104 +333,6 @@ static int parse_ihex(FILE *image, void *context, bool (*is_external)(uint32_t a
333 333 }
334 334  
335 335 /*
336   - * Parse a binary image file and write it as is to the target.
337   - * Applies to Cypress BIX images for RAM or Cypress IIC images
338   - * for EEPROM.
339   - *
340   - * image - the BIX image file
341   - * context - for use by poke()
342   - * is_external - if non-null, used to check which segments go into
343   - * external memory (writable only by software loader)
344   - * poke - called with each memory segment; errors indicated
345   - * by returning negative values.
346   - *
347   - * Caller is responsible for halting CPU as needed, such as when
348   - * overwriting a second stage loader.
349   - */
350   -static int parse_bin(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
351   - int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) {
352   - unsigned char data[4096];
353   - uint32_t data_addr = 0;
354   - size_t data_len = 0;
355   - int rc;
356   - bool external = false;
357   -
358   - for (;;) {
359   - data_len = fread(data, 1, 4096, image);
360   - if (data_len == 0) break;
361   - if (is_external) external = is_external(data_addr, data_len);
362   - rc = poke(context, data_addr, external, data, data_len);
363   - if (rc < 0) return -1;
364   - data_addr += (uint32_t)data_len;
365   - }
366   - return feof(image) ? 0 : -1;
367   -}
368   -
369   -/*
370   - * Parse a Cypress IIC image file and invoke the poke() function on the
371   - * various segments for writing to RAM
372   - *
373   - * image - the IIC image file
374   - * context - for use by poke()
375   - * is_external - if non-null, used to check which segments go into
376   - * external memory (writable only by software loader)
377   - * poke - called with each memory segment; errors indicated
378   - * by returning negative values.
379   - *
380   - * Caller is responsible for halting CPU as needed, such as when
381   - * overwriting a second stage loader.
382   - */
383   -static int parse_iic(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
384   - int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) {
385   - unsigned char data[4096];
386   - uint32_t data_addr = 0;
387   - size_t data_len = 0, read_len;
388   - uint8_t block_header[4];
389   - int rc;
390   - bool external = false;
391   - long file_size, initial_pos;
392   -
393   - initial_pos = ftell(image);
394   - if (initial_pos < 0) return -1;
395   -
396   - if (fseek(image, 0L, SEEK_END) != 0) return -1;
397   - file_size = ftell(image);
398   - if (fseek(image, initial_pos, SEEK_SET) != 0) return -1;
399   - for (;;) {
400   - /* Ignore the trailing reset IIC data (5 bytes) */
401   - if (ftell(image) >= (file_size - 5)) break;
402   - if (fread(&block_header, 1, sizeof(block_header), image) != 4) {
403   - logerror("unable to read IIC block header\n");
404   - return -1;
405   - }
406   - data_len = (block_header[0] << 8) + block_header[1];
407   - data_addr = (block_header[2] << 8) + block_header[3];
408   - if (data_len > sizeof(data)) {
409   - /* If this is ever reported as an error, switch to using malloc/realloc */
410   - logerror("IIC data block too small - please report this error to "
411   - "libusb.info\n");
412   - return -1;
413   - }
414   - read_len = fread(data, 1, data_len, image);
415   - if (read_len != data_len) {
416   - logerror("read error\n");
417   - return -1;
418   - }
419   - if (is_external) external = is_external(data_addr, data_len);
420   - rc = poke(context, data_addr, external, data, data_len);
421   - if (rc < 0) return -1;
422   - }
423   - return 0;
424   -}
425   -
426   -/* the parse call will be selected according to the image type */
427   -static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
428   - int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data,
429   - size_t len)) = {parse_ihex, parse_iic, parse_bin};
430   -
431   -/*****************************************************************************/
432   -
433   -/*
434 336 * For writing to RAM using a first (hardware) or second (software)
435 337 * stage loader and 0xA0 or 0xA3 vendor requests
436 338 */
... ... @@ -641,13 +543,12 @@ exit:
641 543 * memory is written, expecting a second stage loader to have already
642 544 * been loaded. Then file is re-parsed and on-chip memory is written.
643 545 */
644   -int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage) {
  546 +int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int stage) {
645 547 FILE *image;
646 548 uint32_t cpucs_addr;
647 549 bool (*is_external)(uint32_t off, size_t len);
648 550 struct ram_poke_context ctx;
649 551 int status;
650   - uint8_t iic_header[8] = {0};
651 552 int ret = 0;
652 553  
653 554 if (fx_type == FX_TYPE_FX3) return fx3_load_ram(device, path);
... ... @@ -659,16 +560,6 @@ int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type,
659 560 } else if (verbose > 1)
660 561 logerror("open firmware image %s for RAM upload\n", path);
661 562  
662   - if (img_type == IMG_TYPE_IIC) {
663   - if ((fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header)) ||
664   - (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2)) ||
665   - ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2)) ||
666   - ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6))) {
667   - logerror("IIC image does not contain executable code - cannot load to RAM.\n");
668   - ret = -1;
669   - goto exit;
670   - }
671   - }
672 563  
673 564 /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
674 565 switch (fx_type) {
... ... @@ -707,7 +598,7 @@ int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type,
707 598 /* scan the image, first (maybe only) time */
708 599 ctx.device = device;
709 600 ctx.total = ctx.count = 0;
710   - status = parse[img_type](image, &ctx, is_external, ram_poke);
  601 + status = parse_ihex(image, &ctx, is_external, ram_poke);
711 602 if (status < 0) {
712 603 logerror("unable to upload %s\n", path);
713 604 ret = status;
... ...
openhantek/src/usb/ezusb.h
... ... @@ -23,51 +23,9 @@
23 23 #include <inttypes.h>
24 24  
25 25 struct libusb_device_handle;
26   -
27   -#define FX_TYPE_UNDEFINED -1
28   -#define FX_TYPE_AN21 0 /* Original AnchorChips parts */
29   -#define FX_TYPE_FX1 1 /* Updated Cypress versions */
30 26 #define FX_TYPE_FX2 2 /* USB 2.0 versions */
31 27 #define FX_TYPE_FX2LP 3 /* Updated FX2 */
32 28 #define FX_TYPE_FX3 4 /* USB 3.0 versions */
33   -#define FX_TYPE_MAX 5
34   -#define FX_TYPE_NAMES \
35   - { "an21", "fx", "fx2", "fx2lp", "fx3" }
36   -
37   -#define IMG_TYPE_UNDEFINED -1
38   -#define IMG_TYPE_HEX 0 /* Intel HEX */
39   -#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */
40   -#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */
41   -#define IMG_TYPE_IMG 3 /* Cypress IMG format */
42   -#define IMG_TYPE_MAX 4
43   -#define IMG_TYPE_NAMES \
44   - { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" }
45   -
46   -/*
47   - * Automatically identified devices (VID, PID, type, designation).
48   - */
49   -typedef struct {
50   - uint16_t vid;
51   - uint16_t pid;
52   - int type;
53   - const char *designation;
54   -} fx_known_device;
55   -
56   -#define FX_KNOWN_DEVICES \
57   - { \
58   - {0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)"}, \
59   - {0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)"}, \
60   - {0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)"}, \
61   - {0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)"}, \
62   - {0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)"}, \
63   - {0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)"}, \
64   - {0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)"}, \
65   - {0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)"}, \
66   - {0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)"}, \
67   - {0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1"}, \
68   - {0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)"}, \
69   - {0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3"}, \
70   - }
71 29  
72 30 /*
73 31 * This function uploads the firmware from the given file into RAM.
... ... @@ -77,20 +35,7 @@ typedef struct {
77 35 *
78 36 * The target processor is reset at the end of this upload.
79 37 */
80   -extern int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage);
81   -
82   -/*
83   - * This function uploads the firmware from the given file into EEPROM.
84   - * This uses the right CPUCS address to terminate the EEPROM load with
85   - * a reset command where FX parts behave differently than FX2 ones.
86   - * The configuration byte is as provided here (zero for an21xx parts)
87   - * and the EEPROM type is set so that the microcontroller will boot
88   - * from it.
89   - *
90   - * The caller must have preloaded a second stage loader that knows
91   - * how to respond to the EEPROM write request.
92   - */
93   -extern int ezusb_load_eeprom(libusb_device_handle *device, const char *path, int fx_type, int img_type, int config);
  38 +extern int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int stage);
94 39  
95 40 /* Verbosity level (default 1). Can be increased or decreased with options v/q
96 41 */
... ...
openhantek/src/usb/uploadFirmware.cpp
... ... @@ -49,7 +49,7 @@ bool UploadFirmware::startUpload(USBDevice *device) {
49 49 }
50 50  
51 51 // Write loader
52   - status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 0);
  52 + status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, 0);
53 53  
54 54 if (status != LIBUSB_SUCCESS) {
55 55 errorMessage = TR("Writing the loader firmware failed: %1").arg(libusb_error_name(status));
... ... @@ -59,7 +59,7 @@ bool UploadFirmware::startUpload(USBDevice *device) {
59 59 }
60 60  
61 61 // Write firmware
62   - status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 1);
  62 + status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, 1);
63 63  
64 64 if (status != LIBUSB_SUCCESS) {
65 65 errorMessage = TR("Writing the main firmware failed: %1").arg(libusb_error_name(status));
... ...
openhantek/src/usb/usbdevice.cpp
... ... @@ -177,7 +177,7 @@ int USBDevice::bulkCommand(const DataArray&lt;unsigned char&gt; *command, int attempts
177 177 if (!allowBulkTransfer) return LIBUSB_SUCCESS;
178 178  
179 179 // Send BeginCommand control command
180   - int errorCode = this->controlWrite(CONTROL_BEGINCOMMAND, beginCommandControl.data(),
  180 + int errorCode = this->controlWrite((uint8_t)Hantek::ControlCode::CONTROL_BEGINCOMMAND, beginCommandControl.data(),
181 181 beginCommandControl.getSize());
182 182 if (errorCode < 0) return errorCode;
183 183  
... ... @@ -242,10 +242,10 @@ int USBDevice::controlTransfer(unsigned char type, unsigned char request, unsign
242 242 /// \param index The index field of the packet.
243 243 /// \param attempts The number of attempts, that are done on timeouts.
244 244 /// \return Number of sent bytes on success, libusb error code on error.
245   -int USBDevice::controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value, int index,
  245 +int USBDevice::controlWrite(uint8_t request, unsigned char *data, unsigned int length, int value, int index,
246 246 int attempts) {
247 247 if (!this->handle) return LIBUSB_ERROR_NO_DEVICE;
248   -
  248 + // std::cout << "control" << (int)request << " l:"<<length<<" d:"<<(int)data[0] << std::endl;
249 249 return this->controlTransfer(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, request, data, length, value, index,
250 250 attempts);
251 251 }
... ... @@ -272,7 +272,7 @@ int USBDevice::getConnectionSpeed() {
272 272 int errorCode;
273 273 ControlGetSpeed response;
274 274  
275   - errorCode = this->controlRead(CONTROL_GETSPEED, response.data(), response.getSize());
  275 + errorCode = this->controlRead((uint8_t)Hantek::ControlCode::CONTROL_GETSPEED, response.data(), response.getSize());
276 276 if (errorCode < 0) return errorCode;
277 277  
278 278 return response.getSpeed();
... ...
openhantek/src/usb/usbdevice.h
... ... @@ -57,7 +57,7 @@ class USBDevice : public QObject {
57 57  
58 58 int controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value,
59 59 int index, int attempts = HANTEK_ATTEMPTS);
60   - int controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0,
  60 + int controlWrite(uint8_t request, unsigned char *data, unsigned int length, int value = 0, int index = 0,
61 61 int attempts = HANTEK_ATTEMPTS);
62 62 int controlRead(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0,
63 63 int attempts = HANTEK_ATTEMPTS);
... ...
openhantek/src/utils/dsoStrings.cpp
... ... @@ -31,13 +31,12 @@ namespace Dso {
31 31 /// \return The string that should be used in labels etc., empty when invalid.
32 32 QString channelModeString(ChannelMode mode) {
33 33 switch (mode) {
34   - case CHANNELMODE_VOLTAGE:
  34 + case ChannelMode::Voltage:
35 35 return QApplication::tr("Voltage");
36   - case CHANNELMODE_SPECTRUM:
  36 + case ChannelMode::Spectrum:
37 37 return QApplication::tr("Spectrum");
38   - default:
39   - return QString();
40 38 }
  39 + return QString();
41 40 }
42 41  
43 42 /// \brief Return string representation of the given graph format.
... ... @@ -45,13 +44,12 @@ QString channelModeString(ChannelMode mode) {
45 44 /// \return The string that should be used in labels etc.
46 45 QString graphFormatString(GraphFormat format) {
47 46 switch (format) {
48   - case GRAPHFORMAT_TY:
  47 + case GraphFormat::TY:
49 48 return QApplication::tr("T - Y");
50   - case GRAPHFORMAT_XY:
  49 + case GraphFormat::XY:
51 50 return QApplication::tr("X - Y");
52   - default:
53   - return QString();
54 51 }
  52 + return QString();
55 53 }
56 54  
57 55 /// \brief Return string representation of the given channel coupling.
... ... @@ -59,15 +57,14 @@ QString graphFormatString(GraphFormat format) {
59 57 /// \return The string that should be used in labels etc.
60 58 QString couplingString(Coupling coupling) {
61 59 switch (coupling) {
62   - case COUPLING_AC:
  60 + case Coupling::AC:
63 61 return QApplication::tr("AC");
64   - case COUPLING_DC:
  62 + case Coupling::DC:
65 63 return QApplication::tr("DC");
66   - case COUPLING_GND:
  64 + case Coupling::GND:
67 65 return QApplication::tr("GND");
68   - default:
69   - return QString();
70 66 }
  67 + return QString();
71 68 }
72 69  
73 70 /// \brief Return string representation of the given math mode.
... ... @@ -81,9 +78,8 @@ QString mathModeString(MathMode mode) {
81 78 return QApplication::tr("CH1 - CH2");
82 79 case MathMode::SUB_CH1_FROM_CH2:
83 80 return QApplication::tr("CH2 - CH1");
84   - default:
85   - return QString();
86 81 }
  82 + return QString();
87 83 }
88 84  
89 85 /// \brief Return string representation of the given trigger mode.
... ... @@ -91,17 +87,16 @@ QString mathModeString(MathMode mode) {
91 87 /// \return The string that should be used in labels etc.
92 88 QString triggerModeString(TriggerMode mode) {
93 89 switch (mode) {
94   - case TRIGGERMODE_AUTO:
  90 + case TriggerMode::AUTO:
95 91 return QApplication::tr("Auto");
96   - case TRIGGERMODE_NORMAL:
  92 + case TriggerMode::NORMAL:
97 93 return QApplication::tr("Normal");
98   - case TRIGGERMODE_SINGLE:
  94 + case TriggerMode::SINGLE:
99 95 return QApplication::tr("Single");
100   - case TRIGGERMODE_SOFTWARE:
  96 + case TriggerMode::SOFTWARE:
101 97 return QApplication::tr("Software");
102   - default:
103   - return QString();
104 98 }
  99 + return QString();
105 100 }
106 101  
107 102 /// \brief Return string representation of the given trigger slope.
... ... @@ -109,9 +104,9 @@ QString triggerModeString(TriggerMode mode) {
109 104 /// \return The string that should be used in labels etc.
110 105 QString slopeString(Slope slope) {
111 106 switch (slope) {
112   - case SLOPE_POSITIVE:
  107 + case Slope::Positive:
113 108 return QString::fromUtf8("\u2197");
114   - case SLOPE_NEGATIVE:
  109 + case Slope::Negative:
115 110 return QString::fromUtf8("\u2198");
116 111 default:
117 112 return QString();
... ...
openhantek/src/utils/enumclass.h
... ... @@ -2,7 +2,7 @@
2 2  
3 3 #pragma once
4 4  
5   -template< typename T >
  5 +template< typename T, T first, T last >
6 6 class Enum
7 7 {
8 8 public:
... ... @@ -34,14 +34,14 @@ public:
34 34  
35 35 };
36 36  
37   -template< typename T >
38   -typename Enum<T>::Iterator begin( Enum<T> )
  37 +template< typename T, T first, T last >
  38 +typename Enum<T,first,last>::Iterator begin( Enum<T,first,last> )
39 39 {
40   - return typename Enum<T>::Iterator( (int)T::First );
  40 + return typename Enum<T,first,last>::Iterator( (int)first );
41 41 }
42 42  
43   -template< typename T >
44   -typename Enum<T>::Iterator end( Enum<T> )
  43 +template< typename T, T first, T last >
  44 +typename Enum<T,first,last>::Iterator end( Enum<T,first,last> )
45 45 {
46   - return typename Enum<T>::Iterator( ((int)T::Last) + 1 );
  46 + return typename Enum<T,first,last>::Iterator( ((int)last) + 1 );
47 47 }
... ...
openhantek/src/viewconstants.h
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
1 3 #pragma once
2 4  
3 5 #define DIVS_TIME 10.0f ///< Number of horizontal screen divs
... ...
openhantek/src/viewsettings.h
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
1 3 #pragma once
2 4  
3 5 #include <QColor>
... ... @@ -6,16 +8,18 @@
6 8 #include <QString>
7 9 #include <QVector>
8 10  
  11 +#include "hantekdso/enums.h"
  12 +
9 13 ////////////////////////////////////////////////////////////////////////////////
10 14 /// \struct DsoSettingsColorValues
11 15 /// \brief Holds the color values for the oscilloscope screen.
12 16 struct DsoSettingsColorValues {
13   - QColor axes; ///< X- and Y-axis and subdiv lines on them
14   - QColor background; ///< The scope background
15   - QColor border; ///< The border of the scope screen
16   - QColor grid; ///< The color of the grid
17   - QColor markers; ///< The color of the markers
18   - QColor text; ///< The default text color
  17 + QColor axes; ///< X- and Y-axis and subdiv lines on them
  18 + QColor background; ///< The scope background
  19 + QColor border; ///< The border of the scope screen
  20 + QColor grid; ///< The color of the grid
  21 + QColor markers; ///< The color of the markers
  22 + QColor text; ///< The default text color
19 23 std::vector<QColor> spectrum; ///< The colors of the spectrum graphs
20 24 std::vector<QColor> voltage; ///< The colors of the voltage graphs
21 25 };
... ... @@ -24,26 +28,22 @@ struct DsoSettingsColorValues {
24 28 /// \struct DsoSettingsView
25 29 /// \brief Holds all view settings.
26 30 struct DsoSettingsView {
27   - DsoSettingsColorValues screen = {QColor(0xff, 0xff, 0xff, 0x7f),
28   - QColor(0x00, 0x00, 0x00, 0xff),
29   - QColor(0xff, 0xff, 0xff, 0xff),
30   - QColor(0xff, 0xff, 0xff, 0x3f),
31   - QColor(0xff, 0xff, 0xff, 0xbf),
32   - QColor(0xff, 0xff, 0xff, 0xff),
33   - std::vector<QColor>(),
34   - std::vector<QColor>()};
35   - DsoSettingsColorValues print = {QColor(0x00, 0x00, 0x00, 0xbf),
36   - QColor(0x00, 0x00, 0x00, 0x00),
37   - QColor(0x00, 0x00, 0x00, 0xff),
38   - QColor(0x00, 0x00, 0x00, 0x7f),
39   - QColor(0x00, 0x00, 0x00, 0xef),
40   - QColor(0x00, 0x00, 0x00, 0xff),
41   - std::vector<QColor>(),
42   - std::vector<QColor>()};
  31 + DsoSettingsColorValues screen = {QColor(0xff, 0xff, 0xff, 0x7f), QColor(0x00, 0x00, 0x00, 0xff),
  32 + QColor(0xff, 0xff, 0xff, 0xff), QColor(0xff, 0xff, 0xff, 0x3f),
  33 + QColor(0xff, 0xff, 0xff, 0xbf), QColor(0xff, 0xff, 0xff, 0xff),
  34 + std::vector<QColor>(), std::vector<QColor>()};
  35 + DsoSettingsColorValues print = {QColor(0x00, 0x00, 0x00, 0xbf), QColor(0x00, 0x00, 0x00, 0x00),
  36 + QColor(0x00, 0x00, 0x00, 0xff), QColor(0x00, 0x00, 0x00, 0x7f),
  37 + QColor(0x00, 0x00, 0x00, 0xef), QColor(0x00, 0x00, 0x00, 0xff),
  38 + std::vector<QColor>(), std::vector<QColor>()};
43 39 bool antialiasing = true; ///< Antialiasing for the graphs
44 40 bool digitalPhosphor = false; ///< true slowly fades out the previous graphs
45   - unsigned digitalPhosphorDepth = 8; ///< Number of channels shown at one time
  41 + unsigned digitalPhosphorDepth = 8; ///< Number of channels shown at one time
46 42 Dso::InterpolationMode interpolation = Dso::INTERPOLATION_LINEAR; ///< Interpolation mode for the graph
47 43 bool screenColorImages = false; ///< true exports images with screen colors
48 44 bool zoom = false; ///< true if the magnified scope is enabled
  45 +
  46 + unsigned digitalPhosphorDraws() const {
  47 + return digitalPhosphor ? digitalPhosphorDepth : 1;
  48 + }
49 49 };
... ...
openhantek/src/widgets/colorbox.cpp
... ... @@ -35,7 +35,7 @@
35 35 ColorBox::ColorBox(QColor color, QWidget *parent) : QPushButton(parent) {
36 36 this->setColor(color);
37 37  
38   - connect(this, SIGNAL(clicked()), this, SLOT(waitForColor()));
  38 + connect(this, &QAbstractButton::clicked, this, &ColorBox::waitForColor);
39 39 }
40 40  
41 41 /// \brief Cleans up the widget.
... ...
openhantek/src/widgets/sispinbox.cpp
... ... @@ -170,7 +170,7 @@ void SiSpinBox::init() {
170 170 this->stepId = 0;
171 171 this->mode = 0;
172 172  
173   - connect(this, SIGNAL(valueChanged(double)), this, SLOT(resetSteppedTo()));
  173 + connect(this, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &SiSpinBox::resetSteppedTo);
174 174 }
175 175  
176 176 /// \brief Resets the ::steppedTo flag after the value has been changed.
... ...