Commit b7a65b8aa3c13848b49d366c07a5ec2e55d351de

Authored by David Graeff
1 parent 45521b43

Refactor: Split and reorganise files. Add firmware upload functionality.

* Use QMutexLocker -> avoids deadlocks that I encountered
* HantekDsoControl shouldn't implement QThread and use Qtimer, it is just a worker class with a periodic run() method.
* Udev rules file altered: Allow access to firmware flashed and unflashed hantek devices
* Everything that is non-gui is in the subdirectory hantek now.
* Everything that is USB communication/find USB devices/upload to USB device is in the subdirectory 'usb' now.
* Utility classes are in the subdirectory 'utils'.
* Split types.h/cpp

Signed-off-by: David Graeff <david.graeff@web.de>
Showing 70 changed files with 6516 additions and 5805 deletions
CMakeLists.txt
... ... @@ -11,21 +11,30 @@ list(APPEND CMAKE_MODULE_PATH &quot;${CMAKE_CURRENT_LIST_DIR}/cmake/&quot;)
11 11  
12 12 INCLUDE_DIRECTORIES("." "/usr/local/include")
13 13  
14   -# Qt Widgets based Gui with OpenGL canvas
15   -add_subdirectory(openhantek)
16   -
17 14 # Use CPack to make deb/rpm/zip/exe installer packages
18 15 include(cmake/CPackInfos.cmake)
19 16  
  17 +# Qt Widgets based Gui with OpenGL canvas
  18 +add_subdirectory(openhantek)
  19 +
20 20 if (WIN32)
21 21 install(FILES COPYING readme.md DESTINATION ".")
22 22 endif()
23 23  
  24 +if("${CMAKE_SYSTEM}" MATCHES "Linux")
  25 + if(EXISTS "/lib/udev/rules.d/")
  26 + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/firmware/60-hantek.rules"
  27 + DESTINATION "/lib/udev/rules.d/" COMPONENT Runtime)
  28 + else()
  29 + message(WARNING "Could not find udev rules directory (/lib/udev/rules.d/), skipping installation of udev rules.")
  30 + endif()
  31 +endif()
  32 +
24 33 # Add auxiliary files to the project, so that these files appear in VisualStudio/QtCreator
25 34 add_custom_target(readme SOURCES readme.md)
26 35  
27 36 # Add "cppcheck" command
28   -add_custom_target(cppcheck COMMAND "cppcheck --enable=all -I \"${CMAKE_CURRENT_LIST_DIR}/libusbDSO\" -I \"${CMAKE_CURRENT_LIST_DIR}/libPostprocessingDSO\" -I \"${CMAKE_CURRENT_LIST_DIR}/openhantek/src\" -q ${SRC} --template=\"{file}:{line}: {severity}: {message}\"")
  37 +add_custom_target(cppcheck COMMAND "cppcheck --enable=all -I \"${CMAKE_CURRENT_LIST_DIR}/openhantek/src\" -q ${SRC} --template=\"{file}:{line}: {severity}: {message}\"")
29 38  
30 39 # Add "doc" target to build the documentation.
31 40 find_package(Doxygen QUIET)
... ...
firmware/60-hantek.rules
1 1 # Hantek DSO-2090
2   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/2090/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso2090x86-firmware.hex -s /usr/local/share/hantek/dso2090x86-loader.hex -D $env{DEVNAME}"
3   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/8613/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso2090x86-firmware.hex -s /usr/local/share/hantek/dso2090x86-loader.hex -D $env{DEVNAME}"
4   -ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", TAG+="uaccess", TAG+="udev-acl"
  2 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2090", TAG+="uaccess", TAG+="udev-acl"
  3 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2090", TAG+="uaccess", TAG+="udev-acl"
  4 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="8613", TAG+="uaccess", TAG+="udev-acl"
5 5  
6 6 # Hantek DSO-2150
7   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/2150/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso2150x86-firmware.hex -s /usr/local/share/hantek/dso2150x86-loader.hex -D $env{DEVNAME}"
8   -ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", TAG+="uaccess", TAG+="udev-acl"
  7 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2150", TAG+="uaccess", TAG+="udev-acl"
  8 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2150", TAG+="uaccess", TAG+="udev-acl"
9 9  
10 10 # Hantek DSO-2250
11   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/2250/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso2250x86-firmware.hex -s /usr/local/share/hantek/dso2250x86-loader.hex -D $env{DEVNAME}"
12   -ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", TAG+="uaccess", TAG+="udev-acl"
  11 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="2250", TAG+="uaccess", TAG+="udev-acl"
  12 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="2250", TAG+="uaccess", TAG+="udev-acl"
13 13  
14 14 # Hantek DSO-5200
15   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/5200/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso5200x86-firmware.hex -s /usr/local/share/hantek/dso5200x86-loader.hex -D $env{DEVNAME}"
16   -ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", TAG+="uaccess", TAG+="udev-acl"
  15 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="5200", TAG+="uaccess", TAG+="udev-acl"
  16 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="5200", TAG+="uaccess", TAG+="udev-acl"
17 17  
18 18 # Hantek DSO-5200A
19   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/520a/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso5200ax86-firmware.hex -s /usr/local/share/hantek/dso5200ax86-loader.hex -D $env{DEVNAME}"
20   -ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", TAG+="uaccess", TAG+="udev-acl"
  19 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="520a", TAG+="uaccess", TAG+="udev-acl"
  20 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="520a", TAG+="uaccess", TAG+="udev-acl"
21 21  
22   -# Hantek DSO-6022BE
23   -SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="4b4/6022/*", RUN+="/sbin/fxload -t fx2 -I /usr/local/share/hantek/dso6022be-firmware.hex -s /usr/local/share/hantek/dso6022be-loader.hex -D $env{DEVNAME}"
24   -ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="6022", TAG+="uaccess", TAG+="udev-acl"
  22 +# Hantek DSO-6022BE/BL
  23 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="6022", TAG+="uaccess", TAG+="udev-acl"
  24 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b5", ATTRS{idProduct}=="602a", TAG+="uaccess", TAG+="udev-acl"
  25 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="6022", TAG+="uaccess", TAG+="udev-acl"
  26 +SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="04b4", ATTRS{idProduct}=="602a", TAG+="uaccess", TAG+="udev-acl"
... ...
firmware/extractfw/Makefile renamed to firmware/Makefile
firmware/README.md
1   -Binary firmware extracted from the Hantek Windows drivers downloaded from
2   -<http://www.hantek.com/en/ProductDetail_2_44.html>, using the script `fwget.sh`.
3   -
4   -I have only tested the DSO2090 firmware. All these models are listed on the
5   -"DSO2000 Series" page on the Hantek website.
6   -
  1 +Use the `fwget.sh` script to extract a firmware from a windows driver.
7 2 The copyright belongs to Hantek.
... ...
firmware/extractfw/extractfw.c renamed to firmware/extractfw.c
firmware/extractfw/.gitignore deleted
1   -extractfw
2   -*.o
firmware/fwget.sh
... ... @@ -3,6 +3,7 @@
3 3 shopt -s globstar
4 4  
5 5 cd "$(dirname "$0")"
  6 +make
6 7 rm -rf tmp
7 8 mkdir tmp
8 9  
... ... @@ -14,7 +15,7 @@ done
14 15 cd ..
15 16  
16 17 for f in tmp/**/*.sys; do
17   - extractfw/extractfw $f
  18 + ./extractfw $f
18 19 done
19 20 mv tmp/**/*.hex .
20 21 rm -rf tmp
... ...
openhantek/CMakeLists.txt
... ... @@ -10,7 +10,7 @@ set(CMAKE_AUTORCC ON)
10 10  
11 11 # include directories
12 12 set(CMAKE_INCLUDE_CURRENT_DIR ON)
13   -include_directories(src/ src/hantek)
  13 +include_directories(src/ src/dso src/hantek)
14 14  
15 15 # collect sources and other files
16 16 file(GLOB_RECURSE SRC "src/*.cpp")
... ...
firmware/dso2090x86-firmware.hex renamed to openhantek/res/firmware/dso2090x86-firmware.hex
firmware/dso2090x86-loader.hex renamed to openhantek/res/firmware/dso2090x86-loader.hex
firmware/dso2150x86-firmware.hex renamed to openhantek/res/firmware/dso2150x86-firmware.hex
firmware/dso2150x86-loader.hex renamed to openhantek/res/firmware/dso2150x86-loader.hex
firmware/dso2250x86-firmware.hex renamed to openhantek/res/firmware/dso2250x86-firmware.hex
firmware/dso2250x86-loader.hex renamed to openhantek/res/firmware/dso2250x86-loader.hex
firmware/dso5200ax86-firmware.hex renamed to openhantek/res/firmware/dso5200ax86-firmware.hex
firmware/dso5200ax86-loader.hex renamed to openhantek/res/firmware/dso5200ax86-loader.hex
firmware/dso5200x86-firmware.hex renamed to openhantek/res/firmware/dso5200x86-firmware.hex
firmware/dso5200x86-loader.hex renamed to openhantek/res/firmware/dso5200x86-loader.hex
firmware/dso6022be-firmware.hex renamed to openhantek/res/firmware/dso6022be-firmware.hex
firmware/dso6022be-loader.hex renamed to openhantek/res/firmware/dso6022be-loader.hex
openhantek/res/firmwares.qrc 0 โ†’ 100644
  1 +<RCC>
  2 + <qresource prefix="/">
  3 + <file>firmware/dso2090x86-firmware.hex</file>
  4 + <file>firmware/dso2090x86-loader.hex</file>
  5 + <file>firmware/dso2150x86-firmware.hex</file>
  6 + <file>firmware/dso2150x86-loader.hex</file>
  7 + <file>firmware/dso2250x86-firmware.hex</file>
  8 + <file>firmware/dso2250x86-loader.hex</file>
  9 + <file>firmware/dso5200ax86-firmware.hex</file>
  10 + <file>firmware/dso5200ax86-loader.hex</file>
  11 + <file>firmware/dso5200x86-firmware.hex</file>
  12 + <file>firmware/dso5200x86-loader.hex</file>
  13 + <file>firmware/dso6022be-firmware.hex</file>
  14 + <file>firmware/dso6022be-loader.hex</file>
  15 + </qresource>
  16 +</RCC>
... ...
openhantek/src/configpages.h
... ... @@ -27,7 +27,7 @@
27 27  
28 28 #include <QWidget>
29 29  
30   -#include "dso.h"
  30 +#include "definitions.h"
31 31 #include "dsowidget.h"
32 32  
33 33 class ColorBox;
... ...
openhantek/src/dataanalyzer.cpp
... ... @@ -32,7 +32,7 @@
32 32 #include "dataanalyzer.h"
33 33  
34 34 #include "glscope.h"
35   -#include "helper.h"
  35 +#include "utils/printutils.h"
36 36 #include "settings.h"
37 37  
38 38 ////////////////////////////////////////////////////////////////////////////////
... ... @@ -48,30 +48,6 @@ AnalyzedData::AnalyzedData() {
48 48 this->frequency = 0.0;
49 49 }
50 50  
51   -////////////////////////////////////////////////////////////////////////////////
52   -// class DataAnalyzer
53   -/// \brief Initializes the buffers and other variables.
54   -/// \param settings The settings that should be used.
55   -/// \param parent The parent widget.
56   -DataAnalyzer::DataAnalyzer(DsoSettings *settings, QObject *parent)
57   - : QThread(parent) {
58   - this->settings = settings;
59   -
60   - this->lastRecordLength = 0;
61   - this->lastWindow = (Dso::WindowFunction)-1;
62   - this->window = 0;
63   -
64   - this->analyzedDataMutex = new QMutex();
65   -
66   - this->maxSamples = 0;
67   -
68   - this->waitingDataSamplerate = 0.0;
69   - this->waitingDataMutex = 0;
70   -}
71   -
72   -/// \brief Deallocates the buffers.
73   -DataAnalyzer::~DataAnalyzer() {}
74   -
75 51 /// \brief Returns the analyzed data.
76 52 /// \param channel Channel, whose data should be returned.
77 53 /// \return Analyzed data as AnalyzedData struct.
... ... @@ -86,121 +62,126 @@ AnalyzedData const *DataAnalyzer::data(unsigned int channel) const {
86 62 /// \return The maximum sample count of the last analyzed data.
87 63 unsigned int DataAnalyzer::sampleCount() { return this->maxSamples; }
88 64  
89   -/// \brief Returns the mutex for the data.
90   -/// \return Mutex for the analyzed data.
91 65 QMutex *DataAnalyzer::mutex() const { return this->analyzedDataMutex; }
92 66  
93   -/// \brief Analyzes the data from the dso.
94   -void DataAnalyzer::run() {
95   - this->analyzedDataMutex->lock();
96   -
97   - unsigned int maxSamples = 0;
98   - unsigned int channelCount =
99   - (unsigned int)this->settings->scope.voltage.size();
100   -
101   - // Adapt the number of channels for analyzed data
102   - this->analyzedData.resize(channelCount);
103   -
104   - for (unsigned int channel = 0; channel < channelCount; ++channel) {
105   - AnalyzedData *const channelData = &this->analyzedData[channel];
106   -
107   - if ( // Check...
108   - ( // ...if we got data for this channel...
109   - channel < this->settings->scope.physicalChannels &&
110   - channel < (unsigned int)this->waitingData->size() &&
111   - !this->waitingData->at(channel).empty()) ||
112   - ( // ...or if it's a math channel that can be calculated
113   - channel >= this->settings->scope.physicalChannels &&
114   - (this->settings->scope.voltage[channel].used ||
115   - this->settings->scope.spectrum[channel].used) &&
116   - this->analyzedData.size() >= 2 &&
117   - !this->analyzedData[0].samples.voltage.sample.empty() &&
118   - !this->analyzedData[1].samples.voltage.sample.empty())) {
119   - // Set sampling interval
120   - const double interval = 1.0 / this->waitingDataSamplerate;
121   - if (interval != channelData->samples.voltage.interval) {
122   - channelData->samples.voltage.interval = interval;
123   - if (this->waitingDataAppend) // Clear roll buffer if the samplerate
124   - // changed
125   - channelData->samples.voltage.sample.clear();
126   - }
127   -
128   - unsigned int size;
129   - if (channel < this->settings->scope.physicalChannels) {
130   - size = this->waitingData->at(channel).size();
131   - if (this->waitingDataAppend)
132   - size += channelData->samples.voltage.sample.size();
133   - if (size > maxSamples)
134   - maxSamples = size;
135   - } else
136   - size = maxSamples;
137   -
138   - // Physical channels
139   - if (channel < this->settings->scope.physicalChannels) {
140   - // Copy the buffer of the oscilloscope into the sample buffer
141   - if (this->waitingDataAppend)
142   - channelData->samples.voltage.sample.insert(
143   - channelData->samples.voltage.sample.end(),
144   - this->waitingData->at(channel).begin(),
145   - this->waitingData->at(channel).end());
146   - else
147   - channelData->samples.voltage.sample = this->waitingData->at(channel);
148   - }
149   - // Math channel
150   - else {
151   - // Resize the sample vector
152   - channelData->samples.voltage.sample.resize(size);
  67 +void DataAnalyzer::transferData() {
  68 + QMutexLocker locker(waitingDataMutex);
  69 + QMutexLocker locker2(analyzedDataMutex);
  70 +
  71 + unsigned int maxSamples = 0;
  72 + unsigned int channelCount =
  73 + (unsigned int)scope->voltage.size();
  74 +
  75 + // Adapt the number of channels for analyzed data
  76 + this->analyzedData.resize(channelCount);
  77 +
  78 + for (unsigned int channel = 0; channel < channelCount; ++channel) {
  79 + AnalyzedData *const channelData = &this->analyzedData[channel];
  80 +
  81 + if ( // Check...
  82 + ( // ...if we got data for this channel...
  83 + channel < scope->physicalChannels &&
  84 + channel < (unsigned int)this->waitingData->size() &&
  85 + !this->waitingData->at(channel).empty()) ||
  86 + ( // ...or if it's a math channel that can be calculated
  87 + channel >= scope->physicalChannels &&
  88 + (scope->voltage[channel].used ||
  89 + scope->spectrum[channel].used) &&
  90 + this->analyzedData.size() >= 2 &&
  91 + !this->analyzedData[0].samples.voltage.sample.empty() &&
  92 + !this->analyzedData[1].samples.voltage.sample.empty())) {
153 93 // Set sampling interval
154   - this->analyzedData[this->settings->scope.physicalChannels]
155   - .samples.voltage.interval =
156   - this->analyzedData[0].samples.voltage.interval;
157   -
158   - // Resize the sample vector
159   - this->analyzedData[this->settings->scope.physicalChannels]
160   - .samples.voltage.sample.resize(
161   - qMin(this->analyzedData[0].samples.voltage.sample.size(),
162   - this->analyzedData[1].samples.voltage.sample.size()));
163   -
164   - // Calculate values and write them into the sample buffer
165   - std::vector<double>::const_iterator ch1Iterator =
166   - this->analyzedData[0].samples.voltage.sample.begin();
167   - std::vector<double>::const_iterator ch2Iterator =
168   - this->analyzedData[1].samples.voltage.sample.begin();
169   - std::vector<double> &resultData =
170   - this->analyzedData[this->settings->scope.physicalChannels]
171   - .samples.voltage.sample;
172   - for (std::vector<double>::iterator resultIterator = resultData.begin();
173   - resultIterator != resultData.end(); ++resultIterator) {
174   - switch (this->settings->scope
175   - .voltage[this->settings->scope.physicalChannels]
176   - .misc) {
177   - case Dso::MATHMODE_1ADD2:
178   - *resultIterator = *ch1Iterator + *ch2Iterator;
179   - break;
180   - case Dso::MATHMODE_1SUB2:
181   - *resultIterator = *ch1Iterator - *ch2Iterator;
182   - break;
183   - case Dso::MATHMODE_2SUB1:
184   - *resultIterator = *ch2Iterator - *ch1Iterator;
185   - break;
  94 + const double interval = 1.0 / this->waitingDataSamplerate;
  95 + if (interval != channelData->samples.voltage.interval) {
  96 + channelData->samples.voltage.interval = interval;
  97 + if (this->waitingDataAppend) // Clear roll buffer if the samplerate
  98 + // changed
  99 + channelData->samples.voltage.sample.clear();
  100 + }
  101 +
  102 + unsigned int size;
  103 + if (channel < scope->physicalChannels) {
  104 + size = this->waitingData->at(channel).size();
  105 + if (this->waitingDataAppend)
  106 + size += channelData->samples.voltage.sample.size();
  107 + if (size > maxSamples)
  108 + maxSamples = size;
  109 + } else
  110 + size = maxSamples;
  111 +
  112 + // Physical channels
  113 + if (channel < scope->physicalChannels) {
  114 + // Copy the buffer of the oscilloscope into the sample buffer
  115 + if (this->waitingDataAppend)
  116 + channelData->samples.voltage.sample.insert(
  117 + channelData->samples.voltage.sample.end(),
  118 + this->waitingData->at(channel).begin(),
  119 + this->waitingData->at(channel).end());
  120 + else
  121 + channelData->samples.voltage.sample = this->waitingData->at(channel);
  122 + }
  123 + // Math channel
  124 + else {
  125 + // Resize the sample vector
  126 + channelData->samples.voltage.sample.resize(size);
  127 + // Set sampling interval
  128 + this->analyzedData[scope->physicalChannels]
  129 + .samples.voltage.interval =
  130 + this->analyzedData[0].samples.voltage.interval;
  131 +
  132 + // Resize the sample vector
  133 + this->analyzedData[scope->physicalChannels]
  134 + .samples.voltage.sample.resize(
  135 + qMin(this->analyzedData[0].samples.voltage.sample.size(),
  136 + this->analyzedData[1].samples.voltage.sample.size()));
  137 +
  138 + // Calculate values and write them into the sample buffer
  139 + std::vector<double>::const_iterator ch1Iterator =
  140 + this->analyzedData[0].samples.voltage.sample.begin();
  141 + std::vector<double>::const_iterator ch2Iterator =
  142 + this->analyzedData[1].samples.voltage.sample.begin();
  143 + std::vector<double> &resultData =
  144 + this->analyzedData[scope->physicalChannels]
  145 + .samples.voltage.sample;
  146 + for (std::vector<double>::iterator resultIterator = resultData.begin();
  147 + resultIterator != resultData.end(); ++resultIterator) {
  148 + switch (scope->voltage[scope->physicalChannels].misc) {
  149 + case Dso::MATHMODE_1ADD2:
  150 + *resultIterator = *ch1Iterator + *ch2Iterator;
  151 + break;
  152 + case Dso::MATHMODE_1SUB2:
  153 + *resultIterator = *ch1Iterator - *ch2Iterator;
  154 + break;
  155 + case Dso::MATHMODE_2SUB1:
  156 + *resultIterator = *ch2Iterator - *ch1Iterator;
  157 + break;
  158 + }
  159 + ++ch1Iterator;
  160 + ++ch2Iterator;
186 161 }
187   - ++ch1Iterator;
188   - ++ch2Iterator;
189 162 }
  163 + } else {
  164 + // Clear unused channels
  165 + channelData->samples.voltage.sample.clear();
  166 + this->analyzedData[scope->physicalChannels]
  167 + .samples.voltage.interval = 0;
190 168 }
191   - } else {
192   - // Clear unused channels
193   - channelData->samples.voltage.sample.clear();
194   - this->analyzedData[this->settings->scope.physicalChannels]
195   - .samples.voltage.interval = 0;
196 169 }
197   - }
  170 +}
198 171  
199   - this->waitingDataMutex->unlock();
  172 +/// \brief Analyzes the data from the dso.
  173 +void DataAnalyzer::run(DsoSettingsOptions* options,DsoSettingsScope* scope,DsoSettingsView* view) {
  174 + this->options=options;
  175 + this->scope=scope;
  176 + this->view=view;
  177 +
  178 + transferData();
200 179  
201 180 // Lower priority for spectrum calculation
202 181 this->setPriority(QThread::LowPriority);
203 182  
  183 + QMutexLocker locker(analyzedDataMutex);
  184 +
204 185 // Calculate frequencies, peak-to-peak voltages and spectrums
205 186 for (unsigned int channel = 0; channel < this->analyzedData.size();
206 187 ++channel) {
... ... @@ -209,7 +190,7 @@ void DataAnalyzer::run() {
209 190 if (!channelData->samples.voltage.sample.empty()) {
210 191 // Calculate new window
211 192 unsigned int sampleCount = channelData->samples.voltage.sample.size();
212   - if (this->lastWindow != this->settings->scope.spectrumWindow ||
  193 + if (this->lastWindow != scope->spectrumWindow ||
213 194 this->lastRecordLength != sampleCount) {
214 195 if (this->lastRecordLength != sampleCount) {
215 196 this->lastRecordLength = sampleCount;
... ... @@ -221,9 +202,9 @@ void DataAnalyzer::run() {
221 202 }
222 203  
223 204 unsigned int windowEnd = this->lastRecordLength - 1;
224   - this->lastWindow = this->settings->scope.spectrumWindow;
  205 + this->lastWindow = scope->spectrumWindow;
225 206  
226   - switch (this->settings->scope.spectrumWindow) {
  207 + switch (scope->spectrumWindow) {
227 208 case Dso::WINDOW_HAMMING:
228 209 for (unsigned int windowPosition = 0;
229 210 windowPosition < this->lastRecordLength; ++windowPosition)
... ... @@ -441,12 +422,12 @@ void DataAnalyzer::run() {
441 422 channelData->frequency = 0;
442 423  
443 424 // Finally calculate the real spectrum if we want it
444   - if (this->settings->scope.spectrum[channel].used) {
  425 + if (scope->spectrum[channel].used) {
445 426 // Convert values into dB (Relative to the reference level)
446   - double offset = 60 - this->settings->scope.spectrumReference -
  427 + double offset = 60 - scope->spectrumReference -
447 428 20 * log10(dftLength);
448   - double offsetLimit = this->settings->scope.spectrumLimit -
449   - this->settings->scope.spectrumReference;
  429 + double offsetLimit = scope->spectrumLimit -
  430 + scope->spectrumReference;
450 431 for (std::vector<double>::iterator spectrumIterator =
451 432 channelData->samples.spectrum.sample.begin();
452 433 spectrumIterator != channelData->samples.spectrum.sample.end();
... ... @@ -468,9 +449,7 @@ void DataAnalyzer::run() {
468 449 }
469 450  
470 451 this->maxSamples = maxSamples;
471   - emit(analyzed(maxSamples));
472   -
473   - this->analyzedDataMutex->unlock();
  452 + emit analyzed(maxSamples);
474 453 }
475 454  
476 455 /// \brief Starts the analyzing of new input data.
... ... @@ -485,13 +464,12 @@ void DataAnalyzer::analyze(const std::vector&lt;std::vector&lt;double&gt;&gt; *data,
485 464 // Previous analysis still running, drop the new data
486 465 if (this->isRunning()) {
487 466 #ifdef DEBUG
488   - Helper::timestampDebug("Analyzer overload, dropping packets!");
  467 + timestampDebug("Analyzer overload, dropping packets!");
489 468 #endif
490 469 return;
491 470 }
492 471  
493 472 // The thread will analyze it, just save the pointers
494   - mutex->lock();
495 473 this->waitingData = data;
496 474 this->waitingDataAppend = append;
497 475 this->waitingDataMutex = mutex;
... ... @@ -500,6 +478,6 @@ void DataAnalyzer::analyze(const std::vector&lt;std::vector&lt;double&gt;&gt; *data,
500 478 #ifdef DEBUG
501 479 static unsigned long id = 0;
502 480 ++id;
503   - Helper::timestampDebug(QString("Analyzed packet %1").arg(id));
  481 + timestampDebug(QString("Analyzed packet %1").arg(id));
504 482 #endif
505 483 }
... ...
openhantek/src/dataanalyzer.h
... ... @@ -28,14 +28,15 @@
28 28 #include <vector>
29 29  
30 30 #include <QThread>
  31 +#include <QMutex>
31 32  
32   -#include "dso.h"
33   -#include "helper.h"
  33 +#include "definitions.h"
  34 +#include "utils/printutils.h"
34 35  
35   -class DsoSettings;
  36 +class DsoSettingsOptions;
  37 +class DsoSettingsScope;
  38 +class DsoSettingsView;
36 39 class HantekDSOAThread;
37   -class QMutex;
38   -
39 40 ////////////////////////////////////////////////////////////////////////////////
40 41 /// \struct SampleValues dataanalyzer.h
41 42 /// \brief Struct for a array of sample values.
... ... @@ -74,33 +75,32 @@ class DataAnalyzer : public QThread {
74 75 Q_OBJECT
75 76  
76 77 public:
77   - DataAnalyzer(DsoSettings *settings, QObject *parent = 0);
78   - ~DataAnalyzer();
79   -
80 78 const AnalyzedData *data(unsigned int channel) const;
81 79 unsigned int sampleCount();
  80 + /// \brief Returns the mutex for the data.
  81 + /// \return Mutex for the analyzed data.
82 82 QMutex *mutex() const;
83 83  
84 84 protected:
85   - void run();
  85 + void run(DsoSettingsOptions* options,DsoSettingsScope* scope,DsoSettingsView* view);
  86 + void transferData();
86 87  
87   - DsoSettings *settings; ///< The settings provided by the parent class
  88 + DsoSettingsOptions* options; ///< General options of the program
  89 + DsoSettingsScope* scope; ///< All oscilloscope related settings
  90 + DsoSettingsView* view; ///< All view related settings
88 91  
89   - std::vector<AnalyzedData>
90   - analyzedData; ///< The analyzed data for each channel
91   - QMutex *analyzedDataMutex; ///< A mutex for the analyzed data of all channels
  92 + std::vector<AnalyzedData> analyzedData; ///< The analyzed data for each channel
  93 + QMutex *analyzedDataMutex= new QMutex(); ///< A mutex for the analyzed data of all channels
92 94  
93   - unsigned int
94   - lastRecordLength; ///< The record length of the previously analyzed data
95   - unsigned int maxSamples; ///< The maximum record length of the analyzed data
96   - Dso::WindowFunction lastWindow; ///< The previously used dft window function
97   - double *window; ///< The array for the dft window factors
  95 + unsigned int lastRecordLength=0; ///< The record length of the previously analyzed data
  96 + unsigned int maxSamples=0; ///< The maximum record length of the analyzed data
  97 + Dso::WindowFunction lastWindow=(Dso::WindowFunction)-1; ///< The previously used dft window function
  98 + double *window=nullptr; ///< The array for the dft window factors
98 99  
99   - const std::vector<std::vector<double>>
100   - *waitingData; ///< Pointer to input data from device
101   - double waitingDataSamplerate; ///< The samplerate of the input data
  100 + const std::vector<std::vector<double>> *waitingData; ///< Pointer to input data from device
  101 + double waitingDataSamplerate=0.0; ///< The samplerate of the input data
102 102 bool waitingDataAppend; ///< true, if waiting data should be appended
103   - QMutex *waitingDataMutex; ///< A mutex for the input data
  103 + QMutex *waitingDataMutex=nullptr; ///< A mutex for the input data
104 104  
105 105 public slots:
106 106 void analyze(const std::vector<std::vector<double>> *data, double samplerate,
... ...
openhantek/src/dockwindows.cpp
... ... @@ -31,7 +31,8 @@
31 31  
32 32 #include "dockwindows.h"
33 33  
34   -#include "helper.h"
  34 +#include "utils/printutils.h"
  35 +#include "utils/dsoStrings.h"
35 36 #include "settings.h"
36 37 #include "sispinbox.h"
37 38  
... ... @@ -61,7 +62,7 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent,
61 62  
62 63 // Initialize elements
63 64 this->samplerateLabel = new QLabel(tr("Samplerate"));
64   - this->samplerateSiSpinBox = new SiSpinBox(Helper::UNIT_SAMPLES);
  65 + this->samplerateSiSpinBox = new SiSpinBox(UNIT_SAMPLES);
65 66 this->samplerateSiSpinBox->setMinimum(1);
66 67 this->samplerateSiSpinBox->setMaximum(1e8);
67 68 this->samplerateSiSpinBox->setUnitPostfix("/s");
... ... @@ -69,13 +70,13 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent,
69 70 timebaseSteps << 1.0 << 2.0 << 4.0 << 10.0;
70 71  
71 72 this->timebaseLabel = new QLabel(tr("Timebase"));
72   - this->timebaseSiSpinBox = new SiSpinBox(Helper::UNIT_SECONDS);
  73 + this->timebaseSiSpinBox = new SiSpinBox(UNIT_SECONDS);
73 74 this->timebaseSiSpinBox->setSteps(timebaseSteps);
74 75 this->timebaseSiSpinBox->setMinimum(1e-9);
75 76 this->timebaseSiSpinBox->setMaximum(3.6e3);
76 77  
77 78 this->frequencybaseLabel = new QLabel(tr("Frequencybase"));
78   - this->frequencybaseSiSpinBox = new SiSpinBox(Helper::UNIT_HERTZ);
  79 + this->frequencybaseSiSpinBox = new SiSpinBox(UNIT_HERTZ);
79 80 this->frequencybaseSiSpinBox->setMinimum(1.0);
80 81 this->frequencybaseSiSpinBox->setMaximum(100e6);
81 82  
... ... @@ -215,13 +216,13 @@ void HorizontalDock::availableRecordLengthsChanged(
215 216 this->recordLengthComboBox->setItemText(
216 217 index, recordLengthItem == UINT_MAX
217 218 ? tr("Roll")
218   - : Helper::valueToString(recordLengthItem,
219   - Helper::UNIT_SAMPLES, 3));
  219 + : valueToString(recordLengthItem,
  220 + UNIT_SAMPLES, 3));
220 221 } else {
221 222 this->recordLengthComboBox->addItem(
222 223 recordLengthItem == UINT_MAX
223 224 ? tr("Roll")
224   - : Helper::valueToString(recordLengthItem, Helper::UNIT_SAMPLES,
  225 + : valueToString(recordLengthItem, UNIT_SAMPLES,
225 226 3),
226 227 (uint)recordLengthItem);
227 228 }
... ... @@ -464,8 +465,8 @@ SpectrumDock::SpectrumDock(DsoSettings *settings, QWidget *parent,
464 465 << 6e2; ///< Magnitude steps in dB/div
465 466 for (QList<double>::iterator magnitude = this->magnitudeSteps.begin();
466 467 magnitude != this->magnitudeSteps.end(); ++magnitude)
467   - this->magnitudeStrings << Helper::valueToString(*magnitude,
468   - Helper::UNIT_DECIBEL, 0);
  468 + this->magnitudeStrings << valueToString(*magnitude,
  469 + UNIT_DECIBEL, 0);
469 470  
470 471 // Initialize elements
471 472 for (int channel = 0; channel < this->settings->scope.voltage.count();
... ... @@ -605,7 +606,7 @@ VoltageDock::VoltageDock(DsoSettings *settings, QWidget *parent,
605 606 << 5e0; ///< Voltage steps in V/div
606 607 for (QList<double>::iterator gain = this->gainSteps.begin();
607 608 gain != this->gainSteps.end(); ++gain)
608   - this->gainStrings << Helper::valueToString(*gain, Helper::UNIT_VOLTS, 0);
  609 + this->gainStrings << valueToString(*gain, UNIT_VOLTS, 0);
609 610  
610 611 // Initialize elements
611 612 for (int channel = 0; channel < this->settings->scope.voltage.count();
... ...
openhantek/src/dockwindows.h
... ... @@ -28,7 +28,7 @@
28 28 #include <QDockWidget>
29 29 #include <QGridLayout>
30 30  
31   -#include "dso.h"
  31 +#include "definitions.h"
32 32 #include "settings.h"
33 33  
34 34 class QLabel;
... ...
openhantek/src/dso.h deleted
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file dso.h
5   -/// \brief Defines various constants, enums and functions for DSO settings.
6   -//
7   -// Copyright (C) 2010 Oliver Haag
8   -// oliver.haag@gmail.com
9   -//
10   -// This program is free software: you can redistribute it and/or modify it
11   -// under the terms of the GNU General Public License as published by the Free
12   -// Software Foundation, either version 3 of the License, or (at your option)
13   -// any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful, but WITHOUT
16   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18   -// more details.
19   -//
20   -// You should have received a copy of the GNU General Public License along with
21   -// this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -////////////////////////////////////////////////////////////////////////////////
24   -
25   -#ifndef DSO_H
26   -#define DSO_H
27   -
28   -#include <QString>
29   -
30   -#define MARKER_COUNT 2 ///< Number of markers
31   -
32   -////////////////////////////////////////////////////////////////////////////////
33   -/// \namespace Dso dso.h
34   -/// \brief All DSO specific things for different modes and so on.
35   -namespace Dso {
36   -//////////////////////////////////////////////////////////////////////////////
37   -/// \enum ErrorCode hantek/control.h
38   -/// \brief The return codes for device control methods.
39   -enum ErrorCode {
40   - ERROR_NONE = 0, ///< Successful operation
41   - ERROR_CONNECTION = -1, ///< Device not connected or communication error
42   - ERROR_UNSUPPORTED = -2, ///< Not supported by this device
43   - ERROR_PARAMETER = -3 ///< Parameter out of range
44   -};
45   -
46   -//////////////////////////////////////////////////////////////////////////////
47   -/// \enum ChannelMode dso.h
48   -/// \brief The channel display modes.
49   -enum ChannelMode {
50   - CHANNELMODE_VOLTAGE, ///< Standard voltage view
51   - CHANNELMODE_SPECTRUM, ///< Spectrum view
52   - CHANNELMODE_COUNT ///< The total number of modes
53   -};
54   -
55   -//////////////////////////////////////////////////////////////////////////////
56   -/// \enum GraphFormat dso.h
57   -/// \brief The possible viewing formats for the graphs on the scope.
58   -enum GraphFormat {
59   - GRAPHFORMAT_TY, ///< The standard mode
60   - GRAPHFORMAT_XY, ///< CH1 on X-axis, CH2 on Y-axis
61   - GRAPHFORMAT_COUNT ///< The total number of formats
62   -};
63   -
64   -//////////////////////////////////////////////////////////////////////////////
65   -/// \enum Coupling dso.h
66   -/// \brief The coupling modes for the channels.
67   -enum Coupling {
68   - COUPLING_AC, ///< Offset filtered out by condensator
69   - COUPLING_DC, ///< No filtering
70   - COUPLING_GND, ///< Channel is grounded
71   - COUPLING_COUNT ///< The total number of coupling modes
72   -};
73   -
74   -//////////////////////////////////////////////////////////////////////////////
75   -/// \enum MathMode dso.h
76   -/// \brief The different math modes for the math-channel.
77   -enum MathMode {
78   - MATHMODE_1ADD2, ///< Add the values of the channels
79   - MATHMODE_1SUB2, ///< Subtract CH2 from CH1
80   - MATHMODE_2SUB1, ///< Subtract CH1 from CH2
81   - MATHMODE_COUNT ///< The total number of math modes
82   -};
83   -
84   -//////////////////////////////////////////////////////////////////////////////
85   -/// \enum TriggerMode dso.h
86   -/// \brief The different triggering modes.
87   -enum TriggerMode {
88   - TRIGGERMODE_AUTO, ///< Automatic without trigger event
89   - TRIGGERMODE_NORMAL, ///< Normal mode
90   - TRIGGERMODE_SINGLE, ///< Stop after the first trigger event
91   - TRIGGERMODE_SOFTWARE, ///< Software trigger mode
92   - TRIGGERMODE_COUNT ///< The total number of modes
93   -};
94   -
95   -//////////////////////////////////////////////////////////////////////////////
96   -/// \enum Slope dso.h
97   -/// \brief The slope that causes a trigger.
98   -enum Slope {
99   - SLOPE_POSITIVE, ///< From lower to higher voltage
100   - SLOPE_NEGATIVE, ///< From higher to lower voltage
101   - SLOPE_COUNT ///< Total number of trigger slopes
102   -};
103   -
104   -//////////////////////////////////////////////////////////////////////////////
105   -/// \enum WindowFunction dso.h
106   -/// \brief The supported window functions.
107   -/// These are needed for spectrum analysis and are applied to the sample values
108   -/// before calculating the DFT.
109   -enum WindowFunction {
110   - WINDOW_RECTANGULAR, ///< Rectangular window (aka Dirichlet)
111   - WINDOW_HAMMING, ///< Hamming window
112   - WINDOW_HANN, ///< Hann window
113   - WINDOW_COSINE, ///< Cosine window (aka Sine)
114   - WINDOW_LANCZOS, ///< Lanczos window (aka Sinc)
115   - WINDOW_BARTLETT, ///< Bartlett window (Endpoints == 0)
116   - WINDOW_TRIANGULAR, ///< Triangular window (Endpoints != 0)
117   - WINDOW_GAUSS, ///< Gauss window (simga = 0.4)
118   - WINDOW_BARTLETTHANN, ///< Bartlett-Hann window
119   - WINDOW_BLACKMAN, ///< Blackman window (alpha = 0.16)
120   - // WINDOW_KAISER, ///< Kaiser window (alpha = 3.0)
121   - WINDOW_NUTTALL, ///< Nuttall window, cont. first deriv.
122   - WINDOW_BLACKMANHARRIS, ///< Blackman-Harris window
123   - WINDOW_BLACKMANNUTTALL, ///< Blackman-Nuttall window
124   - WINDOW_FLATTOP, ///< Flat top window
125   - WINDOW_COUNT ///< Total number of window functions
126   -};
127   -
128   -////////////////////////////////////////////////////////////////////////////////
129   -/// \enum InterpolationMode dso.h
130   -/// \brief The different interpolation modes for the graphs.
131   -enum InterpolationMode {
132   - INTERPOLATION_OFF = 0, ///< Just dots for each sample
133   - INTERPOLATION_LINEAR, ///< Sample dots connected by lines
134   - INTERPOLATION_SINC, ///< Smooth graph through the dots
135   - INTERPOLATION_COUNT ///< Total number of interpolation modes
136   -};
137   -
138   -QString channelModeString(ChannelMode mode);
139   -QString graphFormatString(GraphFormat format);
140   -QString couplingString(Coupling coupling);
141   -QString mathModeString(MathMode mode);
142   -QString triggerModeString(TriggerMode mode);
143   -QString slopeString(Slope slope);
144   -QString windowFunctionString(WindowFunction window);
145   -QString interpolationModeString(InterpolationMode interpolation);
146   -}
147   -
148   -#endif
openhantek/src/dsocontrol.cpp deleted
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// dsocontrol.cpp
5   -//
6   -// Copyright (C) 2010 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   -////////////////////////////////////////////////////////////////////////////////
23   -
24   -#include "dsocontrol.h"
25   -
26   -////////////////////////////////////////////////////////////////////////////////
27   -// class DsoControl
28   -/// \brief Initialize variables.
29   -DsoControl::DsoControl(QObject *parent) : QThread(parent) {
30   - this->sampling = false;
31   -}
32   -
33   -/// \brief Start sampling process.
34   -void DsoControl::startSampling() {
35   - this->sampling = true;
36   - emit samplingStarted();
37   -}
38   -
39   -/// \brief Stop sampling process.
40   -void DsoControl::stopSampling() {
41   - this->sampling = false;
42   - emit samplingStopped();
43   -}
44   -
45   -/// \brief Get a list of the names of the special trigger sources.
46   -const QStringList *DsoControl::getSpecialTriggerSources() {
47   - return &(this->specialTriggerSources);
48   -}
49   -
50   -/// \brief Try to connect to the oscilloscope.
51   -void DsoControl::connectDevice() {
52   - this->sampling = false;
53   - this->start();
54   -}
55   -
56   -/// \brief Disconnect the oscilloscope.
57   -void DsoControl::disconnectDevice() { this->quit(); }
openhantek/src/dsocontrol.h deleted
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file dsocontrol.h
5   -/// \brief Declares the abstract Control class.
6   -//
7   -// Copyright (C) 2010 Oliver Haag
8   -// oliver.haag@gmail.com
9   -//
10   -// This program is free software: you can redistribute it and/or modify it
11   -// under the terms of the GNU General Public License as published by the Free
12   -// Software Foundation, either version 3 of the License, or (at your option)
13   -// any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful, but WITHOUT
16   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18   -// more details.
19   -//
20   -// You should have received a copy of the GNU General Public License along with
21   -// this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -////////////////////////////////////////////////////////////////////////////////
24   -
25   -#ifndef DSOCONTROL_H
26   -#define DSOCONTROL_H
27   -
28   -#include <vector>
29   -
30   -#include <QStringList>
31   -#include <QThread>
32   -
33   -#include "dso.h"
34   -#include "helper.h"
35   -
36   -class QMutex;
37   -
38   -/// \class DsoControl
39   -/// \brief A abstraction layer that enables protocol-independent dso usage.
40   -class DsoControl : public QThread {
41   - Q_OBJECT
42   -
43   -public:
44   - DsoControl(QObject *parent = 0);
45   -
46   - virtual unsigned int
47   - getChannelCount() = 0; ///< Get the number of channels for this oscilloscope
48   - virtual QList<unsigned int> *
49   - getAvailableRecordLengths() = 0; ///< Get available record lengths, empty list
50   - ///for continuous
51   - virtual double getMinSamplerate() = 0; ///< The minimum samplerate supported
52   - virtual double getMaxSamplerate() = 0; ///< The maximum samplerate supported
53   -
54   - const QStringList *getSpecialTriggerSources();
55   -
56   -protected:
57   - bool sampling; ///< true, if the oscilloscope is taking samples
58   -
59   - QStringList specialTriggerSources; ///< Names of the special trigger sources
60   -
61   -signals:
62   - void deviceConnected(); ///< The oscilloscope device has been disconnected
63   - void deviceDisconnected(); ///< The oscilloscope device has been connected
64   - void
65   - samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger
66   - void
67   - samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger
68   - void statusMessage(const QString &message,
69   - int timeout); ///< Status message about the oscilloscope
70   - void samplesAvailable(const std::vector<std::vector<double>> *data,
71   - double samplerate, bool append,
72   - QMutex *mutex); ///< New sample data is available
73   -
74   - void availableRecordLengthsChanged(
75   - const QList<unsigned int> &recordLengths); ///< The available record
76   - ///lengths, empty list for
77   - ///continuous
78   - void samplerateLimitsChanged(
79   - double minimum,
80   - double maximum); ///< The minimum or maximum samplerate has changed
81   - void recordLengthChanged(
82   - unsigned long duration); ///< The record length has changed
83   - void
84   - recordTimeChanged(double duration); ///< The record time duration has changed
85   - void samplerateChanged(double samplerate); ///< The samplerate has changed
86   - void samplerateSet(int mode,
87   - QList<double> sampleSteps); ///< The samplerate has changed
88   -
89   -public slots:
90   - virtual void connectDevice();
91   - virtual void disconnectDevice();
92   -
93   - virtual void startSampling();
94   - virtual void stopSampling();
95   -
96   - virtual unsigned int setRecordLength(
97   - unsigned int size) = 0; ///< Set record length id, minimum for continuous
98   - virtual double setSamplerate(
99   - double samplerate) = 0; ///< Set the samplerate that should be met
100   - virtual double setRecordTime(
101   - double duration) = 0; ///< Set the record time duration that should be met
102   -
103   - virtual int
104   - setTriggerMode(Dso::TriggerMode mode) = 0; ///< Set the trigger mode
105   - virtual int setTriggerSource(bool special,
106   - unsigned int id) = 0; ///< Set the trigger source
107   - virtual double
108   - setTriggerLevel(unsigned int channel,
109   - double level) = 0; ///< Set the trigger level for a channel
110   - virtual int setTriggerSlope(
111   - Dso::Slope slope) = 0; ///< Set the slope that causes triggering
112   - virtual double setPretriggerPosition(double position) = 0; ///< Set the
113   - ///pretrigger
114   - ///position (0.0 =
115   - ///left, 1.0 =
116   - ///right side)
117   - virtual int forceTrigger() = 0;
118   -
119   - virtual int setChannelUsed(unsigned int channel,
120   - bool used) = 0; ///< Enable/disable a channel
121   - virtual int
122   - setCoupling(unsigned int channel,
123   - Dso::Coupling coupling) = 0; ///< Set the coupling for a channel
124   - virtual double setGain(unsigned int channel,
125   - double gain) = 0; ///< Set the gain for a channel
126   - virtual double
127   - setOffset(unsigned int channel,
128   - double offset) = 0; ///< Set the graph offset of a channel
129   -
130   -#ifdef DEBUG
131   - virtual int stringCommand(
132   - QString command) = 0; ///< Sends commands directly, for debugging
133   -#endif
134   -};
135   -
136   -#endif
openhantek/src/dsowidget.cpp
... ... @@ -30,11 +30,12 @@
30 30  
31 31 #include "dsowidget.h"
32 32  
  33 +#include "hantek/definitions.h"
  34 +#include "utils/printutils.h"
  35 +#include "utils/dsoStrings.h"
33 36 #include "dataanalyzer.h"
34   -#include "dso.h"
35 37 #include "exporter.h"
36 38 #include "glscope.h"
37   -#include "helper.h"
38 39 #include "levelslider.h"
39 40 #include "settings.h"
40 41  
... ... @@ -351,18 +352,18 @@ void DsoWidget::updateMarkerDetails() {
351 352 this->markerInfoLabel->setText(
352 353 tr("Zoom x%L1").arg(DIVS_TIME / divs, -1, 'g', 3));
353 354 this->markerTimebaseLabel->setText(
354   - Helper::valueToString(time / DIVS_TIME, Helper::UNIT_SECONDS, 3) +
  355 + valueToString(time / DIVS_TIME, UNIT_SECONDS, 3) +
355 356 tr("/div"));
356 357 this->markerFrequencybaseLabel->setText(
357   - Helper::valueToString(
  358 + valueToString(
358 359 divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME,
359   - Helper::UNIT_HERTZ, 4) +
  360 + UNIT_HERTZ, 4) +
360 361 tr("/div"));
361 362 }
362 363 this->markerTimeLabel->setText(
363   - Helper::valueToString(time, Helper::UNIT_SECONDS, 4));
  364 + valueToString(time, UNIT_SECONDS, 4));
364 365 this->markerFrequencyLabel->setText(
365   - Helper::valueToString(1.0 / time, Helper::UNIT_HERTZ, 4));
  366 + valueToString(1.0 / time, UNIT_HERTZ, 4));
366 367 }
367 368  
368 369 /// \brief Update the label about the trigger settings
... ... @@ -373,8 +374,8 @@ void DsoWidget::updateSpectrumDetails(unsigned int channel) {
373 374  
374 375 if (this->settings->scope.spectrum[channel].used)
375 376 this->measurementMagnitudeLabel[channel]->setText(
376   - Helper::valueToString(this->settings->scope.spectrum[channel].magnitude,
377   - Helper::UNIT_DECIBEL, 3) +
  377 + valueToString(this->settings->scope.spectrum[channel].magnitude,
  378 + UNIT_DECIBEL, 3) +
378 379 tr("/div"));
379 380 else
380 381 this->measurementMagnitudeLabel[channel]->setText(QString());
... ... @@ -388,10 +389,10 @@ void DsoWidget::updateTriggerDetails() {
388 389 this->settings->view.color.screen
389 390 .voltage[this->settings->scope.trigger.source]);
390 391 this->settingsTriggerLabel->setPalette(tablePalette);
391   - QString levelString = Helper::valueToString(
  392 + QString levelString = valueToString(
392 393 this->settings->scope.voltage[this->settings->scope.trigger.source]
393 394 .trigger,
394   - Helper::UNIT_VOLTS, 3);
  395 + UNIT_VOLTS, 3);
395 396 QString pretriggerString =
396 397 tr("%L1%").arg((int)(this->settings->scope.trigger.position * 100 + 0.5));
397 398 this->settingsTriggerLabel->setText(
... ... @@ -416,8 +417,8 @@ void DsoWidget::updateVoltageDetails(unsigned int channel) {
416 417  
417 418 if (this->settings->scope.voltage[channel].used)
418 419 this->measurementGainLabel[channel]->setText(
419   - Helper::valueToString(this->settings->scope.voltage[channel].gain,
420   - Helper::UNIT_VOLTS, 3) +
  420 + valueToString(this->settings->scope.voltage[channel].gain,
  421 + UNIT_VOLTS, 3) +
421 422 tr("/div"));
422 423 else
423 424 this->measurementGainLabel[channel]->setText(QString());
... ... @@ -427,21 +428,21 @@ void DsoWidget::updateVoltageDetails(unsigned int channel) {
427 428 /// \param frequencybase The frequencybase used for displaying the trace.
428 429 void DsoWidget::updateFrequencybase(double frequencybase) {
429 430 this->settingsFrequencybaseLabel->setText(
430   - Helper::valueToString(frequencybase, Helper::UNIT_HERTZ, 4) + tr("/div"));
  431 + valueToString(frequencybase, UNIT_HERTZ, 4) + tr("/div"));
431 432 }
432 433  
433 434 /// \brief Updates the samplerate field after changing the samplerate.
434 435 /// \param samplerate The samplerate set in the oscilloscope.
435 436 void DsoWidget::updateSamplerate(double samplerate) {
436 437 this->settingsSamplerateLabel->setText(
437   - Helper::valueToString(samplerate, Helper::UNIT_SAMPLES, 4) + tr("/s"));
  438 + valueToString(samplerate, UNIT_SAMPLES, 4) + tr("/s"));
438 439 }
439 440  
440 441 /// \brief Handles timebaseChanged signal from the horizontal dock.
441 442 /// \param timebase The timebase used for displaying the trace.
442 443 void DsoWidget::updateTimebase(double timebase) {
443 444 this->settingsTimebaseLabel->setText(
444   - Helper::valueToString(timebase, Helper::UNIT_SECONDS, 4) + tr("/div"));
  445 + valueToString(timebase, UNIT_SECONDS, 4) + tr("/div"));
445 446  
446 447 this->updateMarkerDetails();
447 448 }
... ... @@ -544,7 +545,7 @@ void DsoWidget::updateVoltageUsed(unsigned int channel, bool used) {
544 545 /// \brief Change the record length.
545 546 void DsoWidget::updateRecordLength(unsigned long size) {
546 547 this->settingsRecordLengthLabel->setText(
547   - Helper::valueToString(size, Helper::UNIT_SAMPLES, 4));
  548 + valueToString(size, UNIT_SAMPLES, 4));
548 549 }
549 550  
550 551 /// \brief Export the oscilloscope screen to a file.
... ... @@ -606,11 +607,11 @@ void DsoWidget::dataAnalyzed() {
606 607 if (this->settings->scope.voltage[channel].used &&
607 608 this->dataAnalyzer->data(channel)) {
608 609 // Amplitude string representation (4 significant digits)
609   - this->measurementAmplitudeLabel[channel]->setText(Helper::valueToString(
610   - this->dataAnalyzer->data(channel)->amplitude, Helper::UNIT_VOLTS, 4));
  610 + this->measurementAmplitudeLabel[channel]->setText(valueToString(
  611 + this->dataAnalyzer->data(channel)->amplitude, UNIT_VOLTS, 4));
611 612 // Frequency string representation (5 significant digits)
612   - this->measurementFrequencyLabel[channel]->setText(Helper::valueToString(
613   - this->dataAnalyzer->data(channel)->frequency, Helper::UNIT_HERTZ, 5));
  613 + this->measurementFrequencyLabel[channel]->setText(valueToString(
  614 + this->dataAnalyzer->data(channel)->frequency, UNIT_HERTZ, 5));
614 615 }
615 616 }
616 617 }
... ...
openhantek/src/exporter.cpp
... ... @@ -36,9 +36,10 @@
36 36 #include "exporter.h"
37 37  
38 38 #include "dataanalyzer.h"
39   -#include "dso.h"
  39 +#include "definitions.h"
40 40 #include "glgenerator.h"
41   -#include "helper.h"
  41 +#include "utils/printutils.h"
  42 +#include "utils/dsoStrings.h"
42 43 #include "settings.h"
43 44  
44 45 ////////////////////////////////////////////////////////////////////////////////
... ... @@ -123,17 +124,15 @@ bool Exporter::doExport() {
123 124  
124 125 painter.setBrush(Qt::SolidPattern);
125 126  
126   - this->dataAnalyzer->mutex()->lock();
127   -
128 127 // Draw the settings table
129 128 double stretchBase = (double)(paintDevice->width() - lineHeight * 10) / 4;
130 129  
131 130 // Print trigger details
132 131 painter.setPen(colorValues->voltage[this->settings->scope.trigger.source]);
133   - QString levelString = Helper::valueToString(
  132 + QString levelString = valueToString(
134 133 this->settings->scope.voltage[this->settings->scope.trigger.source]
135 134 .trigger,
136   - Helper::UNIT_VOLTS, 3);
  135 + UNIT_VOLTS, 3);
137 136 QString pretriggerString = tr("%L1%").arg(
138 137 (int)(this->settings->scope.trigger.position * 100 + 0.5));
139 138 painter.drawText(
... ... @@ -145,285 +144,288 @@ bool Exporter::doExport() {
145 144 Dso::slopeString(this->settings->scope.trigger.slope),
146 145 levelString, pretriggerString));
147 146  
148   - // Print sample count
149   - painter.setPen(colorValues->text);
150   - painter.drawText(QRectF(lineHeight * 10, 0, stretchBase, lineHeight),
151   - tr("%1 S").arg(this->dataAnalyzer->sampleCount()),
152   - QTextOption(Qt::AlignRight));
153   - // Print samplerate
154   - painter.drawText(
155   - QRectF(lineHeight * 10 + stretchBase, 0, stretchBase, lineHeight),
156   - Helper::valueToString(this->settings->scope.horizontal.samplerate,
157   - Helper::UNIT_SAMPLES) +
158   - tr("/s"),
159   - QTextOption(Qt::AlignRight));
160   - // Print timebase
161   - painter.drawText(
162   - QRectF(lineHeight * 10 + stretchBase * 2, 0, stretchBase, lineHeight),
163   - Helper::valueToString(this->settings->scope.horizontal.timebase,
164   - Helper::UNIT_SECONDS, 0) +
165   - tr("/div"),
166   - QTextOption(Qt::AlignRight));
167   - // Print frequencybase
168   - painter.drawText(
169   - QRectF(lineHeight * 10 + stretchBase * 3, 0, stretchBase, lineHeight),
170   - Helper::valueToString(this->settings->scope.horizontal.frequencybase,
171   - Helper::UNIT_HERTZ, 0) +
172   - tr("/div"),
173   - QTextOption(Qt::AlignRight));
174   -
175   - // Draw the measurement table
176   - stretchBase = (double)(paintDevice->width() - lineHeight * 6) / 10;
177   - int channelCount = 0;
178   - for (int channel = this->settings->scope.voltage.count() - 1; channel >= 0;
179   - channel--) {
180   - if ((this->settings->scope.voltage[channel].used ||
181   - this->settings->scope.spectrum[channel].used) &&
182   - this->dataAnalyzer->data(channel)) {
183   - ++channelCount;
184   - double top = (double)paintDevice->height() - channelCount * lineHeight;
185   -
186   - // Print label
187   - painter.setPen(colorValues->voltage[channel]);
188   - painter.drawText(QRectF(0, top, lineHeight * 4, lineHeight),
189   - this->settings->scope.voltage[channel].name);
190   - // Print coupling/math mode
191   - if ((unsigned int)channel < this->settings->scope.physicalChannels)
192   - painter.drawText(
193   - QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight),
194   - Dso::couplingString(
195   - (Dso::Coupling)this->settings->scope.voltage[channel].misc));
196   - else
197   - painter.drawText(
198   - QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight),
199   - Dso::mathModeString(
200   - (Dso::MathMode)this->settings->scope.voltage[channel].misc));
  147 + double scopeHeight;
201 148  
202   - // Print voltage gain
203   - painter.drawText(
204   - QRectF(lineHeight * 6, top, stretchBase * 2, lineHeight),
205   - Helper::valueToString(this->settings->scope.voltage[channel].gain,
206   - Helper::UNIT_VOLTS, 0) +
207   - tr("/div"),
208   - QTextOption(Qt::AlignRight));
209   - // Print spectrum magnitude
210   - if (this->settings->scope.spectrum[channel].used) {
211   - painter.setPen(colorValues->spectrum[channel]);
212   - painter.drawText(QRectF(lineHeight * 6 + stretchBase * 2, top,
213   - stretchBase * 2, lineHeight),
214   - Helper::valueToString(
215   - this->settings->scope.spectrum[channel].magnitude,
216   - Helper::UNIT_DECIBEL, 0) +
217   - tr("/div"),
218   - QTextOption(Qt::AlignRight));
219   - }
  149 + { // DataAnalyser mutex lock
  150 + QMutexLocker locker(this->dataAnalyzer->mutex());
220 151  
221   - // Amplitude string representation (4 significant digits)
  152 + // Print sample count
222 153 painter.setPen(colorValues->text);
  154 + painter.drawText(QRectF(lineHeight * 10, 0, stretchBase, lineHeight),
  155 + tr("%1 S").arg(this->dataAnalyzer->sampleCount()),
  156 + QTextOption(Qt::AlignRight));
  157 + // Print samplerate
223 158 painter.drawText(
224   - QRectF(lineHeight * 6 + stretchBase * 4, top, stretchBase * 3,
225   - lineHeight),
226   - Helper::valueToString(this->dataAnalyzer->data(channel)->amplitude,
227   - Helper::UNIT_VOLTS, 4),
  159 + QRectF(lineHeight * 10 + stretchBase, 0, stretchBase, lineHeight),
  160 + valueToString(this->settings->scope.horizontal.samplerate,
  161 + UNIT_SAMPLES) +
  162 + tr("/s"),
228 163 QTextOption(Qt::AlignRight));
229   - // Frequency string representation (5 significant digits)
  164 + // Print timebase
230 165 painter.drawText(
231   - QRectF(lineHeight * 6 + stretchBase * 7, top, stretchBase * 3,
232   - lineHeight),
233   - Helper::valueToString(this->dataAnalyzer->data(channel)->frequency,
234   - Helper::UNIT_HERTZ, 5),
  166 + QRectF(lineHeight * 10 + stretchBase * 2, 0, stretchBase, lineHeight),
  167 + valueToString(this->settings->scope.horizontal.timebase,
  168 + UNIT_SECONDS, 0) +
  169 + tr("/div"),
  170 + QTextOption(Qt::AlignRight));
  171 + // Print frequencybase
  172 + painter.drawText(
  173 + QRectF(lineHeight * 10 + stretchBase * 3, 0, stretchBase, lineHeight),
  174 + valueToString(this->settings->scope.horizontal.frequencybase,
  175 + UNIT_HERTZ, 0) +
  176 + tr("/div"),
235 177 QTextOption(Qt::AlignRight));
236   - }
237   - }
238   -
239   - // Draw the marker table
240   - double scopeHeight;
241   - stretchBase = (double)(paintDevice->width() - lineHeight * 10) / 4;
242   - painter.setPen(colorValues->text);
243   -
244   - // Calculate variables needed for zoomed scope
245   - double divs = fabs(this->settings->scope.horizontal.marker[1] -
246   - this->settings->scope.horizontal.marker[0]);
247   - double time = divs * this->settings->scope.horizontal.timebase;
248   - double zoomFactor = DIVS_TIME / divs;
249   - double zoomOffset = (this->settings->scope.horizontal.marker[0] +
250   - this->settings->scope.horizontal.marker[1]) /
251   - 2;
252   -
253   - if (this->settings->view.zoom) {
254   - scopeHeight =
255   - (double)(paintDevice->height() - (channelCount + 5) * lineHeight) / 2;
256   - double top = 2.5 * lineHeight + scopeHeight;
257   -
258   - painter.drawText(QRectF(0, top, stretchBase, lineHeight),
259   - tr("Zoom x%L1").arg(DIVS_TIME / divs, -1, 'g', 3));
260   -
261   - painter.drawText(QRectF(lineHeight * 10, top, stretchBase, lineHeight),
262   - Helper::valueToString(time, Helper::UNIT_SECONDS, 4),
263   - QTextOption(Qt::AlignRight));
264   - painter.drawText(
265   - QRectF(lineHeight * 10 + stretchBase, top, stretchBase, lineHeight),
266   - Helper::valueToString(1.0 / time, Helper::UNIT_HERTZ, 4),
267   - QTextOption(Qt::AlignRight));
268   -
269   - painter.drawText(
270   - QRectF(lineHeight * 10 + stretchBase * 2, top, stretchBase,
271   - lineHeight),
272   - Helper::valueToString(time / DIVS_TIME, Helper::UNIT_SECONDS, 3) +
273   - tr("/div"),
274   - QTextOption(Qt::AlignRight));
275   - painter.drawText(
276   - QRectF(lineHeight * 10 + stretchBase * 3, top, stretchBase,
277   - lineHeight),
278   - Helper::valueToString(
279   - divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME,
280   - Helper::UNIT_HERTZ, 3) +
281   - tr("/div"),
282   - QTextOption(Qt::AlignRight));
283   - } else {
284   - scopeHeight =
285   - (double)paintDevice->height() - (channelCount + 4) * lineHeight;
286   - double top = 2.5 * lineHeight + scopeHeight;
287   -
288   - painter.drawText(QRectF(0, top, stretchBase, lineHeight),
289   - tr("Marker 1/2"));
290   -
291   - painter.drawText(
292   - QRectF(lineHeight * 10, top, stretchBase * 2, lineHeight),
293   - Helper::valueToString(time, Helper::UNIT_SECONDS, 4),
294   - QTextOption(Qt::AlignRight));
295   - painter.drawText(QRectF(lineHeight * 10 + stretchBase * 2, top,
296   - stretchBase * 2, lineHeight),
297   - Helper::valueToString(1.0 / time, Helper::UNIT_HERTZ, 4),
298   - QTextOption(Qt::AlignRight));
299   - }
300   -
301   - // Set DIVS_TIME x DIVS_VOLTAGE matrix for oscillograph
302   - painter.setMatrix(QMatrix((paintDevice->width() - 1) / DIVS_TIME, 0, 0,
303   - -(scopeHeight - 1) / DIVS_VOLTAGE,
304   - (double)(paintDevice->width() - 1) / 2,
305   - (scopeHeight - 1) / 2 + lineHeight * 1.5),
306   - false);
307   -
308   - // Draw the graphs
309   - painter.setRenderHint(QPainter::Antialiasing);
310   - painter.setBrush(Qt::NoBrush);
311 178  
312   - for (int zoomed = 0; zoomed < (this->settings->view.zoom ? 2 : 1);
313   - ++zoomed) {
314   - switch (this->settings->scope.horizontal.format) {
315   - case Dso::GRAPHFORMAT_TY:
316   - // Add graphs for channels
317   - for (int channel = 0; channel < this->settings->scope.voltage.count();
318   - ++channel) {
319   - if (this->settings->scope.voltage[channel].used &&
  179 + // Draw the measurement table
  180 + stretchBase = (double)(paintDevice->width() - lineHeight * 6) / 10;
  181 + int channelCount = 0;
  182 + for (int channel = this->settings->scope.voltage.count() - 1; channel >= 0;
  183 + channel--) {
  184 + if ((this->settings->scope.voltage[channel].used ||
  185 + this->settings->scope.spectrum[channel].used) &&
320 186 this->dataAnalyzer->data(channel)) {
321   - painter.setPen(QPen(colorValues->voltage[channel], 0));
322   -
323   - // What's the horizontal distance between sampling points?
324   - double horizontalFactor =
325   - this->dataAnalyzer->data(channel)->samples.voltage.interval /
326   - this->settings->scope.horizontal.timebase;
327   - // How many samples are visible?
328   - double centerPosition, centerOffset;
329   - if (zoomed) {
330   - centerPosition = (zoomOffset + DIVS_TIME / 2) / horizontalFactor;
331   - centerOffset = DIVS_TIME / horizontalFactor / zoomFactor / 2;
332   - } else {
333   - centerPosition = DIVS_TIME / 2 / horizontalFactor;
334   - centerOffset = DIVS_TIME / horizontalFactor / 2;
  187 + ++channelCount;
  188 + double top = (double)paintDevice->height() - channelCount * lineHeight;
  189 +
  190 + // Print label
  191 + painter.setPen(colorValues->voltage[channel]);
  192 + painter.drawText(QRectF(0, top, lineHeight * 4, lineHeight),
  193 + this->settings->scope.voltage[channel].name);
  194 + // Print coupling/math mode
  195 + if ((unsigned int)channel < this->settings->scope.physicalChannels)
  196 + painter.drawText(
  197 + QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight),
  198 + Dso::couplingString(
  199 + (Dso::Coupling)this->settings->scope.voltage[channel].misc));
  200 + else
  201 + painter.drawText(
  202 + QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight),
  203 + Dso::mathModeString(
  204 + (Dso::MathMode)this->settings->scope.voltage[channel].misc));
  205 +
  206 + // Print voltage gain
  207 + painter.drawText(
  208 + QRectF(lineHeight * 6, top, stretchBase * 2, lineHeight),
  209 + valueToString(this->settings->scope.voltage[channel].gain,
  210 + UNIT_VOLTS, 0) +
  211 + tr("/div"),
  212 + QTextOption(Qt::AlignRight));
  213 + // Print spectrum magnitude
  214 + if (this->settings->scope.spectrum[channel].used) {
  215 + painter.setPen(colorValues->spectrum[channel]);
  216 + painter.drawText(QRectF(lineHeight * 6 + stretchBase * 2, top,
  217 + stretchBase * 2, lineHeight),
  218 + valueToString(
  219 + this->settings->scope.spectrum[channel].magnitude,
  220 + UNIT_DECIBEL, 0) +
  221 + tr("/div"),
  222 + QTextOption(Qt::AlignRight));
335 223 }
336   - unsigned int firstPosition =
337   - qMax((int)(centerPosition - centerOffset), 0);
338   - unsigned int lastPosition =
339   - qMin((int)(centerPosition + centerOffset),
340   - (int)this->dataAnalyzer->data(channel)
341   - ->samples.voltage.sample.size() -
342   - 1);
343   -
344   - // Draw graph
345   - QPointF *graph = new QPointF[lastPosition - firstPosition + 1];
346   -
347   - for (unsigned int position = firstPosition;
348   - position <= lastPosition; ++position)
349   - graph[position - firstPosition] =
350   - QPointF(position * horizontalFactor - DIVS_TIME / 2,
351   - this->dataAnalyzer->data(channel)
352   - ->samples.voltage.sample[position] /
353   - this->settings->scope.voltage[channel].gain +
354   - this->settings->scope.voltage[channel].offset);
355   -
356   - painter.drawPolyline(graph, lastPosition - firstPosition + 1);
357   - delete[] graph;
  224 +
  225 + // Amplitude string representation (4 significant digits)
  226 + painter.setPen(colorValues->text);
  227 + painter.drawText(
  228 + QRectF(lineHeight * 6 + stretchBase * 4, top, stretchBase * 3,
  229 + lineHeight),
  230 + valueToString(this->dataAnalyzer->data(channel)->amplitude,
  231 + UNIT_VOLTS, 4),
  232 + QTextOption(Qt::AlignRight));
  233 + // Frequency string representation (5 significant digits)
  234 + painter.drawText(
  235 + QRectF(lineHeight * 6 + stretchBase * 7, top, stretchBase * 3,
  236 + lineHeight),
  237 + valueToString(this->dataAnalyzer->data(channel)->frequency,
  238 + UNIT_HERTZ, 5),
  239 + QTextOption(Qt::AlignRight));
358 240 }
359 241 }
360 242  
361   - // Add spectrum graphs
362   - for (int channel = 0; channel < this->settings->scope.spectrum.count();
363   - ++channel) {
364   - if (this->settings->scope.spectrum[channel].used &&
365   - this->dataAnalyzer->data(channel)) {
366   - painter.setPen(QPen(colorValues->spectrum[channel], 0));
367   -
368   - // What's the horizontal distance between sampling points?
369   - double horizontalFactor =
370   - this->dataAnalyzer->data(channel)->samples.spectrum.interval /
371   - this->settings->scope.horizontal.frequencybase;
372   - // How many samples are visible?
373   - double centerPosition, centerOffset;
374   - if (zoomed) {
375   - centerPosition = (zoomOffset + DIVS_TIME / 2) / horizontalFactor;
376   - centerOffset = DIVS_TIME / horizontalFactor / zoomFactor / 2;
377   - } else {
378   - centerPosition = DIVS_TIME / 2 / horizontalFactor;
379   - centerOffset = DIVS_TIME / horizontalFactor / 2;
380   - }
381   - unsigned int firstPosition =
382   - qMax((int)(centerPosition - centerOffset), 0);
383   - unsigned int lastPosition =
384   - qMin((int)(centerPosition + centerOffset),
385   - (int)this->dataAnalyzer->data(channel)
386   - ->samples.spectrum.sample.size() -
387   - 1);
388   -
389   - // Draw graph
390   - QPointF *graph = new QPointF[lastPosition - firstPosition + 1];
391   -
392   - for (unsigned int position = firstPosition;
393   - position <= lastPosition; ++position)
394   - graph[position - firstPosition] = QPointF(
395   - position * horizontalFactor - DIVS_TIME / 2,
396   - this->dataAnalyzer->data(channel)
397   - ->samples.spectrum.sample[position] /
398   - this->settings->scope.spectrum[channel].magnitude +
399   - this->settings->scope.spectrum[channel].offset);
400   -
401   - painter.drawPolyline(graph, lastPosition - firstPosition + 1);
402   - delete[] graph;
403   - }
  243 + // Draw the marker table
  244 + stretchBase = (double)(paintDevice->width() - lineHeight * 10) / 4;
  245 + painter.setPen(colorValues->text);
  246 +
  247 + // Calculate variables needed for zoomed scope
  248 + double divs = fabs(this->settings->scope.horizontal.marker[1] -
  249 + this->settings->scope.horizontal.marker[0]);
  250 + double time = divs * this->settings->scope.horizontal.timebase;
  251 + double zoomFactor = DIVS_TIME / divs;
  252 + double zoomOffset = (this->settings->scope.horizontal.marker[0] +
  253 + this->settings->scope.horizontal.marker[1]) /
  254 + 2;
  255 +
  256 + if (this->settings->view.zoom) {
  257 + scopeHeight =
  258 + (double)(paintDevice->height() - (channelCount + 5) * lineHeight) / 2;
  259 + double top = 2.5 * lineHeight + scopeHeight;
  260 +
  261 + painter.drawText(QRectF(0, top, stretchBase, lineHeight),
  262 + tr("Zoom x%L1").arg(DIVS_TIME / divs, -1, 'g', 3));
  263 +
  264 + painter.drawText(QRectF(lineHeight * 10, top, stretchBase, lineHeight),
  265 + valueToString(time, UNIT_SECONDS, 4),
  266 + QTextOption(Qt::AlignRight));
  267 + painter.drawText(
  268 + QRectF(lineHeight * 10 + stretchBase, top, stretchBase, lineHeight),
  269 + valueToString(1.0 / time, UNIT_HERTZ, 4),
  270 + QTextOption(Qt::AlignRight));
  271 +
  272 + painter.drawText(
  273 + QRectF(lineHeight * 10 + stretchBase * 2, top, stretchBase,
  274 + lineHeight),
  275 + valueToString(time / DIVS_TIME, UNIT_SECONDS, 3) +
  276 + tr("/div"),
  277 + QTextOption(Qt::AlignRight));
  278 + painter.drawText(
  279 + QRectF(lineHeight * 10 + stretchBase * 3, top, stretchBase,
  280 + lineHeight),
  281 + valueToString(
  282 + divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME,
  283 + UNIT_HERTZ, 3) +
  284 + tr("/div"),
  285 + QTextOption(Qt::AlignRight));
  286 + } else {
  287 + scopeHeight =
  288 + (double)paintDevice->height() - (channelCount + 4) * lineHeight;
  289 + double top = 2.5 * lineHeight + scopeHeight;
  290 +
  291 + painter.drawText(QRectF(0, top, stretchBase, lineHeight),
  292 + tr("Marker 1/2"));
  293 +
  294 + painter.drawText(
  295 + QRectF(lineHeight * 10, top, stretchBase * 2, lineHeight),
  296 + valueToString(time, UNIT_SECONDS, 4),
  297 + QTextOption(Qt::AlignRight));
  298 + painter.drawText(QRectF(lineHeight * 10 + stretchBase * 2, top,
  299 + stretchBase * 2, lineHeight),
  300 + valueToString(1.0 / time, UNIT_HERTZ, 4),
  301 + QTextOption(Qt::AlignRight));
404 302 }
405   - break;
406 303  
407   - case Dso::GRAPHFORMAT_XY:
408   - break;
  304 + // Set DIVS_TIME x DIVS_VOLTAGE matrix for oscillograph
  305 + painter.setMatrix(QMatrix((paintDevice->width() - 1) / DIVS_TIME, 0, 0,
  306 + -(scopeHeight - 1) / DIVS_VOLTAGE,
  307 + (double)(paintDevice->width() - 1) / 2,
  308 + (scopeHeight - 1) / 2 + lineHeight * 1.5),
  309 + false);
  310 +
  311 + // Draw the graphs
  312 + painter.setRenderHint(QPainter::Antialiasing);
  313 + painter.setBrush(Qt::NoBrush);
  314 +
  315 + for (int zoomed = 0; zoomed < (this->settings->view.zoom ? 2 : 1);
  316 + ++zoomed) {
  317 + switch (this->settings->scope.horizontal.format) {
  318 + case Dso::GRAPHFORMAT_TY:
  319 + // Add graphs for channels
  320 + for (int channel = 0; channel < this->settings->scope.voltage.count();
  321 + ++channel) {
  322 + if (this->settings->scope.voltage[channel].used &&
  323 + this->dataAnalyzer->data(channel)) {
  324 + painter.setPen(QPen(colorValues->voltage[channel], 0));
  325 +
  326 + // What's the horizontal distance between sampling points?
  327 + double horizontalFactor =
  328 + this->dataAnalyzer->data(channel)->samples.voltage.interval /
  329 + this->settings->scope.horizontal.timebase;
  330 + // How many samples are visible?
  331 + double centerPosition, centerOffset;
  332 + if (zoomed) {
  333 + centerPosition = (zoomOffset + DIVS_TIME / 2) / horizontalFactor;
  334 + centerOffset = DIVS_TIME / horizontalFactor / zoomFactor / 2;
  335 + } else {
  336 + centerPosition = DIVS_TIME / 2 / horizontalFactor;
  337 + centerOffset = DIVS_TIME / horizontalFactor / 2;
  338 + }
  339 + unsigned int firstPosition =
  340 + qMax((int)(centerPosition - centerOffset), 0);
  341 + unsigned int lastPosition =
  342 + qMin((int)(centerPosition + centerOffset),
  343 + (int)this->dataAnalyzer->data(channel)
  344 + ->samples.voltage.sample.size() -
  345 + 1);
  346 +
  347 + // Draw graph
  348 + QPointF *graph = new QPointF[lastPosition - firstPosition + 1];
  349 +
  350 + for (unsigned int position = firstPosition;
  351 + position <= lastPosition; ++position)
  352 + graph[position - firstPosition] =
  353 + QPointF(position * horizontalFactor - DIVS_TIME / 2,
  354 + this->dataAnalyzer->data(channel)
  355 + ->samples.voltage.sample[position] /
  356 + this->settings->scope.voltage[channel].gain +
  357 + this->settings->scope.voltage[channel].offset);
  358 +
  359 + painter.drawPolyline(graph, lastPosition - firstPosition + 1);
  360 + delete[] graph;
  361 + }
  362 + }
409 363  
410   - default:
411   - break;
412   - }
  364 + // Add spectrum graphs
  365 + for (int channel = 0; channel < this->settings->scope.spectrum.count();
  366 + ++channel) {
  367 + if (this->settings->scope.spectrum[channel].used &&
  368 + this->dataAnalyzer->data(channel)) {
  369 + painter.setPen(QPen(colorValues->spectrum[channel], 0));
  370 +
  371 + // What's the horizontal distance between sampling points?
  372 + double horizontalFactor =
  373 + this->dataAnalyzer->data(channel)->samples.spectrum.interval /
  374 + this->settings->scope.horizontal.frequencybase;
  375 + // How many samples are visible?
  376 + double centerPosition, centerOffset;
  377 + if (zoomed) {
  378 + centerPosition = (zoomOffset + DIVS_TIME / 2) / horizontalFactor;
  379 + centerOffset = DIVS_TIME / horizontalFactor / zoomFactor / 2;
  380 + } else {
  381 + centerPosition = DIVS_TIME / 2 / horizontalFactor;
  382 + centerOffset = DIVS_TIME / horizontalFactor / 2;
  383 + }
  384 + unsigned int firstPosition =
  385 + qMax((int)(centerPosition - centerOffset), 0);
  386 + unsigned int lastPosition =
  387 + qMin((int)(centerPosition + centerOffset),
  388 + (int)this->dataAnalyzer->data(channel)
  389 + ->samples.spectrum.sample.size() -
  390 + 1);
  391 +
  392 + // Draw graph
  393 + QPointF *graph = new QPointF[lastPosition - firstPosition + 1];
  394 +
  395 + for (unsigned int position = firstPosition;
  396 + position <= lastPosition; ++position)
  397 + graph[position - firstPosition] = QPointF(
  398 + position * horizontalFactor - DIVS_TIME / 2,
  399 + this->dataAnalyzer->data(channel)
  400 + ->samples.spectrum.sample[position] /
  401 + this->settings->scope.spectrum[channel].magnitude +
  402 + this->settings->scope.spectrum[channel].offset);
  403 +
  404 + painter.drawPolyline(graph, lastPosition - firstPosition + 1);
  405 + delete[] graph;
  406 + }
  407 + }
  408 + break;
413 409  
414   - // Set DIVS_TIME / zoomFactor x DIVS_VOLTAGE matrix for zoomed
415   - // oscillograph
416   - painter.setMatrix(
417   - QMatrix((paintDevice->width() - 1) / DIVS_TIME * zoomFactor, 0, 0,
418   - -(scopeHeight - 1) / DIVS_VOLTAGE,
419   - (double)(paintDevice->width() - 1) / 2 -
420   - zoomOffset * zoomFactor * (paintDevice->width() - 1) /
421   - DIVS_TIME,
422   - (scopeHeight - 1) * 1.5 + lineHeight * 4),
423   - false);
424   - }
  410 + case Dso::GRAPHFORMAT_XY:
  411 + break;
425 412  
426   - this->dataAnalyzer->mutex()->unlock();
  413 + default:
  414 + break;
  415 + }
  416 +
  417 + // Set DIVS_TIME / zoomFactor x DIVS_VOLTAGE matrix for zoomed
  418 + // oscillograph
  419 + painter.setMatrix(
  420 + QMatrix((paintDevice->width() - 1) / DIVS_TIME * zoomFactor, 0, 0,
  421 + -(scopeHeight - 1) / DIVS_VOLTAGE,
  422 + (double)(paintDevice->width() - 1) / 2 -
  423 + zoomOffset * zoomFactor * (paintDevice->width() - 1) /
  424 + DIVS_TIME,
  425 + (scopeHeight - 1) * 1.5 + lineHeight * 4),
  426 + false);
  427 + }
  428 + } // dataanalyser mutex release
427 429  
428 430 // Draw grids
429 431 painter.setRenderHint(QPainter::Antialiasing, false);
... ...
openhantek/src/glgenerator.cpp
... ... @@ -87,7 +87,7 @@ void GlGenerator::generateGraphs() {
87 87 }
88 88 }
89 89  
90   - this->dataAnalyzer->mutex()->lock();
  90 + QMutexLocker locker(this->dataAnalyzer->mutex());
91 91  
92 92 unsigned int preTrigSamples = 0;
93 93 unsigned int postTrigSamples = 0;
... ... @@ -116,10 +116,9 @@ void GlGenerator::generateGraphs() {
116 116 // 3: Ignore samples
117 117 // For now #3 is chosen
118 118 #ifdef DEBUG
119   - Helper::timestampDebug(QString("Too few samples to make a steady "
  119 + timestampDebug(QString("Too few samples to make a steady "
120 120 "picture. Decrease sample rate"));
121 121 #endif
122   - this->dataAnalyzer->mutex()->unlock();
123 122 return;
124 123 }
125 124 preTrigSamples =
... ... @@ -172,9 +171,8 @@ void GlGenerator::generateGraphs() {
172 171 }
173 172 if (swTriggerStart == 0) {
174 173 #ifdef DEBUG
175   - Helper::timestampDebug(QString("Trigger not asserted. Data ignored"));
  174 + timestampDebug(QString("Trigger not asserted. Data ignored"));
176 175 #endif
177   - this->dataAnalyzer->mutex()->unlock();
178 176 return;
179 177 }
180 178 }
... ... @@ -334,8 +332,6 @@ void GlGenerator::generateGraphs() {
334 332 break;
335 333 }
336 334  
337   - this->dataAnalyzer->mutex()->unlock();
338   -
339 335 emit graphsGenerated();
340 336 }
341 337  
... ...
openhantek/src/glgenerator.h
... ... @@ -32,7 +32,7 @@
32 32 #include <QGLFunctions>
33 33 #include <QObject>
34 34  
35   -#include "dso.h"
  35 +#include "definitions.h"
36 36  
37 37 #define DIVS_TIME 10.0 ///< Number of horizontal screen divs
38 38 #define DIVS_VOLTAGE 8.0 ///< Number of vertical screen divs
... ...
openhantek/src/glscope.h
... ... @@ -36,7 +36,7 @@ using GL_WIDGET_CLASS = QOpenGLWidget;
36 36 using GL_WIDGET_CLASS = QGLWidget;
37 37 #endif
38 38  
39   -#include "dso.h"
  39 +#include "definitions.h"
40 40 #include "glgenerator.h"
41 41  
42 42 class DataAnalyzer;
... ...
openhantek/src/hantek/types.cpp renamed to openhantek/src/hantek/bulkStructs.cpp
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// hantek/types.cpp
5   -//
6   -// Copyright (C) 2008, 2009 Oleg Khudyakov
7   -// prcoder@potrebitel.ru
8   -// Copyright (C) 2010 Oliver Haag
9   -// oliver.haag@gmail.com
10   -//
11   -// This program is free software: you can redistribute it and/or modify it
12   -// under the terms of the GNU General Public License as published by the Free
13   -// Software Foundation, either version 3 of the License, or (at your option)
14   -// any later version.
15   -//
16   -// This program is distributed in the hope that it will be useful, but WITHOUT
17   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19   -// more details.
20   -//
21   -// You should have received a copy of the GNU General Public License along with
22   -// this program. If not, see <http://www.gnu.org/licenses/>.
23   -//
24   -////////////////////////////////////////////////////////////////////////////////
25   -
26   -#include <cstring>
27   -
28   -#include "hantek/types.h"
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#include "bulkStructs.h"
29 4  
30 5 namespace Hantek {
  6 +
31 7 //////////////////////////////////////////////////////////////////////////////
32 8 // class BulkSetFilter
33 9 /// \brief Sets the data array to the default values.
34   -BulkSetFilter::BulkSetFilter() : Helper::DataArray<uint8_t>(8) { this->init(); }
  10 +BulkSetFilter::BulkSetFilter() : DataArray<uint8_t>(8) { this->init(); }
35 11  
36 12 /// \brief Sets the FilterByte to the given value.
37 13 /// \param channel1 true if channel 1 is filtered.
38 14 /// \param channel2 true if channel 2 is filtered.
39 15 /// \param trigger true if trigger is filtered.
40 16 BulkSetFilter::BulkSetFilter(bool channel1, bool channel2, bool trigger)
41   - : Helper::DataArray<uint8_t>(8) {
  17 + : DataArray<uint8_t>(8) {
42 18 this->init();
43 19  
44 20 this->setChannel(0, channel1);
... ... @@ -92,7 +68,7 @@ void BulkSetFilter::init() {
92 68 // class BulkSetTriggerAndSamplerate
93 69 /// \brief Sets the data array to the default values.
94 70 BulkSetTriggerAndSamplerate::BulkSetTriggerAndSamplerate()
95   - : Helper::DataArray<uint8_t>(12) {
  71 + : DataArray<uint8_t>(12) {
96 72 this->init();
97 73 }
98 74  
... ... @@ -110,7 +86,7 @@ BulkSetTriggerAndSamplerate::BulkSetTriggerAndSamplerate(
110 86 uint16_t downsampler, uint32_t triggerPosition, uint8_t triggerSource,
111 87 uint8_t recordLength, uint8_t samplerateId, bool downsamplingMode,
112 88 uint8_t usedChannels, bool fastRate, uint8_t triggerSlope)
113   - : Helper::DataArray<uint8_t>(12) {
  89 + : DataArray<uint8_t>(12) {
114 90 this->init();
115 91  
116 92 this->setTriggerSource(triggerSource);
... ... @@ -244,35 +220,35 @@ void BulkSetTriggerAndSamplerate::init() {
244 220 //////////////////////////////////////////////////////////////////////////////
245 221 // class BulkForceTrigger
246 222 /// \brief Sets the data array to needed values.
247   -BulkForceTrigger::BulkForceTrigger() : Helper::DataArray<uint8_t>(2) {
  223 +BulkForceTrigger::BulkForceTrigger() : DataArray<uint8_t>(2) {
248 224 this->array[0] = BULK_FORCETRIGGER;
249 225 }
250 226  
251 227 //////////////////////////////////////////////////////////////////////////////
252 228 // class BulkCaptureStart
253 229 /// \brief Sets the data array to needed values.
254   -BulkCaptureStart::BulkCaptureStart() : Helper::DataArray<uint8_t>(2) {
  230 +BulkCaptureStart::BulkCaptureStart() : DataArray<uint8_t>(2) {
255 231 this->array[0] = BULK_STARTSAMPLING;
256 232 }
257 233  
258 234 //////////////////////////////////////////////////////////////////////////////
259 235 // class BulkTriggerEnabled
260 236 /// \brief Sets the data array to needed values.
261   -BulkTriggerEnabled::BulkTriggerEnabled() : Helper::DataArray<uint8_t>(2) {
  237 +BulkTriggerEnabled::BulkTriggerEnabled() : DataArray<uint8_t>(2) {
262 238 this->array[0] = BULK_ENABLETRIGGER;
263 239 }
264 240  
265 241 //////////////////////////////////////////////////////////////////////////////
266 242 // class BulkGetData
267 243 /// \brief Sets the data array to needed values.
268   -BulkGetData::BulkGetData() : Helper::DataArray<uint8_t>(2) {
  244 +BulkGetData::BulkGetData() : DataArray<uint8_t>(2) {
269 245 this->array[0] = BULK_GETDATA;
270 246 }
271 247  
272 248 //////////////////////////////////////////////////////////////////////////////
273 249 // class BulkGetCaptureState
274 250 /// \brief Sets the data array to needed values.
275   -BulkGetCaptureState::BulkGetCaptureState() : Helper::DataArray<uint8_t>(2) {
  251 +BulkGetCaptureState::BulkGetCaptureState() : DataArray<uint8_t>(2) {
276 252 this->array[0] = BULK_GETCAPTURESTATE;
277 253 }
278 254  
... ... @@ -280,7 +256,7 @@ BulkGetCaptureState::BulkGetCaptureState() : Helper::DataArray&lt;uint8_t&gt;(2) {
280 256 // class BulkResponseGetCaptureState
281 257 /// \brief Initializes the array.
282 258 BulkResponseGetCaptureState::BulkResponseGetCaptureState()
283   - : Helper::DataArray<uint8_t>(512) {}
  259 + : DataArray<uint8_t>(512) {}
284 260  
285 261 /// \brief Gets the capture state.
286 262 /// \return The CaptureState of the oscilloscope.
... ... @@ -297,13 +273,13 @@ unsigned int BulkResponseGetCaptureState::getTriggerPoint() {
297 273 //////////////////////////////////////////////////////////////////////////////
298 274 // class BulkSetGain
299 275 /// \brief Sets the data array to needed values.
300   -BulkSetGain::BulkSetGain() : Helper::DataArray<uint8_t>(8) { this->init(); }
  276 +BulkSetGain::BulkSetGain() : DataArray<uint8_t>(8) { this->init(); }
301 277  
302 278 /// \brief Sets the gain to the given values.
303 279 /// \param channel1 The gain value for channel 1.
304 280 /// \param channel2 The gain value for channel 2.
305 281 BulkSetGain::BulkSetGain(uint8_t channel1, uint8_t channel2)
306   - : Helper::DataArray<uint8_t>(8) {
  282 + : DataArray<uint8_t>(8) {
307 283 this->init();
308 284  
309 285 this->setGain(0, channel1);
... ... @@ -338,14 +314,14 @@ void BulkSetGain::init() { this-&gt;array[0] = BULK_SETGAIN; }
338 314 //////////////////////////////////////////////////////////////////////////////
339 315 // class BulkSetLogicalData
340 316 /// \brief Sets the data array to needed values.
341   -BulkSetLogicalData::BulkSetLogicalData() : Helper::DataArray<uint8_t>(8) {
  317 +BulkSetLogicalData::BulkSetLogicalData() : DataArray<uint8_t>(8) {
342 318 this->init();
343 319 }
344 320  
345 321 /// \brief Sets the data to the given value.
346 322 /// \param data The data byte.
347 323 BulkSetLogicalData::BulkSetLogicalData(uint8_t data)
348   - : Helper::DataArray<uint8_t>(8) {
  324 + : DataArray<uint8_t>(8) {
349 325 this->init();
350 326  
351 327 this->setData(data);
... ... @@ -365,21 +341,21 @@ void BulkSetLogicalData::init() { this-&gt;array[0] = BULK_SETLOGICALDATA; }
365 341 //////////////////////////////////////////////////////////////////////////////
366 342 // class BulkGetLogicalData
367 343 /// \brief Sets the data array to needed values.
368   -BulkGetLogicalData::BulkGetLogicalData() : Helper::DataArray<uint8_t>(2) {
  344 +BulkGetLogicalData::BulkGetLogicalData() : DataArray<uint8_t>(2) {
369 345 this->array[0] = BULK_GETLOGICALDATA;
370 346 }
371 347  
372 348 //////////////////////////////////////////////////////////////////////////////
373 349 // class BulkSetFilter2250
374 350 /// \brief Sets the data array to needed values.
375   -BulkSetChannels2250::BulkSetChannels2250() : Helper::DataArray<uint8_t>(4) {
  351 +BulkSetChannels2250::BulkSetChannels2250() : DataArray<uint8_t>(4) {
376 352 this->init();
377 353 }
378 354  
379 355 /// \brief Sets the used channels.
380 356 /// \param usedChannels The UsedChannels value.
381 357 BulkSetChannels2250::BulkSetChannels2250(uint8_t usedChannels)
382   - : Helper::DataArray<uint8_t>(4) {
  358 + : DataArray<uint8_t>(4) {
383 359 this->init();
384 360  
385 361 this->setUsedChannels(usedChannels);
... ... @@ -401,7 +377,7 @@ void BulkSetChannels2250::init() { this-&gt;array[0] = BULK_BSETCHANNELS; }
401 377 //////////////////////////////////////////////////////////////////////////////
402 378 // class BulkSetTrigger2250
403 379 /// \brief Sets the data array to needed values.
404   -BulkSetTrigger2250::BulkSetTrigger2250() : Helper::DataArray<uint8_t>(8) {
  380 +BulkSetTrigger2250::BulkSetTrigger2250() : DataArray<uint8_t>(8) {
405 381 this->init();
406 382 }
407 383  
... ... @@ -410,7 +386,7 @@ BulkSetTrigger2250::BulkSetTrigger2250() : Helper::DataArray&lt;uint8_t&gt;(8) {
410 386 /// \param triggerSlope The triggerSlope value (CTriggerBits).
411 387 BulkSetTrigger2250::BulkSetTrigger2250(uint8_t triggerSource,
412 388 uint8_t triggerSlope)
413   - : Helper::DataArray<uint8_t>(8) {
  389 + : DataArray<uint8_t>(8) {
414 390 this->init();
415 391  
416 392 this->setTriggerSource(triggerSource);
... ... @@ -449,7 +425,7 @@ void BulkSetTrigger2250::init() {
449 425 //////////////////////////////////////////////////////////////////////////////
450 426 // class BulkSetSamplerate5200
451 427 /// \brief Sets the data array to the default values.
452   -BulkSetSamplerate5200::BulkSetSamplerate5200() : Helper::DataArray<uint8_t>(6) {
  428 +BulkSetSamplerate5200::BulkSetSamplerate5200() : DataArray<uint8_t>(6) {
453 429 this->init();
454 430 }
455 431  
... ... @@ -458,7 +434,7 @@ BulkSetSamplerate5200::BulkSetSamplerate5200() : Helper::DataArray&lt;uint8_t&gt;(6) {
458 434 /// \param samplerateFast The SamplerateFast value.
459 435 BulkSetSamplerate5200::BulkSetSamplerate5200(uint16_t samplerateSlow,
460 436 uint8_t samplerateFast)
461   - : Helper::DataArray<uint8_t>(6) {
  437 + : DataArray<uint8_t>(6) {
462 438 this->init();
463 439  
464 440 this->setSamplerateFast(samplerateFast);
... ... @@ -497,14 +473,14 @@ void BulkSetSamplerate5200::init() {
497 473 // class BulkSetBuffer2250
498 474 /// \brief Sets the data array to the default values.
499 475 BulkSetRecordLength2250::BulkSetRecordLength2250()
500   - : Helper::DataArray<uint8_t>(4) {
  476 + : DataArray<uint8_t>(4) {
501 477 this->init();
502 478 }
503 479  
504 480 /// \brief Sets the data bytes to the specified values.
505 481 /// \param recordLength The ::RecordLengthId value.
506 482 BulkSetRecordLength2250::BulkSetRecordLength2250(uint8_t recordLength)
507   - : Helper::DataArray<uint8_t>(4) {
  483 + : DataArray<uint8_t>(4) {
508 484 this->init();
509 485  
510 486 this->setRecordLength(recordLength);
... ... @@ -526,7 +502,7 @@ void BulkSetRecordLength2250::init() { this-&gt;array[0] = BULK_DSETBUFFER; }
526 502 //////////////////////////////////////////////////////////////////////////////
527 503 // class BulkSetBuffer5200
528 504 /// \brief Sets the data array to the default values.
529   -BulkSetBuffer5200::BulkSetBuffer5200() : Helper::DataArray<uint8_t>(10) {
  505 +BulkSetBuffer5200::BulkSetBuffer5200() : DataArray<uint8_t>(10) {
530 506 this->init();
531 507 }
532 508  
... ... @@ -540,7 +516,7 @@ BulkSetBuffer5200::BulkSetBuffer5200(uint16_t triggerPositionPre,
540 516 uint16_t triggerPositionPost,
541 517 uint8_t usedPre, uint8_t usedPost,
542 518 uint8_t recordLength)
543   - : Helper::DataArray<uint8_t>(10) {
  519 + : DataArray<uint8_t>(10) {
544 520 this->init();
545 521  
546 522 this->setTriggerPositionPre(triggerPositionPre);
... ... @@ -618,7 +594,7 @@ void BulkSetBuffer5200::init() {
618 594 //////////////////////////////////////////////////////////////////////////////
619 595 // class BulkSetSamplerate2250
620 596 /// \brief Sets the data array to the default values.
621   -BulkSetSamplerate2250::BulkSetSamplerate2250() : Helper::DataArray<uint8_t>(8) {
  597 +BulkSetSamplerate2250::BulkSetSamplerate2250() : DataArray<uint8_t>(8) {
622 598 this->init();
623 599 }
624 600  
... ... @@ -628,7 +604,7 @@ BulkSetSamplerate2250::BulkSetSamplerate2250() : Helper::DataArray&lt;uint8_t&gt;(8) {
628 604 /// \param samplerate The Samplerate value.
629 605 BulkSetSamplerate2250::BulkSetSamplerate2250(bool fastRate, bool downsampling,
630 606 uint16_t samplerate)
631   - : Helper::DataArray<uint8_t>(8) {
  607 + : DataArray<uint8_t>(8) {
632 608 this->init();
633 609  
634 610 this->setFastRate(fastRate);
... ... @@ -681,7 +657,7 @@ void BulkSetSamplerate2250::init() {
681 657 //////////////////////////////////////////////////////////////////////////////
682 658 // class BulkSetTrigger5200
683 659 /// \brief Sets the data array to the default values.
684   -BulkSetTrigger5200::BulkSetTrigger5200() : Helper::DataArray<uint8_t>(8) {
  660 +BulkSetTrigger5200::BulkSetTrigger5200() : DataArray<uint8_t>(8) {
685 661 this->init();
686 662 }
687 663  
... ... @@ -695,7 +671,7 @@ BulkSetTrigger5200::BulkSetTrigger5200(uint8_t triggerSource,
695 671 uint8_t usedChannels, bool fastRate,
696 672 uint8_t triggerSlope,
697 673 uint8_t triggerPulse)
698   - : Helper::DataArray<uint8_t>(8) {
  674 + : DataArray<uint8_t>(8) {
699 675 this->init();
700 676  
701 677 this->setTriggerSource(triggerSource);
... ... @@ -775,7 +751,7 @@ void BulkSetTrigger5200::init() {
775 751 /// \class BulkSetBuffer2250 hantek/types.h
776 752 /// \brief The DSO-2250 BULK_FSETBUFFER builder.
777 753 /// \brief Sets the data array to the default values.
778   -BulkSetBuffer2250::BulkSetBuffer2250() : Helper::DataArray<uint8_t>(10) {
  754 +BulkSetBuffer2250::BulkSetBuffer2250() : DataArray<uint8_t>(10) {
779 755 this->init();
780 756 }
781 757  
... ... @@ -784,7 +760,7 @@ BulkSetBuffer2250::BulkSetBuffer2250() : Helper::DataArray&lt;uint8_t&gt;(10) {
784 760 /// \param triggerPositionPost The TriggerPositionPost value.
785 761 BulkSetBuffer2250::BulkSetBuffer2250(uint32_t triggerPositionPre,
786 762 uint32_t triggerPositionPost)
787   - : Helper::DataArray<uint8_t>(12) {
  763 + : DataArray<uint8_t>(12) {
788 764 this->init();
789 765  
790 766 this->setTriggerPositionPre(triggerPositionPre);
... ... @@ -824,222 +800,4 @@ void BulkSetBuffer2250::setTriggerPositionPre(uint32_t position) {
824 800 /// \brief Initialize the array to the needed values.
825 801 void BulkSetBuffer2250::init() { this->array[0] = BULK_FSETBUFFER; }
826 802  
827   -//////////////////////////////////////////////////////////////////////////////
828   -// class ControlGetSpeed
829   -/// \brief Initializes the array.
830   -ControlGetSpeed::ControlGetSpeed() : Helper::DataArray<uint8_t>(10) {}
831   -
832   -/// \brief Gets the speed of the connection.
833   -/// \return The speed level of the USB connection.
834   -ConnectionSpeed ControlGetSpeed::getSpeed() {
835   - return (ConnectionSpeed)this->array[0];
836   -}
837   -
838   -//////////////////////////////////////////////////////////////////////////////
839   -// class ControlBeginCommand
840   -/// \brief Sets the command index to the given value.
841   -/// \param index The CommandIndex for the command.
842   -ControlBeginCommand::ControlBeginCommand(BulkIndex index)
843   - : Helper::DataArray<uint8_t>(10) {
844   - this->init();
845   -
846   - this->setIndex(index);
847   -}
848   -
849   -/// \brief Gets the command index.
850   -/// \return The CommandIndex for the command.
851   -BulkIndex ControlBeginCommand::getIndex() { return (BulkIndex)this->array[1]; }
852   -
853   -/// \brief Sets the command index to the given value.
854   -/// \param index The new CommandIndex for the command.
855   -void ControlBeginCommand::setIndex(BulkIndex index) {
856   - memset(&(this->array[1]), (uint8_t)index, 3);
857   -}
858   -
859   -/// \brief Initialize the array to the needed values.
860   -void ControlBeginCommand::init() { this->array[0] = 0x0f; }
861   -
862   -//////////////////////////////////////////////////////////////////////////////
863   -// class ControlSetOffset
864   -/// \brief Sets the data array to the default values.
865   -ControlSetOffset::ControlSetOffset() : Helper::DataArray<uint8_t>(17) {}
866   -
867   -/// \brief Sets the offsets to the given values.
868   -/// \param channel1 The offset for channel 1.
869   -/// \param channel2 The offset for channel 2.
870   -/// \param trigger The offset for ext. trigger.
871   -ControlSetOffset::ControlSetOffset(uint16_t channel1, uint16_t channel2,
872   - uint16_t trigger)
873   - : Helper::DataArray<uint8_t>(17) {
874   - this->setChannel(0, channel1);
875   - this->setChannel(1, channel2);
876   - this->setTrigger(trigger);
877   -}
878   -
879   -/// \brief Get the offset for the given channel.
880   -/// \param channel The channel whose offset should be returned.
881   -/// \return The channel offset value.
882   -uint16_t ControlSetOffset::getChannel(unsigned int channel) {
883   - if (channel == 0)
884   - return ((this->array[0] & 0x0f) << 8) | this->array[1];
885   - else
886   - return ((this->array[2] & 0x0f) << 8) | this->array[3];
887   -}
888   -
889   -/// \brief Set the offset for the given channel.
890   -/// \param channel The channel that should be set.
891   -/// \param offset The new channel offset value.
892   -void ControlSetOffset::setChannel(unsigned int channel, uint16_t offset) {
893   - if (channel == 0) {
894   - this->array[0] = (uint8_t)(offset >> 8);
895   - this->array[1] = (uint8_t)offset;
896   - } else {
897   - this->array[2] = (uint8_t)(offset >> 8);
898   - this->array[3] = (uint8_t)offset;
899   - }
900   -}
901   -
902   -/// \brief Get the trigger level.
903   -/// \return The trigger level value.
904   -uint16_t ControlSetOffset::getTrigger() {
905   - return ((this->array[4] & 0x0f) << 8) | this->array[5];
906   -}
907   -
908   -/// \brief Set the trigger level.
909   -/// \param level The new trigger level value.
910   -void ControlSetOffset::setTrigger(uint16_t level) {
911   - this->array[4] = (uint8_t)(level >> 8);
912   - this->array[5] = (uint8_t)level;
913   -}
914   -
915   -//////////////////////////////////////////////////////////////////////////////
916   -// class ControlSetRelays
917   -/// \brief Sets all relay states.
918   -/// \param ch1Below1V Sets the state of the Channel 1 below 1 V relay.
919   -/// \param ch1Below100mV Sets the state of the Channel 1 below 100 mV relay.
920   -/// \param ch1CouplingDC Sets the state of the Channel 1 coupling relay.
921   -/// \param ch2Below1V Sets the state of the Channel 2 below 1 V relay.
922   -/// \param ch2Below100mV Sets the state of the Channel 2 below 100 mV relay.
923   -/// \param ch2CouplingDC Sets the state of the Channel 2 coupling relay.
924   -/// \param triggerExt Sets the state of the external trigger relay.
925   -ControlSetRelays::ControlSetRelays(bool ch1Below1V, bool ch1Below100mV,
926   - bool ch1CouplingDC, bool ch2Below1V,
927   - bool ch2Below100mV, bool ch2CouplingDC,
928   - bool triggerExt)
929   - : Helper::DataArray<uint8_t>(17) {
930   - this->setBelow1V(0, ch1Below1V);
931   - this->setBelow100mV(0, ch1Below100mV);
932   - this->setCoupling(0, ch1CouplingDC);
933   - this->setBelow1V(1, ch2Below1V);
934   - this->setBelow100mV(1, ch2Below100mV);
935   - this->setCoupling(1, ch2CouplingDC);
936   - this->setTrigger(triggerExt);
937   -}
938   -
939   -/// \brief Get the below 1 V relay state for the given channel.
940   -/// \param channel The channel whose relay state should be returned.
941   -/// \return true, if the gain of the channel is below 1 V.
942   -bool ControlSetRelays::getBelow1V(unsigned int channel) {
943   - if (channel == 0)
944   - return (this->array[1] & 0x04) == 0x00;
945   - else
946   - return (this->array[4] & 0x20) == 0x00;
947   -}
948   -
949   -/// \brief Set the below 1 V relay for the given channel.
950   -/// \param channel The channel that should be set.
951   -/// \param below true, if the gain of the channel should be below 1 V.
952   -void ControlSetRelays::setBelow1V(unsigned int channel, bool below) {
953   - if (channel == 0)
954   - this->array[1] = below ? 0xfb : 0x04;
955   - else
956   - this->array[4] = below ? 0xdf : 0x20;
957   -}
958   -
959   -/// \brief Get the below 1 V relay state for the given channel.
960   -/// \param channel The channel whose relay state should be returned.
961   -/// \return true, if the gain of the channel is below 1 V.
962   -bool ControlSetRelays::getBelow100mV(unsigned int channel) {
963   - if (channel == 0)
964   - return (this->array[2] & 0x08) == 0x00;
965   - else
966   - return (this->array[5] & 0x40) == 0x00;
967   -}
968   -
969   -/// \brief Set the below 100 mV relay for the given channel.
970   -/// \param channel The channel that should be set.
971   -/// \param below true, if the gain of the channel should be below 100 mV.
972   -void ControlSetRelays::setBelow100mV(unsigned int channel, bool below) {
973   - if (channel == 0)
974   - this->array[2] = below ? 0xf7 : 0x08;
975   - else
976   - this->array[5] = below ? 0xbf : 0x40;
977   -}
978   -
979   -/// \brief Get the coupling relay state for the given channel.
980   -/// \param channel The channel whose relay state should be returned.
981   -/// \return true, if the coupling of the channel is DC.
982   -bool ControlSetRelays::getCoupling(unsigned int channel) {
983   - if (channel == 0)
984   - return (this->array[3] & 0x02) == 0x00;
985   - else
986   - return (this->array[6] & 0x10) == 0x00;
987   -}
988   -
989   -/// \brief Set the coupling relay for the given channel.
990   -/// \param channel The channel that should be set.
991   -/// \param dc true, if the coupling of the channel should be DC.
992   -void ControlSetRelays::setCoupling(unsigned int channel, bool dc) {
993   - if (channel == 0)
994   - this->array[3] = dc ? 0xfd : 0x02;
995   - else
996   - this->array[6] = dc ? 0xef : 0x10;
997   -}
998   -
999   -/// \brief Get the external trigger relay state.
1000   -/// \return true, if the trigger is external (EXT-Connector).
1001   -bool ControlSetRelays::getTrigger() { return (this->array[7] & 0x01) == 0x00; }
1002   -
1003   -/// \brief Set the external trigger relay.
1004   -/// \param ext true, if the trigger should be external (EXT-Connector).
1005   -void ControlSetRelays::setTrigger(bool ext) {
1006   - this->array[7] = ext ? 0xfe : 0x01;
1007   -}
1008   -
1009   -//////////////////////////////////////////////////////////////////////////////
1010   -// class ControlSetVoltDIV_CH1
1011   -/// \brief Sets the data array to the default values.
1012   -ControlSetVoltDIV_CH1::ControlSetVoltDIV_CH1() : Helper::DataArray<uint8_t>(1) {
1013   - this->setDiv(5);
1014   -}
1015   -
1016   -void ControlSetVoltDIV_CH1::setDiv(uint8_t val) { this->array[0] = val; }
1017   -
1018   -//////////////////////////////////////////////////////////////////////////////
1019   -// class ControlSetVoltDIV_CH2
1020   -/// \brief Sets the data array to the default values.
1021   -ControlSetVoltDIV_CH2::ControlSetVoltDIV_CH2() : Helper::DataArray<uint8_t>(1) {
1022   - this->setDiv(5);
1023   -}
1024   -
1025   -void ControlSetVoltDIV_CH2::setDiv(uint8_t val) { this->array[0] = val; }
1026   -
1027   -//////////////////////////////////////////////////////////////////////////////
1028   -// class ControlSetTimeDIV
1029   -/// \brief Sets the data array to the default values.
1030   -ControlSetTimeDIV::ControlSetTimeDIV() : Helper::DataArray<uint8_t>(1) {
1031   - this->setDiv(1);
1032   -}
1033   -
1034   -void ControlSetTimeDIV::setDiv(uint8_t val) { this->array[0] = val; }
1035   -
1036   -//////////////////////////////////////////////////////////////////////////////
1037   -// class ControlAcquireHardData
1038   -/// \brief Sets the data array to the default values.
1039   -ControlAcquireHardData::ControlAcquireHardData()
1040   - : Helper::DataArray<uint8_t>(1) {
1041   - this->init();
1042   -}
1043   -
1044   -void ControlAcquireHardData::init() { this->array[0] = 0x01; }
1045 803 }
... ...
openhantek/src/hantek/bulkStructs.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +
  5 +#include <string>
  6 +#include <list>
  7 +
  8 +#include <QString>
  9 +
  10 +#include "utils/dataarray.h"
  11 +#include "definitions.h"
  12 +
  13 +////////////////////////////////////////////////////////////////////////////////
  14 +/// \namespace Hantek hantek/types.h
  15 +/// \brief All %Hantek DSO device specific things.
  16 +namespace Hantek {
  17 +
  18 +//////////////////////////////////////////////////////////////////////////////
  19 +/// \class BulkSetFilter hantek/types.h
  20 +/// \brief The BULK_SETFILTER builder.
  21 +class BulkSetFilter : public DataArray<uint8_t> {
  22 +public:
  23 + BulkSetFilter();
  24 + BulkSetFilter(bool channel1, bool channel2, bool trigger);
  25 +
  26 + bool getChannel(unsigned int channel);
  27 + void setChannel(unsigned int channel, bool filtered);
  28 + bool getTrigger();
  29 + void setTrigger(bool filtered);
  30 +
  31 +private:
  32 + void init();
  33 +};
  34 +
  35 +//////////////////////////////////////////////////////////////////////////////
  36 +/// \class BulkSetTriggerAndSamplerate hantek/types.h
  37 +/// \brief The BULK_SETTRIGGERANDSAMPLERATE builder.
  38 +class BulkSetTriggerAndSamplerate : public DataArray<uint8_t> {
  39 +public:
  40 + BulkSetTriggerAndSamplerate();
  41 + BulkSetTriggerAndSamplerate(uint16_t downsampler, uint32_t triggerPosition,
  42 + uint8_t triggerSource = 0,
  43 + uint8_t recordLength = 0,
  44 + uint8_t samplerateId = 0,
  45 + bool downsamplingMode = true,
  46 + uint8_t usedChannels = 0, bool fastRate = false,
  47 + uint8_t triggerSlope = 0);
  48 +
  49 + uint8_t getTriggerSource();
  50 + void setTriggerSource(uint8_t value);
  51 + uint8_t getRecordLength();
  52 + void setRecordLength(uint8_t value);
  53 + uint8_t getSamplerateId();
  54 + void setSamplerateId(uint8_t value);
  55 + bool getDownsamplingMode();
  56 + void setDownsamplingMode(bool downsampling);
  57 + uint8_t getUsedChannels();
  58 + void setUsedChannels(uint8_t value);
  59 + bool getFastRate();
  60 + void setFastRate(bool fastRate);
  61 + uint8_t getTriggerSlope();
  62 + void setTriggerSlope(uint8_t slope);
  63 + uint16_t getDownsampler();
  64 + void setDownsampler(uint16_t downsampler);
  65 + uint32_t getTriggerPosition();
  66 + void setTriggerPosition(uint32_t position);
  67 +
  68 +private:
  69 + void init();
  70 +};
  71 +
  72 +//////////////////////////////////////////////////////////////////////////////
  73 +/// \class BulkForceTrigger hantek/types.h
  74 +/// \brief The BULK_FORCETRIGGER builder.
  75 +class BulkForceTrigger : public DataArray<uint8_t> {
  76 +public:
  77 + BulkForceTrigger();
  78 +};
  79 +
  80 +//////////////////////////////////////////////////////////////////////////////
  81 +/// \class BulkCaptureStart hantek/types.h
  82 +/// \brief The BULK_CAPTURESTART builder.
  83 +class BulkCaptureStart : public DataArray<uint8_t> {
  84 +public:
  85 + BulkCaptureStart();
  86 +};
  87 +
  88 +//////////////////////////////////////////////////////////////////////////////
  89 +/// \class BulkTriggerEnabled hantek/types.h
  90 +/// \brief The BULK_TRIGGERENABLED builder.
  91 +class BulkTriggerEnabled : public DataArray<uint8_t> {
  92 +public:
  93 + BulkTriggerEnabled();
  94 +};
  95 +
  96 +//////////////////////////////////////////////////////////////////////////////
  97 +/// \class BulkGetData hantek/types.h
  98 +/// \brief The BULK_GETDATA builder.
  99 +class BulkGetData : public DataArray<uint8_t> {
  100 +public:
  101 + BulkGetData();
  102 +};
  103 +
  104 +//////////////////////////////////////////////////////////////////////////////
  105 +/// \class BulkGetCaptureState hantek/types.h
  106 +/// \brief The BULK_GETCAPTURESTATE builder.
  107 +class BulkGetCaptureState : public DataArray<uint8_t> {
  108 +public:
  109 + BulkGetCaptureState();
  110 +};
  111 +
  112 +//////////////////////////////////////////////////////////////////////////////
  113 +/// \class BulkResponseGetCaptureState hantek/types.h
  114 +/// \brief The parser for the BULK_GETCAPTURESTATE response.
  115 +class BulkResponseGetCaptureState : public DataArray<uint8_t> {
  116 +public:
  117 + BulkResponseGetCaptureState();
  118 +
  119 + CaptureState getCaptureState();
  120 + unsigned int getTriggerPoint();
  121 +};
  122 +
  123 +//////////////////////////////////////////////////////////////////////////////
  124 +/// \class BulkSetGain hantek/types.h
  125 +/// \brief The BULK_SETGAIN builder.
  126 +class BulkSetGain : public DataArray<uint8_t> {
  127 +public:
  128 + BulkSetGain();
  129 + BulkSetGain(uint8_t channel1, uint8_t channel2);
  130 +
  131 + uint8_t getGain(unsigned int channel);
  132 + void setGain(unsigned int channel, uint8_t value);
  133 +
  134 +private:
  135 + void init();
  136 +};
  137 +
  138 +//////////////////////////////////////////////////////////////////////////////
  139 +/// \class BulkSetLogicalData hantek/types.h
  140 +/// \brief The BULK_SETLOGICALDATA builder.
  141 +class BulkSetLogicalData : public DataArray<uint8_t> {
  142 +public:
  143 + BulkSetLogicalData();
  144 + BulkSetLogicalData(uint8_t data);
  145 +
  146 + uint8_t getData();
  147 + void setData(uint8_t data);
  148 +
  149 +private:
  150 + void init();
  151 +};
  152 +
  153 +//////////////////////////////////////////////////////////////////////////////
  154 +/// \class BulkGetLogicalData hantek/types.h
  155 +/// \brief The BULK_GETLOGICALDATA builder.
  156 +class BulkGetLogicalData : public DataArray<uint8_t> {
  157 +public:
  158 + BulkGetLogicalData();
  159 +};
  160 +
  161 +//////////////////////////////////////////////////////////////////////////////
  162 +/// \class BulkSetChannels2250 hantek/types.h
  163 +/// \brief The DSO-2250 BULK_BSETFILTER builder.
  164 +class BulkSetChannels2250 : public DataArray<uint8_t> {
  165 +public:
  166 + BulkSetChannels2250();
  167 + BulkSetChannels2250(uint8_t usedChannels);
  168 +
  169 + uint8_t getUsedChannels();
  170 + void setUsedChannels(uint8_t value);
  171 +
  172 +private:
  173 + void init();
  174 +};
  175 +
  176 +//////////////////////////////////////////////////////////////////////////////
  177 +/// \class BulkSetTrigger2250 hantek/types.h
  178 +/// \brief The DSO-2250 BULK_CSETTRIGGERORSAMPLERATE builder.
  179 +class BulkSetTrigger2250 : public DataArray<uint8_t> {
  180 +public:
  181 + BulkSetTrigger2250();
  182 + BulkSetTrigger2250(uint8_t triggerSource, uint8_t triggerSlope);
  183 +
  184 + uint8_t getTriggerSource();
  185 + void setTriggerSource(uint8_t value);
  186 + uint8_t getTriggerSlope();
  187 + void setTriggerSlope(uint8_t slope);
  188 +
  189 +private:
  190 + void init();
  191 +};
  192 +
  193 +//////////////////////////////////////////////////////////////////////////////
  194 +/// \class BulkSetSamplerate5200 hantek/types.h
  195 +/// \brief The DSO-5200/DSO-5200A BULK_CSETTRIGGERORSAMPLERATE builder.
  196 +class BulkSetSamplerate5200 : public DataArray<uint8_t> {
  197 +public:
  198 + BulkSetSamplerate5200();
  199 + BulkSetSamplerate5200(uint16_t samplerateSlow, uint8_t samplerateFast);
  200 +
  201 + uint8_t getSamplerateFast();
  202 + void setSamplerateFast(uint8_t value);
  203 + uint16_t getSamplerateSlow();
  204 + void setSamplerateSlow(uint16_t samplerate);
  205 +
  206 +private:
  207 + void init();
  208 +};
  209 +
  210 +//////////////////////////////////////////////////////////////////////////////
  211 +/// \class BulkSetRecordLength2250 hantek/types.h
  212 +/// \brief The DSO-2250 BULK_DSETBUFFER builder.
  213 +class BulkSetRecordLength2250 : public DataArray<uint8_t> {
  214 +public:
  215 + BulkSetRecordLength2250();
  216 + BulkSetRecordLength2250(uint8_t recordLength);
  217 +
  218 + uint8_t getRecordLength();
  219 + void setRecordLength(uint8_t value);
  220 +
  221 +private:
  222 + void init();
  223 +};
  224 +
  225 +//////////////////////////////////////////////////////////////////////////////
  226 +/// \class BulkSetBuffer5200 hantek/types.h
  227 +/// \brief The DSO-5200/DSO-5200A BULK_DSETBUFFER builder.
  228 +class BulkSetBuffer5200 : public DataArray<uint8_t> {
  229 +public:
  230 + BulkSetBuffer5200();
  231 + BulkSetBuffer5200(uint16_t triggerPositionPre, uint16_t triggerPositionPost,
  232 + uint8_t usedPre = 0, uint8_t usedPost = 0,
  233 + uint8_t recordLength = 0);
  234 +
  235 + uint16_t getTriggerPositionPre();
  236 + void setTriggerPositionPre(uint16_t value);
  237 + uint16_t getTriggerPositionPost();
  238 + void setTriggerPositionPost(uint16_t value);
  239 + uint8_t getUsedPre();
  240 + void setUsedPre(uint8_t value);
  241 + uint8_t getUsedPost();
  242 + void setUsedPost(uint8_t value);
  243 + uint8_t getRecordLength();
  244 + void setRecordLength(uint8_t value);
  245 +
  246 +private:
  247 + void init();
  248 +};
  249 +
  250 +//////////////////////////////////////////////////////////////////////////////
  251 +/// \class BulkSetSamplerate2250 hantek/types.h
  252 +/// \brief The DSO-2250 BULK_ESETTRIGGERORSAMPLERATE builder.
  253 +class BulkSetSamplerate2250 : public DataArray<uint8_t> {
  254 +public:
  255 + BulkSetSamplerate2250();
  256 + BulkSetSamplerate2250(bool fastRate, bool downsampling = false,
  257 + uint16_t samplerate = 0);
  258 +
  259 + bool getFastRate();
  260 + void setFastRate(bool fastRate);
  261 + bool getDownsampling();
  262 + void setDownsampling(bool downsampling);
  263 + uint16_t getSamplerate();
  264 + void setSamplerate(uint16_t samplerate);
  265 +
  266 +private:
  267 + void init();
  268 +};
  269 +
  270 +//////////////////////////////////////////////////////////////////////////////
  271 +/// \class BulkSetTrigger5200 hantek/types.h
  272 +/// \brief The DSO-5200/DSO-5200A BULK_ESETTRIGGERORSAMPLERATE builder.
  273 +class BulkSetTrigger5200 : public DataArray<uint8_t> {
  274 +public:
  275 + BulkSetTrigger5200();
  276 + BulkSetTrigger5200(uint8_t triggerSource, uint8_t usedChannels,
  277 + bool fastRate = false, uint8_t triggerSlope = 0,
  278 + uint8_t triggerPulse = 0);
  279 +
  280 + uint8_t getTriggerSource();
  281 + void setTriggerSource(uint8_t value);
  282 + uint8_t getUsedChannels();
  283 + void setUsedChannels(uint8_t value);
  284 + bool getFastRate();
  285 + void setFastRate(bool fastRate);
  286 + uint8_t getTriggerSlope();
  287 + void setTriggerSlope(uint8_t slope);
  288 + bool getTriggerPulse();
  289 + void setTriggerPulse(bool pulse);
  290 +
  291 +private:
  292 + void init();
  293 +};
  294 +
  295 +//////////////////////////////////////////////////////////////////////////////
  296 +/// \class BulkSetBuffer2250 hantek/types.h
  297 +/// \brief The DSO-2250 BULK_FSETBUFFER builder.
  298 +class BulkSetBuffer2250 : public DataArray<uint8_t> {
  299 +public:
  300 + BulkSetBuffer2250();
  301 + BulkSetBuffer2250(uint32_t triggerPositionPre, uint32_t triggerPositionPost);
  302 +
  303 + uint32_t getTriggerPositionPost();
  304 + void setTriggerPositionPost(uint32_t value);
  305 + uint32_t getTriggerPositionPre();
  306 + void setTriggerPositionPre(uint32_t value);
  307 +
  308 +private:
  309 + void init();
  310 +};
  311 +
  312 +}
... ...
openhantek/src/hantek/controlStructs.cpp 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#include <cstring>
  4 +
  5 +#include "controlStructs.h"
  6 +
  7 +namespace Hantek {
  8 +
  9 +//////////////////////////////////////////////////////////////////////////////
  10 +// class ControlGetSpeed
  11 +/// \brief Initializes the array.
  12 +ControlGetSpeed::ControlGetSpeed() : DataArray<uint8_t>(10) {}
  13 +
  14 +/// \brief Gets the speed of the connection.
  15 +/// \return The speed level of the USB connection.
  16 +ConnectionSpeed ControlGetSpeed::getSpeed() {
  17 + return (ConnectionSpeed)this->array[0];
  18 +}
  19 +
  20 +//////////////////////////////////////////////////////////////////////////////
  21 +// class ControlSetOffset
  22 +/// \brief Sets the data array to the default values.
  23 +ControlSetOffset::ControlSetOffset() : DataArray<uint8_t>(17) {}
  24 +
  25 +/// \brief Sets the offsets to the given values.
  26 +/// \param channel1 The offset for channel 1.
  27 +/// \param channel2 The offset for channel 2.
  28 +/// \param trigger The offset for ext. trigger.
  29 +ControlSetOffset::ControlSetOffset(uint16_t channel1, uint16_t channel2,
  30 + uint16_t trigger)
  31 + : DataArray<uint8_t>(17) {
  32 + this->setChannel(0, channel1);
  33 + this->setChannel(1, channel2);
  34 + this->setTrigger(trigger);
  35 +}
  36 +
  37 +/// \brief Get the offset for the given channel.
  38 +/// \param channel The channel whose offset should be returned.
  39 +/// \return The channel offset value.
  40 +uint16_t ControlSetOffset::getChannel(unsigned int channel) {
  41 + if (channel == 0)
  42 + return ((this->array[0] & 0x0f) << 8) | this->array[1];
  43 + else
  44 + return ((this->array[2] & 0x0f) << 8) | this->array[3];
  45 +}
  46 +
  47 +/// \brief Set the offset for the given channel.
  48 +/// \param channel The channel that should be set.
  49 +/// \param offset The new channel offset value.
  50 +void ControlSetOffset::setChannel(unsigned int channel, uint16_t offset) {
  51 + if (channel == 0) {
  52 + this->array[0] = (uint8_t)(offset >> 8);
  53 + this->array[1] = (uint8_t)offset;
  54 + } else {
  55 + this->array[2] = (uint8_t)(offset >> 8);
  56 + this->array[3] = (uint8_t)offset;
  57 + }
  58 +}
  59 +
  60 +/// \brief Get the trigger level.
  61 +/// \return The trigger level value.
  62 +uint16_t ControlSetOffset::getTrigger() {
  63 + return ((this->array[4] & 0x0f) << 8) | this->array[5];
  64 +}
  65 +
  66 +/// \brief Set the trigger level.
  67 +/// \param level The new trigger level value.
  68 +void ControlSetOffset::setTrigger(uint16_t level) {
  69 + this->array[4] = (uint8_t)(level >> 8);
  70 + this->array[5] = (uint8_t)level;
  71 +}
  72 +
  73 +//////////////////////////////////////////////////////////////////////////////
  74 +// class ControlSetRelays
  75 +/// \brief Sets all relay states.
  76 +/// \param ch1Below1V Sets the state of the Channel 1 below 1 V relay.
  77 +/// \param ch1Below100mV Sets the state of the Channel 1 below 100 mV relay.
  78 +/// \param ch1CouplingDC Sets the state of the Channel 1 coupling relay.
  79 +/// \param ch2Below1V Sets the state of the Channel 2 below 1 V relay.
  80 +/// \param ch2Below100mV Sets the state of the Channel 2 below 100 mV relay.
  81 +/// \param ch2CouplingDC Sets the state of the Channel 2 coupling relay.
  82 +/// \param triggerExt Sets the state of the external trigger relay.
  83 +ControlSetRelays::ControlSetRelays(bool ch1Below1V, bool ch1Below100mV,
  84 + bool ch1CouplingDC, bool ch2Below1V,
  85 + bool ch2Below100mV, bool ch2CouplingDC,
  86 + bool triggerExt)
  87 + : DataArray<uint8_t>(17) {
  88 + this->setBelow1V(0, ch1Below1V);
  89 + this->setBelow100mV(0, ch1Below100mV);
  90 + this->setCoupling(0, ch1CouplingDC);
  91 + this->setBelow1V(1, ch2Below1V);
  92 + this->setBelow100mV(1, ch2Below100mV);
  93 + this->setCoupling(1, ch2CouplingDC);
  94 + this->setTrigger(triggerExt);
  95 +}
  96 +
  97 +/// \brief Get the below 1 V relay state for the given channel.
  98 +/// \param channel The channel whose relay state should be returned.
  99 +/// \return true, if the gain of the channel is below 1 V.
  100 +bool ControlSetRelays::getBelow1V(unsigned int channel) {
  101 + if (channel == 0)
  102 + return (this->array[1] & 0x04) == 0x00;
  103 + else
  104 + return (this->array[4] & 0x20) == 0x00;
  105 +}
  106 +
  107 +/// \brief Set the below 1 V relay for the given channel.
  108 +/// \param channel The channel that should be set.
  109 +/// \param below true, if the gain of the channel should be below 1 V.
  110 +void ControlSetRelays::setBelow1V(unsigned int channel, bool below) {
  111 + if (channel == 0)
  112 + this->array[1] = below ? 0xfb : 0x04;
  113 + else
  114 + this->array[4] = below ? 0xdf : 0x20;
  115 +}
  116 +
  117 +/// \brief Get the below 1 V relay state for the given channel.
  118 +/// \param channel The channel whose relay state should be returned.
  119 +/// \return true, if the gain of the channel is below 1 V.
  120 +bool ControlSetRelays::getBelow100mV(unsigned int channel) {
  121 + if (channel == 0)
  122 + return (this->array[2] & 0x08) == 0x00;
  123 + else
  124 + return (this->array[5] & 0x40) == 0x00;
  125 +}
  126 +
  127 +/// \brief Set the below 100 mV relay for the given channel.
  128 +/// \param channel The channel that should be set.
  129 +/// \param below true, if the gain of the channel should be below 100 mV.
  130 +void ControlSetRelays::setBelow100mV(unsigned int channel, bool below) {
  131 + if (channel == 0)
  132 + this->array[2] = below ? 0xf7 : 0x08;
  133 + else
  134 + this->array[5] = below ? 0xbf : 0x40;
  135 +}
  136 +
  137 +/// \brief Get the coupling relay state for the given channel.
  138 +/// \param channel The channel whose relay state should be returned.
  139 +/// \return true, if the coupling of the channel is DC.
  140 +bool ControlSetRelays::getCoupling(unsigned int channel) {
  141 + if (channel == 0)
  142 + return (this->array[3] & 0x02) == 0x00;
  143 + else
  144 + return (this->array[6] & 0x10) == 0x00;
  145 +}
  146 +
  147 +/// \brief Set the coupling relay for the given channel.
  148 +/// \param channel The channel that should be set.
  149 +/// \param dc true, if the coupling of the channel should be DC.
  150 +void ControlSetRelays::setCoupling(unsigned int channel, bool dc) {
  151 + if (channel == 0)
  152 + this->array[3] = dc ? 0xfd : 0x02;
  153 + else
  154 + this->array[6] = dc ? 0xef : 0x10;
  155 +}
  156 +
  157 +/// \brief Get the external trigger relay state.
  158 +/// \return true, if the trigger is external (EXT-Connector).
  159 +bool ControlSetRelays::getTrigger() { return (this->array[7] & 0x01) == 0x00; }
  160 +
  161 +/// \brief Set the external trigger relay.
  162 +/// \param ext true, if the trigger should be external (EXT-Connector).
  163 +void ControlSetRelays::setTrigger(bool ext) {
  164 + this->array[7] = ext ? 0xfe : 0x01;
  165 +}
  166 +
  167 +//////////////////////////////////////////////////////////////////////////////
  168 +// class ControlSetVoltDIV_CH1
  169 +/// \brief Sets the data array to the default values.
  170 +ControlSetVoltDIV_CH1::ControlSetVoltDIV_CH1() : DataArray<uint8_t>(1) {
  171 + this->setDiv(5);
  172 +}
  173 +
  174 +void ControlSetVoltDIV_CH1::setDiv(uint8_t val) { this->array[0] = val; }
  175 +
  176 +//////////////////////////////////////////////////////////////////////////////
  177 +// class ControlSetVoltDIV_CH2
  178 +/// \brief Sets the data array to the default values.
  179 +ControlSetVoltDIV_CH2::ControlSetVoltDIV_CH2() : DataArray<uint8_t>(1) {
  180 + this->setDiv(5);
  181 +}
  182 +
  183 +void ControlSetVoltDIV_CH2::setDiv(uint8_t val) { this->array[0] = val; }
  184 +
  185 +//////////////////////////////////////////////////////////////////////////////
  186 +// class ControlSetTimeDIV
  187 +/// \brief Sets the data array to the default values.
  188 +ControlSetTimeDIV::ControlSetTimeDIV() : DataArray<uint8_t>(1) {
  189 + this->setDiv(1);
  190 +}
  191 +
  192 +void ControlSetTimeDIV::setDiv(uint8_t val) { this->array[0] = val; }
  193 +
  194 +//////////////////////////////////////////////////////////////////////////////
  195 +// class ControlAcquireHardData
  196 +/// \brief Sets the data array to the default values.
  197 +ControlAcquireHardData::ControlAcquireHardData()
  198 + : DataArray<uint8_t>(1) {
  199 + this->init();
  200 +}
  201 +
  202 +void ControlAcquireHardData::init() { this->array[0] = 0x01; }
  203 +}
... ...
openhantek/src/hantek/controlStructs.h 0 โ†’ 100644
  1 +#pragma once
  2 +
  3 +#include "definitions.h"
  4 +#include "utils/dataarray.h"
  5 +
  6 +namespace Hantek {
  7 +
  8 +//////////////////////////////////////////////////////////////////////////////
  9 +/// \class ControlGetSpeed hantek/types.h
  10 +/// \brief The CONTROL_GETSPEED parser.
  11 +class ControlGetSpeed : public DataArray<uint8_t> {
  12 +public:
  13 + ControlGetSpeed();
  14 +
  15 + ConnectionSpeed getSpeed();
  16 +};
  17 +
  18 +
  19 +//////////////////////////////////////////////////////////////////////////////
  20 +/// \class ControlSetOffset hantek/types.h
  21 +/// \brief The CONTROL_SETOFFSET builder.
  22 +class ControlSetOffset : public DataArray<uint8_t> {
  23 +public:
  24 + ControlSetOffset();
  25 + ControlSetOffset(uint16_t channel1, uint16_t channel2, uint16_t trigger);
  26 +
  27 + uint16_t getChannel(unsigned int channel);
  28 + void setChannel(unsigned int channel, uint16_t offset);
  29 + uint16_t getTrigger();
  30 + void setTrigger(uint16_t level);
  31 +
  32 +private:
  33 + void init();
  34 +};
  35 +
  36 +//////////////////////////////////////////////////////////////////////////////
  37 +/// \class ControlSetRelays hantek/types.h
  38 +/// \brief The CONTROL_SETRELAYS builder.
  39 +class ControlSetRelays : public DataArray<uint8_t> {
  40 +public:
  41 + ControlSetRelays(bool ch1Below1V = false, bool ch1Below100mV = false,
  42 + bool ch1CouplingDC = false, bool ch2Below1V = false,
  43 + bool ch2Below100mV = false, bool ch2CouplingDC = false,
  44 + bool triggerExt = false);
  45 +
  46 + bool getBelow1V(unsigned int channel);
  47 + void setBelow1V(unsigned int channel, bool below);
  48 + bool getBelow100mV(unsigned int channel);
  49 + void setBelow100mV(unsigned int channel, bool below);
  50 + bool getCoupling(unsigned int channel);
  51 + void setCoupling(unsigned int channel, bool dc);
  52 + bool getTrigger();
  53 + void setTrigger(bool ext);
  54 +};
  55 +
  56 +//////////////////////////////////////////////////////////////////////////////
  57 +/// \class ControlSetVoltDIV_CH1 hantek/types.h
  58 +/// \brief The CONTROL_SETVOLTDIV_CH1 builder.
  59 +class ControlSetVoltDIV_CH1 : public DataArray<uint8_t> {
  60 +public:
  61 + ControlSetVoltDIV_CH1();
  62 + void setDiv(uint8_t val);
  63 +};
  64 +
  65 +//////////////////////////////////////////////////////////////////////////////
  66 +/// \class ControlSetVoltDIV_CH2 hantek/types.h
  67 +/// \brief The CONTROL_SETVOLTDIV_CH2 builder.
  68 +class ControlSetVoltDIV_CH2 : public DataArray<uint8_t> {
  69 +public:
  70 + ControlSetVoltDIV_CH2();
  71 + void setDiv(uint8_t val);
  72 +};
  73 +
  74 +//////////////////////////////////////////////////////////////////////////////
  75 +/// \class ControlSetTimeDIV hantek/types.h
  76 +/// \brief The CONTROL_SETTIMEDIV builder.
  77 +class ControlSetTimeDIV : public DataArray<uint8_t> {
  78 +public:
  79 + ControlSetTimeDIV();
  80 + void setDiv(uint8_t val);
  81 +};
  82 +
  83 +//////////////////////////////////////////////////////////////////////////////
  84 +/// \class ControlAcquireHardData hantek/types.h
  85 +/// \brief The CONTROL_ACQUIIRE_HARD_DATA builder.
  86 +class ControlAcquireHardData : public DataArray<uint8_t> {
  87 +public:
  88 + ControlAcquireHardData();
  89 +
  90 +private:
  91 + void init();
  92 +};
  93 +
  94 +}
  95 +
... ...
openhantek/src/hantek/controlbegin.cpp 0 โ†’ 100644
  1 +#include "controlbegin.h"
  2 +
  3 +//////////////////////////////////////////////////////////////////////////////
  4 +// class ControlBeginCommand
  5 +/// \brief Sets the command index to the given value.
  6 +/// \param index The CommandIndex for the command.
  7 +ControlBeginCommand::ControlBeginCommand(Hantek::BulkIndex index)
  8 + : DataArray<uint8_t>(10) {
  9 + this->init();
  10 +
  11 + this->setIndex(index);
  12 +}
  13 +
  14 +/// \brief Gets the command index.
  15 +/// \return The CommandIndex for the command.
  16 +Hantek::BulkIndex ControlBeginCommand::getIndex() { return (Hantek::BulkIndex)this->array[1]; }
  17 +
  18 +/// \brief Sets the command index to the given value.
  19 +/// \param index The new CommandIndex for the command.
  20 +void ControlBeginCommand::setIndex(Hantek::BulkIndex index) {
  21 + memset(&(this->array[1]), (uint8_t)index, 3);
  22 +}
  23 +
  24 +/// \brief Initialize the array to the needed values.
  25 +void ControlBeginCommand::init() { this->array[0] = 0x0f; }
  26 +
... ...
openhantek/src/hantek/controlbegin.h 0 โ†’ 100644
  1 +
  2 +// SPDX-License-Identifier: GPL-2.0+
  3 +
  4 +#pragma once
  5 +#include "utils/dataarray.h"
  6 +#include "definitions.h"
  7 +
  8 +//////////////////////////////////////////////////////////////////////////////
  9 +/// \class ControlBeginCommand hantek/types.h
  10 +/// \brief The CONTROL_BEGINCOMMAND builder.
  11 +class ControlBeginCommand : public DataArray<uint8_t> {
  12 +public:
  13 + ControlBeginCommand(Hantek::BulkIndex index = Hantek::COMMANDINDEX_0);
  14 +
  15 + Hantek::BulkIndex getIndex();
  16 + void setIndex(Hantek::BulkIndex index);
  17 +
  18 +private:
  19 + void init();
  20 +};
  21 +
... ...
openhantek/src/hantek/types.h renamed to openhantek/src/hantek/definitions.h
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file hantek/types.h
5   -/// \brief Declares types needed for the Hantek::Device class.
6   -//
7   -// Copyright (C) 2008, 2009 Oleg Khudyakov
8   -// prcoder@potrebitel.ru
9   -// Copyright (C) 2010 Oliver Haag
10   -// oliver.haag@gmail.com
11   -//
12   -// This program is free software: you can redistribute it and/or modify it
13   -// under the terms of the GNU General Public License as published by the Free
14   -// Software Foundation, either version 3 of the License, or (at your option)
15   -// any later version.
16   -//
17   -// This program is distributed in the hope that it will be useful, but WITHOUT
18   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20   -// more details.
21   -//
22   -// You should have received a copy of the GNU General Public License along with
23   -// this program. If not, see <http://www.gnu.org/licenses/>.
24   -//
25   -////////////////////////////////////////////////////////////////////////////////
  1 +// SPDX-License-Identifier: GPL-2.0+
26 2  
27   -#ifndef HANTEK_TYPES_H
28   -#define HANTEK_TYPES_H
  3 +#pragma once
29 4  
30 5 #include <stdint.h>
  6 +#include <QString>
31 7  
32   -#include "helper.h"
33   -
34   -#define HANTEK_VENDOR_ID 0x04b5 ///< VID for Hantek DSOs with loaded fw
35 8 #define HANTEK_EP_OUT 0x02 ///< OUT Endpoint for bulk transfers
36 9 #define HANTEK_EP_IN 0x86 ///< IN Endpoint for bulk transfers
37   -#define HANTEK_TIMEOUT 500 ///< Timeout for USB transfers in ms
38   -#define HANTEK_TIMEOUT_MULTI \
39   - 100 ///< Timeout for multi packet USB transfers in ms
40   -#define HANTEK_ATTEMPTS 3 ///< The number of transfer attempts
41   -#define HANTEK_ATTEMPTS_MULTI \
42   - 1 ///< The number of multi packet transfer attempts
43 10  
44 11 #define HANTEK_CHANNELS 2 ///< Number of physical channels
45 12 #define HANTEK_SPECIAL_CHANNELS 2 ///< Number of special channels
46 13  
  14 +#define MARKER_COUNT 2 ///< Number of markers
  15 +
  16 +/// \namespace Dso
  17 +/// \brief All DSO specific things for different modes and so on.
  18 +namespace Dso {
  19 + /// \enum ErrorCode hantek/control.h
  20 + /// \brief The return codes for device control methods.
  21 + enum ErrorCode {
  22 + ERROR_NONE = 0, ///< Successful operation
  23 + ERROR_CONNECTION = -1, ///< Device not connected or communication error
  24 + ERROR_UNSUPPORTED = -2, ///< Not supported by this device
  25 + ERROR_PARAMETER = -3 ///< Parameter out of range
  26 + };
  27 +
  28 +
  29 + /// \enum ChannelMode
  30 + /// \brief The channel display modes.
  31 + enum ChannelMode {
  32 + CHANNELMODE_VOLTAGE, ///< Standard voltage view
  33 + CHANNELMODE_SPECTRUM, ///< Spectrum view
  34 + CHANNELMODE_COUNT ///< The total number of modes
  35 + };
  36 +
  37 +
  38 + /// \enum GraphFormat
  39 + /// \brief The possible viewing formats for the graphs on the scope.
  40 + enum GraphFormat {
  41 + GRAPHFORMAT_TY, ///< The standard mode
  42 + GRAPHFORMAT_XY, ///< CH1 on X-axis, CH2 on Y-axis
  43 + GRAPHFORMAT_COUNT ///< The total number of formats
  44 + };
  45 +
  46 +
  47 + /// \enum Coupling
  48 + /// \brief The coupling modes for the channels.
  49 + enum Coupling {
  50 + COUPLING_AC, ///< Offset filtered out by condensator
  51 + COUPLING_DC, ///< No filtering
  52 + COUPLING_GND, ///< Channel is grounded
  53 + COUPLING_COUNT ///< The total number of coupling modes
  54 + };
  55 +
  56 +
  57 + /// \enum MathMode
  58 + /// \brief The different math modes for the math-channel.
  59 + enum MathMode {
  60 + MATHMODE_1ADD2, ///< Add the values of the channels
  61 + MATHMODE_1SUB2, ///< Subtract CH2 from CH1
  62 + MATHMODE_2SUB1, ///< Subtract CH1 from CH2
  63 + MATHMODE_COUNT ///< The total number of math modes
  64 + };
  65 +
  66 +
  67 + /// \enum TriggerMode
  68 + /// \brief The different triggering modes.
  69 + enum TriggerMode {
  70 + TRIGGERMODE_AUTO, ///< Automatic without trigger event
  71 + TRIGGERMODE_NORMAL, ///< Normal mode
  72 + TRIGGERMODE_SINGLE, ///< Stop after the first trigger event
  73 + TRIGGERMODE_SOFTWARE, ///< Software trigger mode
  74 + TRIGGERMODE_COUNT ///< The total number of modes
  75 + };
  76 +
  77 +
  78 + /// \enum Slope
  79 + /// \brief The slope that causes a trigger.
  80 + enum Slope {
  81 + SLOPE_POSITIVE, ///< From lower to higher voltage
  82 + SLOPE_NEGATIVE, ///< From higher to lower voltage
  83 + SLOPE_COUNT ///< Total number of trigger slopes
  84 + };
  85 +
  86 +
  87 + /// \enum WindowFunction
  88 + /// \brief The supported window functions.
  89 + /// These are needed for spectrum analysis and are applied to the sample values
  90 + /// before calculating the DFT.
  91 + enum WindowFunction {
  92 + WINDOW_RECTANGULAR, ///< Rectangular window (aka Dirichlet)
  93 + WINDOW_HAMMING, ///< Hamming window
  94 + WINDOW_HANN, ///< Hann window
  95 + WINDOW_COSINE, ///< Cosine window (aka Sine)
  96 + WINDOW_LANCZOS, ///< Lanczos window (aka Sinc)
  97 + WINDOW_BARTLETT, ///< Bartlett window (Endpoints == 0)
  98 + WINDOW_TRIANGULAR, ///< Triangular window (Endpoints != 0)
  99 + WINDOW_GAUSS, ///< Gauss window (simga = 0.4)
  100 + WINDOW_BARTLETTHANN, ///< Bartlett-Hann window
  101 + WINDOW_BLACKMAN, ///< Blackman window (alpha = 0.16)
  102 + // WINDOW_KAISER, ///< Kaiser window (alpha = 3.0)
  103 + WINDOW_NUTTALL, ///< Nuttall window, cont. first deriv.
  104 + WINDOW_BLACKMANHARRIS, ///< Blackman-Harris window
  105 + WINDOW_BLACKMANNUTTALL, ///< Blackman-Nuttall window
  106 + WINDOW_FLATTOP, ///< Flat top window
  107 + WINDOW_COUNT ///< Total number of window functions
  108 + };
  109 +
  110 +
  111 + /// \enum InterpolationMode
  112 + /// \brief The different interpolation modes for the graphs.
  113 + enum InterpolationMode {
  114 + INTERPOLATION_OFF = 0, ///< Just dots for each sample
  115 + INTERPOLATION_LINEAR, ///< Sample dots connected by lines
  116 + INTERPOLATION_SINC, ///< Smooth graph through the dots
  117 + INTERPOLATION_COUNT ///< Total number of interpolation modes
  118 + };
  119 +}
  120 +
47 121 ////////////////////////////////////////////////////////////////////////////////
48 122 /// \namespace Hantek hantek/types.h
49 123 /// \brief All %Hantek DSO device specific things.
50 124 namespace Hantek {
51   -//////////////////////////////////////////////////////////////////////////////
52   -/// \enum BulkCode hantek/types.h
53   -/// \brief All supported bulk commands.
54   -/// Indicies given in square brackets specify byte numbers in little endian
55   -/// format.
56   -enum BulkCode {
57   - /// BulkSetFilter [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO5200,
58   - /// ::MODEL_DSO5200A</em>]
59   - /// <p>
60   - /// This command sets channel and trigger filter:
61   - /// <table>
62   - /// <tr>
63   - /// <td>0x00</td>
64   - /// <td>0x00</td>
65   - /// <td>FilterBits</td>
66   - /// <td>0x00</td>
67   - /// <td>0x00</td>
68   - /// <td>0x00</td>
69   - /// <td>0x00</td>
70   - /// <td>0x00</td>
71   - /// </tr>
72   - /// </table>
73   - /// </p>
74   - /// <p>
75   - /// This command is used by the official %Hantek software, but doesn't seem
76   - /// to be used by the device.
77   - /// <p><br /></p>
78   - BULK_SETFILTER,
79   -
80   - /// BulkSetTriggerAndSamplerate [<em>::MODEL_DSO2090, ::MODEL_DSO2150</em>]
81   - /// <p>
82   - /// This command sets trigger and timebase:
83   - /// <table>
84   - /// <tr>
85   - /// <td>0x01</td>
86   - /// <td>0x00</td>
87   - /// <td>Tsr1Bits</td>
88   - /// <td>Tsr2Bits</td>
89   - /// <td>Downsampler[0]</td>
90   - /// <td>Downsampler[1]</td>
91   - /// </tr>
92   - /// </table>
93   - /// <table>
94   - /// <tr>
95   - /// <td>TriggerPosition[0]</td>
96   - /// <td>TriggerPosition[1]</td>
97   - /// <td>0x00</td>
98   - /// <td>0x00</td>
99   - /// <td>TriggerPosition[2]</td>
100   - /// <td>0x00</td>
101   - /// </tr>
102   - /// </table>
103   - /// </p>
104   - /// <p>
105   - /// The samplerate is set relative to the base samplerate by a divider or to
106   - /// a maximum samplerate.<br />
107   - /// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to
108   - /// the following values:
109   - /// <table>
110   - /// <tr>
111   - /// <td><b>Tsr1Bits.samplerateId</b></td><td>0</td><td>1</td><td>2</td><td>3</td>
112   - /// </tr>
113   - /// <tr>
114   - /// <td><b>Samplerate</b></td><td>Max</td><td>Base</td><td>Base /
115   - /// 2</td><td>Base / 5</td>
116   - /// </tr>
117   - /// </table>
118   - /// For higher divider values, the value can be set using the 16-bit value
119   - /// in the two Downsampler bytes. The value of Downsampler is given by:<br
120   - /// />
121   - /// <i>Downsampler = 1comp((Base / Samplerate / 2) - 2)</i><br />
122   - /// The Base samplerate is 50 MS/s for the DSO-2090 and DSO-2150. The Max
123   - /// samplerate is also 50 MS/s for the DSO-2090 and 75 MS/s for the
124   - /// DSO-2150.<br />
125   - /// When using fast rate mode the Base and Max samplerate is twice as fast.
126   - /// When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided
127   - /// by 1000.
128   - /// </p>
129   - /// <p>
130   - /// The TriggerPosition sets the position of the pretrigger in samples. The
131   - /// left side (0 %) is 0x77660 when using the small buffer and 0x78000 when
132   - /// using the large buffer.
133   - /// </p>
134   - /// <p><br /></p>
135   - BULK_SETTRIGGERANDSAMPLERATE,
136   -
137   - /// BulkForceTrigger [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
138   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
139   - /// <p>
140   - /// This command forces triggering:
141   - /// <table>
142   - /// <tr>
143   - /// <td>0x02</td>
144   - /// <td>0x00</td>
145   - /// </tr>
146   - /// </table>
147   - /// </p>
148   - /// <p><br /></p>
149   - BULK_FORCETRIGGER,
150   -
151   - /// BulkCaptureStart [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
152   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
153   - /// <p>
154   - /// This command starts to capture data:
155   - /// <table>
156   - /// <tr>
157   - /// <td>0x03</td>
158   - /// <td>0x00</td>
159   - /// </tr>
160   - /// </table>
161   - /// </p>
162   - /// <p><br /></p>
163   - BULK_STARTSAMPLING,
164   -
165   - /// BulkTriggerEnabled [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
166   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
167   - /// <p>
168   - /// This command sets the trigger:
169   - /// <table>
170   - /// <tr>
171   - /// <td>0x04</td>
172   - /// <td>0x00</td>
173   - /// </tr>
174   - /// </table>
175   - /// </p>
176   - /// <p><br /></p>
177   - BULK_ENABLETRIGGER,
178   -
179   - /// BulkGetData [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
180   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
181   - /// <p>
182   - /// This command reads data from the hardware:
183   - /// <table>
184   - /// <tr>
185   - /// <td>0x05</td>
186   - /// <td>0x00</td>
187   - /// </tr>
188   - /// </table>
189   - /// </p>
190   - /// <p>
191   - /// The oscilloscope returns the sample data, that will be split if it's
192   - /// larger than the IN endpoint packet length:
193   - /// <table>
194   - /// <tr>
195   - /// <td>Sample[0]</td>
196   - /// <td>...</td>
197   - /// <td>Sample[511]</td>
198   - /// </tr>
199   - /// <tr>
200   - /// <td>Sample[512]</td>
201   - /// <td>...</td>
202   - /// <td>Sample[1023]</td>
203   - /// </tr>
204   - /// <tr>
205   - /// <td>Sample[1024]</td>
206   - /// <td colspan="2">...</td>
207   - /// </tr>
208   - /// </table>
209   - /// Because of the 10 bit data model, the DSO-5200 transmits the two extra
210   - /// bits for each sample afterwards:
211   - /// <table>
212   - /// <tr>
213   - /// <td>Extra[0] << 2 | Extra[1]</td>
214   - /// <td>0</td>
215   - /// <td>Extra[2] << 2 | Extra[3]</td>
216   - /// <td>0</td>
217   - /// <td>...</td>
218   - /// <td>Extra[510] << 2 | Extra[511]</td>
219   - /// <td>0</td>
220   - /// </tr>
221   - /// <tr>
222   - /// <td>Extra[512] << 2 | Extra[513]</td>
223   - /// <td colspan="6">...</td>
224   - /// </tr>
225   - /// </table>
226   - /// </p>
227   - /// <p><br /></p>
228   - BULK_GETDATA,
229   -
230   - /// BulkGetCaptureState [<em>::MODEL_DSO2090, ::MODEL_DSO2150,
231   - /// ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
232   - /// <p>
233   - /// This command checks the capture state:
234   - /// <table>
235   - /// <tr>
236   - /// <td>0x06</td>
237   - /// <td>0x00</td>
238   - /// </tr>
239   - /// </table>
240   - /// </p>
241   - /// <p>
242   - /// The oscilloscope returns it's capture state and the trigger point. Not
243   - /// sure about this, looks like 248 16-bit words with nearly constant
244   - /// values. These can be converted to the start address of the data in the
245   - /// buffer (See Hantek::Control::calculateTriggerPoint):
246   - /// <table>
247   - /// <tr>
248   - /// <td>::CaptureState</td>
249   - /// <td>0x00</td>
250   - /// <td>TriggerPoint[0]</td>
251   - /// <td>TriggerPoint[1]</td>
252   - /// <td>...</td>
253   - /// </tr>
254   - /// </table>
255   - /// </p>
256   - /// <p><br /></p>
257   - BULK_GETCAPTURESTATE,
258   -
259   - /// BulkSetGain [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
260   - /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
261   - /// <p>
262   - /// This command sets the gain:
263   - /// <table>
264   - /// <tr>
265   - /// <td>0x07</td>
266   - /// <td>0x00</td>
267   - /// <td>GainBits</td>
268   - /// <td>0x00</td>
269   - /// <td>0x00</td>
270   - /// <td>0x00</td>
271   - /// <td>0x00</td>
272   - /// <td>0x00</td>
273   - /// </tr>
274   - /// </table>
275   - /// It is usually used in combination with ::CONTROL_SETRELAYS.
276   - /// </p>
277   - /// <p><br /></p>
278   - BULK_SETGAIN,
279   -
280   - /// BulkSetLogicalData [<em></em>]
281   - /// <p>
282   - /// This command sets the logical data (Not used in official %Hantek
283   - /// software):
284   - /// <table>
285   - /// <tr>
286   - /// <td>0x08</td>
287   - /// <td>0x00</td>
288   - /// <td>Data | 0x01</td>
289   - /// <td>0x00</td>
290   - /// <td>0x00</td>
291   - /// <td>0x00</td>
292   - /// <td>0x00</td>
293   - /// <td>0x00</td>
294   - /// </tr>
295   - /// </table>
296   - /// </p>
297   - /// <p><br /></p>
298   - BULK_SETLOGICALDATA,
299   -
300   - /// BulkGetLogicalData [<em></em>]
301   - /// <p>
302   - /// This command reads the logical data (Not used in official %Hantek
303   - /// software):
304   - /// <table>
305   - /// <tr>
306   - /// <td>0x09</td>
307   - /// <td>0x00</td>
308   - /// </tr>
309   - /// </table>
310   - /// </p>
311   - /// <p>
312   - /// The oscilloscope returns the logical data, which contains valid data in
313   - /// the first byte although it is 64 or 512 bytes long:
314   - /// <table>
315   - /// <tr>
316   - /// <td>Data</td>
317   - /// <td>...</td>
318   - /// </tr>
319   - /// </table>
320   - /// </p>
321   - /// <p><br /></p>
322   - BULK_GETLOGICALDATA,
323   -
324   - /// [<em></em>]
325   - /// <p>
326   - /// This command isn't used for any supported model:
327   - /// <table>
328   - /// <tr>
329   - /// <td>0x0a</td>
330   - /// <td>...</td>
331   - /// </tr>
332   - /// </table>
333   - /// </p>
334   - /// <p><br /></p>
335   - BULK_AUNKNOWN,
336   -
337   - /// BulkSetChannels2250 [<em>::MODEL_DSO2250</em>]
338   - /// <p>
339   - /// This command sets the activated channels for the DSO-2250:
340   - /// <table>
341   - /// <tr>
342   - /// <td>0x0b</td>
343   - /// <td>0x00</td>
344   - /// <td>BUsedChannels</td>
345   - /// <td>0x00</td>
346   - /// </tr>
347   - /// </table>
348   - /// </p>
349   - /// <p><br /></p>
350   - BULK_BSETCHANNELS,
351   -
352   - /// BulkSetTrigger2250 [<em>::MODEL_DSO2250</em>]
353   - /// <p>
354   - /// This command sets the trigger source for the DSO-2250:
355   - /// <table>
356   - /// <tr>
357   - /// <td>0x0c</td>
358   - /// <td>0x00</td>
359   - /// <td>CTriggerBits</td>
360   - /// <td>0x00</td>
361   - /// <td>0x00</td>
362   - /// <td>0x00</td>
363   - /// <td>0x00</td>
364   - /// <td>0x00</td>
365   - /// </tr>
366   - /// </table>
367   - /// </p>
368   - /// <p><br /></p>
369   - /// BulkSetSamplerate5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
370   - /// <p>
371   - /// This command sets the sampling rate for the DSO-5200:
372   - /// <table>
373   - /// <tr>
374   - /// <td>0x0c</td>
375   - /// <td>0x00</td>
376   - /// <td>SamplerateSlow[0]</td>
377   - /// <td>SamplerateSlow[1]</td>
378   - /// <td>SamplerateFast</td>
379   - /// <td>0x00</td>
380   - /// </tr>
381   - /// </table>
382   - /// </p>
383   - /// <p>
384   - /// The samplerate is set relative to the maximum sample rate by a divider
385   - /// that is set in SamplerateFast and the 16-bit value in the two
386   - /// SamplerateSlow bytes.<br />
387   - /// Without using fast rate mode, the samplerate is:<br />
388   - /// <i>Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 -
389   - /// SamplerateFast)</i><br />
390   - /// SamplerateBase is 100 MS/s for the DSO-5200 in normal mode and 200 MS/s
391   - /// in fast rate mode, the modifications regarding record length are the the
392   - /// same that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
393   - /// normal mode and 250 MS/s in fast rate mode, and is reached by setting
394   - /// SamplerateSlow = 0 and SamplerateFast = 4.
395   - /// </p>
396   - /// <p><br /></p>
397   - BULK_CSETTRIGGERORSAMPLERATE,
398   -
399   - /// BulkSetRecordLength2250 [<em>::MODEL_DSO2250</em>]
400   - /// <p>
401   - /// This command sets the record length for the DSO-2250:
402   - /// <table>
403   - /// <tr>
404   - /// <td>0x0d</td>
405   - /// <td>0x00</td>
406   - /// <td>::RecordLengthId</td>
407   - /// <td>0x00</td>
408   - /// </tr>
409   - /// </table>
410   - /// </p>
411   - /// <p><br /></p>
412   - /// BulkSetBuffer5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
413   - /// <p>
414   - /// This command sets the trigger position and record length for the
415   - /// DSO-5200:
416   - /// <table>
417   - /// <tr>
418   - /// <td>0x0d</td>
419   - /// <td>0x00</td>
420   - /// <td>TriggerPositionPre[0]</td>
421   - /// <td>TriggerPositionPre[1]</td>
422   - /// <td>::DTriggerPositionUsed</td>
423   - /// </tr>
424   - /// </table>
425   - /// <table>
426   - /// <tr>
427   - /// <td>0xff</td>
428   - /// <td>TriggerPositionPost[0]</td>
429   - /// <td>TriggerPositionPost[1]</td>
430   - /// <td>DBufferBits</td>
431   - /// <td>0xff</td>
432   - /// </tr>
433   - /// </table>
434   - /// </p>
435   - /// <p>
436   - /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
437   - /// position. Both values have a range from 0xd7ff (0xc7ff for 14 kiS
438   - /// buffer) to 0xfffe. On the left side (0 %) the TriggerPositionPre value
439   - /// is minimal, on the right side (100 %) it is maximal. The
440   - /// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
441   - /// </p>
442   - /// <p><br /></p>
443   - BULK_DSETBUFFER,
444   -
445   - /// BulkSetSamplerate2250 [<em>::MODEL_DSO2250</em>]
446   - /// <p>
447   - /// This command sets the samplerate:
448   - /// <table>
449   - /// <tr>
450   - /// <td>0x0e</td>
451   - /// <td>0x00</td>
452   - /// <td>ESamplerateBits</td>
453   - /// <td>0x00</td>
454   - /// <td>Samplerate[0]</td>
455   - /// <td>Samplerate[1]</td>
456   - /// <td>0x00</td>
457   - /// <td>0x00</td>
458   - /// </tr>
459   - /// </table>
460   - /// </p>
461   - /// <p>
462   - /// The downsampler can be activated by setting ESamplerateBits.downsampling
463   - /// = 1. If this is the case, the value of Downsampler is given by:<br />
464   - /// <i>Downsampler = 1comp((Base / Samplerate) - 2)</i><br />
465   - /// Base is 100 MS/s for the DSO-2250 in standard mode and 200 MS/s in fast
466   - /// rate mode, the modifications regarding record length are the the same
467   - /// that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
468   - /// standard mode and 250 MS/s in fast rate mode and is achieved by setting
469   - /// ESamplerateBits.downsampling = 0.
470   - /// </p>
471   - /// <p><br /></p>
472   - /// BulkSetTrigger5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
473   - /// <p>
474   - /// This command sets the channel and trigger settings:
475   - /// <table>
476   - /// <tr>
477   - /// <td>0x0e</td>
478   - /// <td>0x00</td>
479   - /// <td>ETsrBits</td>
480   - /// <td>0x00</td>
481   - /// <td>0x00</td>
482   - /// <td>0x00</td>
483   - /// <td>0x00</td>
484   - /// <td>0x00</td>
485   - /// </tr>
486   - /// </table>
487   - /// </p>
488   - /// <p><br /></p>
489   - BULK_ESETTRIGGERORSAMPLERATE,
490   -
491   - /// BulkSetBuffer2250 [<em>::MODEL_DSO2250</em>]
492   - /// <p>
493   - /// This command sets the trigger position and buffer configuration for the
494   - /// DSO-2250:
495   - /// <table>
496   - /// <tr>
497   - /// <td>0x0f</td>
498   - /// <td>0x00</td>
499   - /// <td>TriggerPositionPost[0]</td>
500   - /// <td>TriggerPositionPost[1]</td>
501   - /// <td>TriggerPositionPost[2]</td>
502   - /// <td>0x00</td>
503   - /// </tr>
504   - /// </table>
505   - /// <table>
506   - /// <tr>
507   - /// <td>TriggerPositionPre[0]</td>
508   - /// <td>TriggerPositionPre[1]</td>
509   - /// <td>TriggerPositionPre[2]</td>
510   - /// <td>0x00</td>
511   - /// <td>0x00</td>
512   - /// <td>0x00</td>
513   - /// </tr>
514   - /// </table>
515   - /// </p>
516   - /// <p>
517   - /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
518   - /// position. Both values have a range from 0x7d800 (0x00000 for 512 kiS
519   - /// buffer) to 0x7ffff. On the left side (0 %) the TriggerPositionPre value
520   - /// is minimal, on the right side (100 %) it is maximal. The
521   - /// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
522   - /// </p>
523   - /// <p><br /></p>
524   - BULK_FSETBUFFER,
525   -
526   - BULK_COUNT
527   -};
528   -
529   -//////////////////////////////////////////////////////////////////////////////
530   -/// \enum ControlCode hantek/types.h
531   -/// \brief All supported control commands.
532   -enum ControlCode {
533   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
534   - /// ::MODEL_DSO5200A]</em>
535   - /// <p>
536   - /// The 0xa2 control read/write command gives access to a ::ControlValue.
537   - /// </p>
538   - /// <p><br /></p>
539   - CONTROL_VALUE = 0xa2,
540   -
541   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
542   - /// ::MODEL_DSO5200A]</em>
543   - /// <p>
544   - /// The 0xb2 control read command gets the speed level of the USB
545   - /// connection:
546   - /// <table>
547   - /// <tr>
548   - /// <td>::ConnectionSpeed</td>
549   - /// <td>0x00</td>
550   - /// <td>0x00</td>
551   - /// <td>0x00</td>
552   - /// <td>0x00</td>
553   - /// <td>0x00</td>
554   - /// <td>0x00</td>
555   - /// <td>0x00</td>
556   - /// <td>0x00</td>
557   - /// <td>0x00</td>
558   - /// </tr>
559   - /// </table>
560   - /// </p>
561   - /// <p><br /></p>
562   - CONTROL_GETSPEED = 0xb2,
563   -
564   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
565   - /// ::MODEL_DSO5200A]</em>
566   - /// <p>
567   - /// The 0xb3 control write command is sent before any bulk command:
568   - /// <table>
569   - /// <tr>
570   - /// <td>0x0f</td>
571   - /// <td>::BulkIndex</td>
572   - /// <td>::BulkIndex</td>
573   - /// <td>::BulkIndex</td>
574   - /// <td>0x00</td>
575   - /// <td>0x00</td>
576   - /// <td>0x00</td>
577   - /// <td>0x00</td>
578   - /// <td>0x00</td>
579   - /// <td>0x00</td>
580   - /// </tr>
581   - /// </table>
582   - /// </p>
583   - /// <p><br /></p>
584   - CONTROL_BEGINCOMMAND = 0xb3,
585   -
586   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
587   - /// ::MODEL_DSO5200A]</em>
588   - /// <p>
589   - /// The 0xb4 control write command sets the channel offsets:
590   - /// <table>
591   - /// <tr>
592   - /// <td>Ch1Offset[1]</td>
593   - /// <td>Ch1Offset[0]</td>
594   - /// <td>Ch2Offset[1]</td>
595   - /// <td>Ch2Offset[0]</td>
596   - /// <td>TriggerOffset[1]</td>
597   - /// <td>TriggerOffset[0]</td>
598   - /// </tr>
599   - /// </table>
600   - /// <table>
601   - /// <tr>
602   - /// <td>0x00</td>
603   - /// <td>0x00</td>
604   - /// <td>0x00</td>
605   - /// <td>0x00</td>
606   - /// <td>0x00</td>
607   - /// <td>0x00</td>
608   - /// <td>0x00</td>
609   - /// <td>0x00</td>
610   - /// <td>0x00</td>
611   - /// <td>0x00</td>
612   - /// <td>0x00</td>
613   - /// </tr>
614   - /// </table>
615   - /// </p>
616   - /// <p><br /></p>
617   - CONTROL_SETOFFSET = 0xb4,
618   -
619   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
620   - /// ::MODEL_DSO5200A]</em>
621   - /// <p>
622   - /// The 0xb5 control write command sets the internal relays:
623   - /// <table>
624   - /// <tr>
625   - /// <td>0x00</td>
626   - /// <td>0x04 ^ (Ch1Gain < 1 V)</td>
627   - /// <td>0x08 ^ (Ch1Gain < 100 mV)</td>
628   - /// <td>0x02 ^ (Ch1Coupling == DC)</td>
629   - /// </tr>
630   - /// </table>
631   - /// <table>
632   - /// <tr>
633   - /// <td>0x20 ^ (Ch2Gain < 1 V)</td>
634   - /// <td>0x40 ^ (Ch2Gain < 100 mV)</td>
635   - /// <td>0x10 ^ (Ch2Coupling == DC)</td>
636   - /// <td>0x01 ^ (Trigger == EXT)</td>
637   - /// </tr>
638   - /// </table>
639   - /// <table>
640   - /// <tr>
641   - /// <td>0x00</td>
642   - /// <td>0x00</td>
643   - /// <td>0x00</td>
644   - /// <td>0x00</td>
645   - /// <td>0x00</td>
646   - /// <td>0x00</td>
647   - /// <td>0x00</td>
648   - /// <td>0x00</td>
649   - /// <td>0x00</td>
650   - /// </tr>
651   - /// </table>
652   - /// </p>
653   - /// <p>
654   - /// The limits are <= instead of < for the 10 bit models, since those
655   - /// support voltages up to 10 V.
656   - /// </p>
657   - /// <p><br /></p>
658   - CONTROL_SETRELAYS = 0xb5,
659   -
660   - CONTROL_SETVOLTDIV_CH1 = 0xe0,
661   - CONTROL_SETVOLTDIV_CH2 = 0xe1,
662   - CONTROL_SETTIMEDIV = 0xe2,
663   - CONTROL_ACQUIIRE_HARD_DATA = 0xe3
664   -};
665   -
666   -//////////////////////////////////////////////////////////////////////////////
667   -/// \enum ControlValue hantek/types.h
668   -/// \brief All supported values for control commands.
669   -enum ControlValue {
670   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
671   - /// ::MODEL_DSO5200A]</em>
672   - /// <p>
673   - /// Value 0x08 is the calibration data for the channels offsets. It holds the
674   - /// offset value for the top and bottom of the scope screen for every gain
675   - /// step on every channel. The data is stored as a three-dimensional array:<br
676   - /// />
677   - /// <i>channelLevels[channel][GainId][::LevelOffset]</i>
678   - /// </p>
679   - /// <p><br /></p>
680   - VALUE_OFFSETLIMITS = 0x08,
681   -
682   - /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
683   - /// ::MODEL_DSO5200A]</em>
684   - /// <p>
685   - /// Value 0x0a is the address of the device. It has a length of one byte.
686   - /// </p>
687   - /// <p><br /></p>
688   - VALUE_DEVICEADDRESS = 0x0a,
689   -
690   - /// <em>[::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A]</em>
691   - /// <p>
692   - /// Value 0x60 is the calibration data for the fast rate mode on the DSO-2250,
693   - /// DSO-5200 and DSO-5200A. It's used to correct the level differences between
694   - /// the two merged channels to avoid deterministic noise.
695   - /// </p>
696   - /// <p><br /></p>
697   - VALUE_FASTRATECALIBRATION = 0x60,
698   -
699   - /// <em>[::MODEL_DSO5200, ::MODEL_DSO5200A]</em>
700   - /// <p>
701   - /// Value 0x70 contains correction values for the ETS functionality of the
702   - /// DSO-5200 and DSO-5200A.
703   - /// </p>
704   - /// <p><br /></p>
705   - VALUE_ETSCORRECTION = 0x70
706   -};
707   -
708   -//////////////////////////////////////////////////////////////////////////////
709   -/// \enum Model hantek/types.h
710   -/// \brief All supported Hantek DSO models.
711   -enum Model {
712   - MODEL_UNKNOWN = -1, ///< Unknown model
713   - MODEL_DSO2090, ///< %Hantek DSO-2090 USB
714   - MODEL_DSO2150, ///< %Hantek DSO-2150 USB
715   - MODEL_DSO2250, ///< %Hantek DSO-2250 USB
716   - MODEL_DSO5200, ///< %Hantek DSO-5200 USB
717   - MODEL_DSO5200A, ///< %Hantek DSO-5200A USB
718   - MODEL_DSO6022BE, ///< %Hantek6022BE USB
719   - MODEL_COUNT
720   -};
721   -
722   -//////////////////////////////////////////////////////////////////////////////
723   -/// \enum ConnectionSpeed hantek/types.h
724   -/// \brief The speed level of the USB connection.
725   -enum ConnectionSpeed {
726   - CONNECTION_FULLSPEED = 0, ///< FullSpeed USB, 64 byte bulk transfers
727   - CONNECTION_HIGHSPEED = 1 ///< HighSpeed USB, 512 byte bulk transfers
728   -};
729   -
730   -//////////////////////////////////////////////////////////////////////////////
731   -/// \enum UsedChannels hantek/types.h
732   -/// \brief The enabled channels.
733   -enum UsedChannels {
734   - USED_CH1, ///< Only channel 1 is activated
735   - USED_CH2, ///< Only channel 2 is activated
736   - USED_CH1CH2, ///< Channel 1 and 2 are both activated
737   - USED_NONE ///< No channels are activated
738   -};
739   -
740   -//////////////////////////////////////////////////////////////////////////////
741   -/// \enum TriggerSource hantek/types.h
742   -/// \brief The possible trigger sources.
743   -enum TriggerSource {
744   - TRIGGER_CH2,
745   - TRIGGER_CH1,
746   - TRIGGER_ALT,
747   - TRIGGER_EXT,
748   - TRIGGER_EXT10
749   -};
750   -
751   -//////////////////////////////////////////////////////////////////////////////
752   -/// \enum RecordLengthId hantek/types.h
753   -/// \brief The size id for CommandSetTriggerAndSamplerate.
754   -enum RecordLengthId {
755   - RECORDLENGTHID_ROLL = 0, ///< Used for the roll mode
756   - RECORDLENGTHID_SMALL, ///< The standard buffer with 10240 samples
757   - RECORDLENGTHID_LARGE ///< The large buffer, 32768 samples (14336 for DSO-5200)
758   -};
759   -
760   -//////////////////////////////////////////////////////////////////////////////
761   -/// \enum CaptureState hantek/types.h
762   -/// \brief The different capture states which the oscilloscope returns.
763   -enum CaptureState {
764   - CAPTURE_WAITING = 0, ///< The scope is waiting for a trigger event
765   - CAPTURE_SAMPLING = 1, ///< The scope is sampling data after triggering
766   - CAPTURE_READY = 2, ///< Sampling data is available (DSO-2090/DSO-2150)
767   - CAPTURE_READY2250 = 3, ///< Sampling data is available (DSO-2250)
768   - CAPTURE_READY5200 = 7 ///< Sampling data is available (DSO-5200/DSO-5200A)
769   -};
770   -
771   -//////////////////////////////////////////////////////////////////////////////
772   -/// \enum BulkIndex hantek/types.h
773   -/// \brief Can be set by CONTROL_BEGINCOMMAND, maybe it allows multiple commands
774   -/// at the same time?
775   -enum BulkIndex {
776   - COMMANDINDEX_0 = 0x03, ///< Used most of the time
777   - COMMANDINDEX_1 = 0x0a,
778   - COMMANDINDEX_2 = 0x09,
779   - COMMANDINDEX_3 = 0x01, ///< Used for ::BULK_SETTRIGGERANDSAMPLERATE sometimes
780   - COMMANDINDEX_4 = 0x02,
781   - COMMANDINDEX_5 = 0x08
782   -};
783   -
784   -//////////////////////////////////////////////////////////////////////////////
785   -/// \enum LevelOffset hantek/types.h
786   -/// \brief The array indicies for the CalibrationData.
787   -enum LevelOffset {
788   - OFFSET_START, ///< The channel level at the bottom of the scope
789   - OFFSET_END, ///< The channel level at the top of the scope
790   - OFFSET_COUNT
791   -};
792   -
793   -//////////////////////////////////////////////////////////////////////////////
794   -/// \enum BUsedChannels hantek/types.h
795   -/// \brief The enabled channels for the DSO-2250.
796   -enum BUsedChannels {
797   - BUSED_CH1, ///< Only channel 1 is activated
798   - BUSED_NONE, ///< No channels are activated
799   - BUSED_CH1CH2, ///< Channel 1 and 2 are both activated
800   - BUSED_CH2 ///< Only channel 2 is activated
801   -};
802   -
803   -//////////////////////////////////////////////////////////////////////////////
804   -/// \enum DTriggerPositionUsed hantek/types.h
805   -/// \brief The trigger position states for the 0x0d command.
806   -enum DTriggerPositionUsed {
807   - DTRIGGERPOSITION_OFF = 0, ///< Used for Roll mode
808   - DTRIGGERPOSITION_ON = 7 ///< Used for normal operation
809   -};
810   -
811   -//////////////////////////////////////////////////////////////////////////////
812   -/// \struct FilterBits hantek/types.h
813   -/// \brief The bits for BULK_SETFILTER.
814   -struct FilterBits {
815   - uint8_t channel1 : 1; ///< Set to true when channel 1 isn't used
816   - uint8_t channel2 : 1; ///< Set to true when channel 2 isn't used
817   - uint8_t trigger : 1; ///< Set to true when trigger isn't used
818   - uint8_t reserved : 5; ///< Unused bits
819   -};
820   -
821   -//////////////////////////////////////////////////////////////////////////////
822   -/// \struct GainBits hantek/types.h
823   -/// \brief The gain bits for BULK_SETGAIN.
824   -struct GainBits {
825   - uint8_t channel1 : 2; ///< Gain for CH1, 0 = 1e* V, 1 = 2e*, 2 = 5e*
826   - uint8_t channel2 : 2; ///< Gain for CH1, 0 = 1e* V, 1 = 2e*, 2 = 5e*
827   - uint8_t reserved : 4; ///< Unused bits
828   -};
829   -
830   -//////////////////////////////////////////////////////////////////////////////
831   -/// \struct Tsr1Bits hantek/types.h
832   -/// \brief Trigger and samplerate bits (Byte 1).
833   -struct Tsr1Bits {
834   - uint8_t triggerSource : 2; ///< The trigger source, see Hantek::TriggerSource
835   - uint8_t recordLength : 3; ///< See ::RecordLengthId
836   - uint8_t samplerateId : 2; ///< Samplerate ID when downsampler is disabled
837   - uint8_t downsamplingMode : 1; ///< true, if Downsampler is used
838   -};
839   -
840   -//////////////////////////////////////////////////////////////////////////////
841   -/// \struct Tsr2Bits hantek/types.h
842   -/// \brief Trigger and samplerate bits (Byte 2).
843   -struct Tsr2Bits {
844   - uint8_t usedChannels : 2; ///< Used channels, see Hantek::UsedChannels
845   - uint8_t fastRate : 1; ///< true, if one channels uses all buffers
846   - uint8_t triggerSlope : 1; ///< The trigger slope, see Dso::Slope, inverted
847   - ///when Tsr1Bits.samplerateFast is uneven
848   - uint8_t reserved : 4; ///< Unused bits
849   -};
850   -
851   -//////////////////////////////////////////////////////////////////////////////
852   -/// \struct CTriggerBits hantek/types.h
853   -/// \brief Trigger bits for 0x0c command.
854   -struct CTriggerBits {
855   - uint8_t triggerSource : 2; ///< The trigger source, see Hantek::TriggerSource
856   - uint8_t triggerSlope : 1; ///< The trigger slope, see Dso::Slope
857   - uint8_t reserved : 5; ///< Unused bits
858   -};
859   -
860   -//////////////////////////////////////////////////////////////////////////////
861   -/// \struct DBufferBits hantek/types.h
862   -/// \brief Buffer mode bits for 0x0d command.
863   -struct DBufferBits {
864   - uint8_t triggerPositionUsed : 3; ///< See ::DTriggerPositionUsed
865   - uint8_t recordLength : 3; ///< See ::RecordLengthId
866   - uint8_t reserved : 2; ///< Unused bits
867   -};
868   -
869   -//////////////////////////////////////////////////////////////////////////////
870   -/// \struct ESamplerateBits hantek/types.h
871   -/// \brief Samplerate bits for DSO-2250 0x0e command.
872   -struct ESamplerateBits {
873   - uint8_t fastRate : 1; ///< false, if one channels uses all buffers
874   - uint8_t downsampling : 1; ///< true, if the downsampler is activated
875   - uint8_t reserved : 4; ///< Unused bits
876   -};
877   -
878   -//////////////////////////////////////////////////////////////////////////////
879   -/// \struct ETsrBits hantek/types.h
880   -/// \brief Trigger and samplerate bits for DSO-5200/DSO-5200A 0x0e command.
881   -struct ETsrBits {
882   - uint8_t fastRate : 1; ///< false, if one channels uses all buffers
883   - uint8_t usedChannels : 2; ///< Used channels, see Hantek::UsedChannels
884   - uint8_t triggerSource : 2; ///< The trigger source, see Hantek::TriggerSource
885   - uint8_t triggerSlope : 2; ///< The trigger slope, see Dso::Slope
886   - uint8_t triggerPulse : 1; ///< Pulses are causing trigger events
887   -};
888   -
889   -//////////////////////////////////////////////////////////////////////////////
890   -/// \class BulkSetFilter hantek/types.h
891   -/// \brief The BULK_SETFILTER builder.
892   -class BulkSetFilter : public Helper::DataArray<uint8_t> {
893   -public:
894   - BulkSetFilter();
895   - BulkSetFilter(bool channel1, bool channel2, bool trigger);
896   -
897   - bool getChannel(unsigned int channel);
898   - void setChannel(unsigned int channel, bool filtered);
899   - bool getTrigger();
900   - void setTrigger(bool filtered);
901   -
902   -private:
903   - void init();
904   -};
905   -
906   -//////////////////////////////////////////////////////////////////////////////
907   -/// \class BulkSetTriggerAndSamplerate hantek/types.h
908   -/// \brief The BULK_SETTRIGGERANDSAMPLERATE builder.
909   -class BulkSetTriggerAndSamplerate : public Helper::DataArray<uint8_t> {
910   -public:
911   - BulkSetTriggerAndSamplerate();
912   - BulkSetTriggerAndSamplerate(uint16_t downsampler, uint32_t triggerPosition,
913   - uint8_t triggerSource = 0,
914   - uint8_t recordLength = 0,
915   - uint8_t samplerateId = 0,
916   - bool downsamplingMode = true,
917   - uint8_t usedChannels = 0, bool fastRate = false,
918   - uint8_t triggerSlope = 0);
919   -
920   - uint8_t getTriggerSource();
921   - void setTriggerSource(uint8_t value);
922   - uint8_t getRecordLength();
923   - void setRecordLength(uint8_t value);
924   - uint8_t getSamplerateId();
925   - void setSamplerateId(uint8_t value);
926   - bool getDownsamplingMode();
927   - void setDownsamplingMode(bool downsampling);
928   - uint8_t getUsedChannels();
929   - void setUsedChannels(uint8_t value);
930   - bool getFastRate();
931   - void setFastRate(bool fastRate);
932   - uint8_t getTriggerSlope();
933   - void setTriggerSlope(uint8_t slope);
934   - uint16_t getDownsampler();
935   - void setDownsampler(uint16_t downsampler);
936   - uint32_t getTriggerPosition();
937   - void setTriggerPosition(uint32_t position);
938   -
939   -private:
940   - void init();
941   -};
942   -
943   -//////////////////////////////////////////////////////////////////////////////
944   -/// \class BulkForceTrigger hantek/types.h
945   -/// \brief The BULK_FORCETRIGGER builder.
946   -class BulkForceTrigger : public Helper::DataArray<uint8_t> {
947   -public:
948   - BulkForceTrigger();
949   -};
950   -
951   -//////////////////////////////////////////////////////////////////////////////
952   -/// \class BulkCaptureStart hantek/types.h
953   -/// \brief The BULK_CAPTURESTART builder.
954   -class BulkCaptureStart : public Helper::DataArray<uint8_t> {
955   -public:
956   - BulkCaptureStart();
957   -};
958   -
959   -//////////////////////////////////////////////////////////////////////////////
960   -/// \class BulkTriggerEnabled hantek/types.h
961   -/// \brief The BULK_TRIGGERENABLED builder.
962   -class BulkTriggerEnabled : public Helper::DataArray<uint8_t> {
963   -public:
964   - BulkTriggerEnabled();
965   -};
966   -
967   -//////////////////////////////////////////////////////////////////////////////
968   -/// \class BulkGetData hantek/types.h
969   -/// \brief The BULK_GETDATA builder.
970   -class BulkGetData : public Helper::DataArray<uint8_t> {
971   -public:
972   - BulkGetData();
973   -};
974   -
975   -//////////////////////////////////////////////////////////////////////////////
976   -/// \class BulkGetCaptureState hantek/types.h
977   -/// \brief The BULK_GETCAPTURESTATE builder.
978   -class BulkGetCaptureState : public Helper::DataArray<uint8_t> {
979   -public:
980   - BulkGetCaptureState();
981   -};
982   -
983   -//////////////////////////////////////////////////////////////////////////////
984   -/// \class BulkResponseGetCaptureState hantek/types.h
985   -/// \brief The parser for the BULK_GETCAPTURESTATE response.
986   -class BulkResponseGetCaptureState : public Helper::DataArray<uint8_t> {
987   -public:
988   - BulkResponseGetCaptureState();
989   -
990   - CaptureState getCaptureState();
991   - unsigned int getTriggerPoint();
992   -};
993   -
994   -//////////////////////////////////////////////////////////////////////////////
995   -/// \class BulkSetGain hantek/types.h
996   -/// \brief The BULK_SETGAIN builder.
997   -class BulkSetGain : public Helper::DataArray<uint8_t> {
998   -public:
999   - BulkSetGain();
1000   - BulkSetGain(uint8_t channel1, uint8_t channel2);
1001   -
1002   - uint8_t getGain(unsigned int channel);
1003   - void setGain(unsigned int channel, uint8_t value);
1004   -
1005   -private:
1006   - void init();
1007   -};
1008   -
1009   -//////////////////////////////////////////////////////////////////////////////
1010   -/// \class BulkSetLogicalData hantek/types.h
1011   -/// \brief The BULK_SETLOGICALDATA builder.
1012   -class BulkSetLogicalData : public Helper::DataArray<uint8_t> {
1013   -public:
1014   - BulkSetLogicalData();
1015   - BulkSetLogicalData(uint8_t data);
1016   -
1017   - uint8_t getData();
1018   - void setData(uint8_t data);
1019   -
1020   -private:
1021   - void init();
1022   -};
1023   -
1024   -//////////////////////////////////////////////////////////////////////////////
1025   -/// \class BulkGetLogicalData hantek/types.h
1026   -/// \brief The BULK_GETLOGICALDATA builder.
1027   -class BulkGetLogicalData : public Helper::DataArray<uint8_t> {
1028   -public:
1029   - BulkGetLogicalData();
1030   -};
1031   -
1032   -//////////////////////////////////////////////////////////////////////////////
1033   -/// \class BulkSetChannels2250 hantek/types.h
1034   -/// \brief The DSO-2250 BULK_BSETFILTER builder.
1035   -class BulkSetChannels2250 : public Helper::DataArray<uint8_t> {
1036   -public:
1037   - BulkSetChannels2250();
1038   - BulkSetChannels2250(uint8_t usedChannels);
1039   -
1040   - uint8_t getUsedChannels();
1041   - void setUsedChannels(uint8_t value);
1042   -
1043   -private:
1044   - void init();
1045   -};
1046   -
1047   -//////////////////////////////////////////////////////////////////////////////
1048   -/// \class BulkSetTrigger2250 hantek/types.h
1049   -/// \brief The DSO-2250 BULK_CSETTRIGGERORSAMPLERATE builder.
1050   -class BulkSetTrigger2250 : public Helper::DataArray<uint8_t> {
1051   -public:
1052   - BulkSetTrigger2250();
1053   - BulkSetTrigger2250(uint8_t triggerSource, uint8_t triggerSlope);
1054   -
1055   - uint8_t getTriggerSource();
1056   - void setTriggerSource(uint8_t value);
1057   - uint8_t getTriggerSlope();
1058   - void setTriggerSlope(uint8_t slope);
1059   -
1060   -private:
1061   - void init();
1062   -};
1063   -
1064   -//////////////////////////////////////////////////////////////////////////////
1065   -/// \class BulkSetSamplerate5200 hantek/types.h
1066   -/// \brief The DSO-5200/DSO-5200A BULK_CSETTRIGGERORSAMPLERATE builder.
1067   -class BulkSetSamplerate5200 : public Helper::DataArray<uint8_t> {
1068   -public:
1069   - BulkSetSamplerate5200();
1070   - BulkSetSamplerate5200(uint16_t samplerateSlow, uint8_t samplerateFast);
1071   -
1072   - uint8_t getSamplerateFast();
1073   - void setSamplerateFast(uint8_t value);
1074   - uint16_t getSamplerateSlow();
1075   - void setSamplerateSlow(uint16_t samplerate);
1076   -
1077   -private:
1078   - void init();
1079   -};
1080   -
1081   -//////////////////////////////////////////////////////////////////////////////
1082   -/// \class BulkSetRecordLength2250 hantek/types.h
1083   -/// \brief The DSO-2250 BULK_DSETBUFFER builder.
1084   -class BulkSetRecordLength2250 : public Helper::DataArray<uint8_t> {
1085   -public:
1086   - BulkSetRecordLength2250();
1087   - BulkSetRecordLength2250(uint8_t recordLength);
1088   -
1089   - uint8_t getRecordLength();
1090   - void setRecordLength(uint8_t value);
1091   -
1092   -private:
1093   - void init();
1094   -};
1095   -
1096   -//////////////////////////////////////////////////////////////////////////////
1097   -/// \class BulkSetBuffer5200 hantek/types.h
1098   -/// \brief The DSO-5200/DSO-5200A BULK_DSETBUFFER builder.
1099   -class BulkSetBuffer5200 : public Helper::DataArray<uint8_t> {
1100   -public:
1101   - BulkSetBuffer5200();
1102   - BulkSetBuffer5200(uint16_t triggerPositionPre, uint16_t triggerPositionPost,
1103   - uint8_t usedPre = 0, uint8_t usedPost = 0,
1104   - uint8_t recordLength = 0);
1105   -
1106   - uint16_t getTriggerPositionPre();
1107   - void setTriggerPositionPre(uint16_t value);
1108   - uint16_t getTriggerPositionPost();
1109   - void setTriggerPositionPost(uint16_t value);
1110   - uint8_t getUsedPre();
1111   - void setUsedPre(uint8_t value);
1112   - uint8_t getUsedPost();
1113   - void setUsedPost(uint8_t value);
1114   - uint8_t getRecordLength();
1115   - void setRecordLength(uint8_t value);
1116   -
1117   -private:
1118   - void init();
1119   -};
1120   -
1121   -//////////////////////////////////////////////////////////////////////////////
1122   -/// \class BulkSetSamplerate2250 hantek/types.h
1123   -/// \brief The DSO-2250 BULK_ESETTRIGGERORSAMPLERATE builder.
1124   -class BulkSetSamplerate2250 : public Helper::DataArray<uint8_t> {
1125   -public:
1126   - BulkSetSamplerate2250();
1127   - BulkSetSamplerate2250(bool fastRate, bool downsampling = false,
1128   - uint16_t samplerate = 0);
1129   -
1130   - bool getFastRate();
1131   - void setFastRate(bool fastRate);
1132   - bool getDownsampling();
1133   - void setDownsampling(bool downsampling);
1134   - uint16_t getSamplerate();
1135   - void setSamplerate(uint16_t samplerate);
1136   -
1137   -private:
1138   - void init();
1139   -};
1140   -
1141   -//////////////////////////////////////////////////////////////////////////////
1142   -/// \class BulkSetTrigger5200 hantek/types.h
1143   -/// \brief The DSO-5200/DSO-5200A BULK_ESETTRIGGERORSAMPLERATE builder.
1144   -class BulkSetTrigger5200 : public Helper::DataArray<uint8_t> {
1145   -public:
1146   - BulkSetTrigger5200();
1147   - BulkSetTrigger5200(uint8_t triggerSource, uint8_t usedChannels,
1148   - bool fastRate = false, uint8_t triggerSlope = 0,
1149   - uint8_t triggerPulse = 0);
1150   -
1151   - uint8_t getTriggerSource();
1152   - void setTriggerSource(uint8_t value);
1153   - uint8_t getUsedChannels();
1154   - void setUsedChannels(uint8_t value);
1155   - bool getFastRate();
1156   - void setFastRate(bool fastRate);
1157   - uint8_t getTriggerSlope();
1158   - void setTriggerSlope(uint8_t slope);
1159   - bool getTriggerPulse();
1160   - void setTriggerPulse(bool pulse);
1161   -
1162   -private:
1163   - void init();
1164   -};
1165   -
1166   -//////////////////////////////////////////////////////////////////////////////
1167   -/// \class BulkSetBuffer2250 hantek/types.h
1168   -/// \brief The DSO-2250 BULK_FSETBUFFER builder.
1169   -class BulkSetBuffer2250 : public Helper::DataArray<uint8_t> {
1170   -public:
1171   - BulkSetBuffer2250();
1172   - BulkSetBuffer2250(uint32_t triggerPositionPre, uint32_t triggerPositionPost);
1173   -
1174   - uint32_t getTriggerPositionPost();
1175   - void setTriggerPositionPost(uint32_t value);
1176   - uint32_t getTriggerPositionPre();
1177   - void setTriggerPositionPre(uint32_t value);
1178   -
1179   -private:
1180   - void init();
1181   -};
1182   -
1183   -//////////////////////////////////////////////////////////////////////////////
1184   -/// \class ControlGetSpeed hantek/types.h
1185   -/// \brief The CONTROL_GETSPEED parser.
1186   -class ControlGetSpeed : public Helper::DataArray<uint8_t> {
1187   -public:
1188   - ControlGetSpeed();
1189   -
1190   - ConnectionSpeed getSpeed();
1191   -};
1192   -
1193   -//////////////////////////////////////////////////////////////////////////////
1194   -/// \class ControlBeginCommand hantek/types.h
1195   -/// \brief The CONTROL_BEGINCOMMAND builder.
1196   -class ControlBeginCommand : public Helper::DataArray<uint8_t> {
1197   -public:
1198   - ControlBeginCommand(BulkIndex index = COMMANDINDEX_0);
1199   -
1200   - BulkIndex getIndex();
1201   - void setIndex(BulkIndex index);
1202   -
1203   -private:
1204   - void init();
1205   -};
1206   -
1207   -//////////////////////////////////////////////////////////////////////////////
1208   -/// \class ControlSetOffset hantek/types.h
1209   -/// \brief The CONTROL_SETOFFSET builder.
1210   -class ControlSetOffset : public Helper::DataArray<uint8_t> {
1211   -public:
1212   - ControlSetOffset();
1213   - ControlSetOffset(uint16_t channel1, uint16_t channel2, uint16_t trigger);
1214   -
1215   - uint16_t getChannel(unsigned int channel);
1216   - void setChannel(unsigned int channel, uint16_t offset);
1217   - uint16_t getTrigger();
1218   - void setTrigger(uint16_t level);
1219   -
1220   -private:
1221   - void init();
1222   -};
1223   -
1224   -//////////////////////////////////////////////////////////////////////////////
1225   -/// \class ControlSetRelays hantek/types.h
1226   -/// \brief The CONTROL_SETRELAYS builder.
1227   -class ControlSetRelays : public Helper::DataArray<uint8_t> {
1228   -public:
1229   - ControlSetRelays(bool ch1Below1V = false, bool ch1Below100mV = false,
1230   - bool ch1CouplingDC = false, bool ch2Below1V = false,
1231   - bool ch2Below100mV = false, bool ch2CouplingDC = false,
1232   - bool triggerExt = false);
1233   -
1234   - bool getBelow1V(unsigned int channel);
1235   - void setBelow1V(unsigned int channel, bool below);
1236   - bool getBelow100mV(unsigned int channel);
1237   - void setBelow100mV(unsigned int channel, bool below);
1238   - bool getCoupling(unsigned int channel);
1239   - void setCoupling(unsigned int channel, bool dc);
1240   - bool getTrigger();
1241   - void setTrigger(bool ext);
1242   -};
1243   -
1244   -//////////////////////////////////////////////////////////////////////////////
1245   -/// \class ControlSetVoltDIV_CH1 hantek/types.h
1246   -/// \brief The CONTROL_SETVOLTDIV_CH1 builder.
1247   -class ControlSetVoltDIV_CH1 : public Helper::DataArray<uint8_t> {
1248   -public:
1249   - ControlSetVoltDIV_CH1();
1250   - void setDiv(uint8_t val);
1251   -};
1252   -
1253   -//////////////////////////////////////////////////////////////////////////////
1254   -/// \class ControlSetVoltDIV_CH2 hantek/types.h
1255   -/// \brief The CONTROL_SETVOLTDIV_CH2 builder.
1256   -class ControlSetVoltDIV_CH2 : public Helper::DataArray<uint8_t> {
1257   -public:
1258   - ControlSetVoltDIV_CH2();
1259   - void setDiv(uint8_t val);
1260   -};
1261   -
1262   -//////////////////////////////////////////////////////////////////////////////
1263   -/// \class ControlSetTimeDIV hantek/types.h
1264   -/// \brief The CONTROL_SETTIMEDIV builder.
1265   -class ControlSetTimeDIV : public Helper::DataArray<uint8_t> {
1266   -public:
1267   - ControlSetTimeDIV();
1268   - void setDiv(uint8_t val);
1269   -};
1270   -
1271   -//////////////////////////////////////////////////////////////////////////////
1272   -/// \class ControlAcquireHardData hantek/types.h
1273   -/// \brief The CONTROL_ACQUIIRE_HARD_DATA builder.
1274   -class ControlAcquireHardData : public Helper::DataArray<uint8_t> {
1275   -public:
1276   - ControlAcquireHardData();
1277   -
1278   -private:
1279   - void init();
1280   -};
  125 + //////////////////////////////////////////////////////////////////////////////
  126 + /// \enum BulkCode hantek/types.h
  127 + /// \brief All supported bulk commands.
  128 + /// Indicies given in square brackets specify byte numbers in little endian
  129 + /// format.
  130 + enum BulkCode {
  131 + /// BulkSetFilter [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO5200,
  132 + /// ::MODEL_DSO5200A</em>]
  133 + /// <p>
  134 + /// This command sets channel and trigger filter:
  135 + /// <table>
  136 + /// <tr>
  137 + /// <td>0x00</td>
  138 + /// <td>0x00</td>
  139 + /// <td>FilterBits</td>
  140 + /// <td>0x00</td>
  141 + /// <td>0x00</td>
  142 + /// <td>0x00</td>
  143 + /// <td>0x00</td>
  144 + /// <td>0x00</td>
  145 + /// </tr>
  146 + /// </table>
  147 + /// </p>
  148 + /// <p>
  149 + /// This command is used by the official %Hantek software, but doesn't seem
  150 + /// to be used by the device.
  151 + /// <p><br /></p>
  152 + BULK_SETFILTER,
  153 +
  154 + /// BulkSetTriggerAndSamplerate [<em>::MODEL_DSO2090, ::MODEL_DSO2150</em>]
  155 + /// <p>
  156 + /// This command sets trigger and timebase:
  157 + /// <table>
  158 + /// <tr>
  159 + /// <td>0x01</td>
  160 + /// <td>0x00</td>
  161 + /// <td>Tsr1Bits</td>
  162 + /// <td>Tsr2Bits</td>
  163 + /// <td>Downsampler[0]</td>
  164 + /// <td>Downsampler[1]</td>
  165 + /// </tr>
  166 + /// </table>
  167 + /// <table>
  168 + /// <tr>
  169 + /// <td>TriggerPosition[0]</td>
  170 + /// <td>TriggerPosition[1]</td>
  171 + /// <td>0x00</td>
  172 + /// <td>0x00</td>
  173 + /// <td>TriggerPosition[2]</td>
  174 + /// <td>0x00</td>
  175 + /// </tr>
  176 + /// </table>
  177 + /// </p>
  178 + /// <p>
  179 + /// The samplerate is set relative to the base samplerate by a divider or to
  180 + /// a maximum samplerate.<br />
  181 + /// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to
  182 + /// the following values:
  183 + /// <table>
  184 + /// <tr>
  185 + /// <td><b>Tsr1Bits.samplerateId</b></td><td>0</td><td>1</td><td>2</td><td>3</td>
  186 + /// </tr>
  187 + /// <tr>
  188 + /// <td><b>Samplerate</b></td><td>Max</td><td>Base</td><td>Base /
  189 + /// 2</td><td>Base / 5</td>
  190 + /// </tr>
  191 + /// </table>
  192 + /// For higher divider values, the value can be set using the 16-bit value
  193 + /// in the two Downsampler bytes. The value of Downsampler is given by:<br
  194 + /// />
  195 + /// <i>Downsampler = 1comp((Base / Samplerate / 2) - 2)</i><br />
  196 + /// The Base samplerate is 50 MS/s for the DSO-2090 and DSO-2150. The Max
  197 + /// samplerate is also 50 MS/s for the DSO-2090 and 75 MS/s for the
  198 + /// DSO-2150.<br />
  199 + /// When using fast rate mode the Base and Max samplerate is twice as fast.
  200 + /// When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided
  201 + /// by 1000.
  202 + /// </p>
  203 + /// <p>
  204 + /// The TriggerPosition sets the position of the pretrigger in samples. The
  205 + /// left side (0 %) is 0x77660 when using the small buffer and 0x78000 when
  206 + /// using the large buffer.
  207 + /// </p>
  208 + /// <p><br /></p>
  209 + BULK_SETTRIGGERANDSAMPLERATE,
  210 +
  211 + /// BulkForceTrigger [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
  212 + /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  213 + /// <p>
  214 + /// This command forces triggering:
  215 + /// <table>
  216 + /// <tr>
  217 + /// <td>0x02</td>
  218 + /// <td>0x00</td>
  219 + /// </tr>
  220 + /// </table>
  221 + /// </p>
  222 + /// <p><br /></p>
  223 + BULK_FORCETRIGGER,
  224 +
  225 + /// BulkCaptureStart [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
  226 + /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  227 + /// <p>
  228 + /// This command starts to capture data:
  229 + /// <table>
  230 + /// <tr>
  231 + /// <td>0x03</td>
  232 + /// <td>0x00</td>
  233 + /// </tr>
  234 + /// </table>
  235 + /// </p>
  236 + /// <p><br /></p>
  237 + BULK_STARTSAMPLING,
  238 +
  239 + /// BulkTriggerEnabled [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
  240 + /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  241 + /// <p>
  242 + /// This command sets the trigger:
  243 + /// <table>
  244 + /// <tr>
  245 + /// <td>0x04</td>
  246 + /// <td>0x00</td>
  247 + /// </tr>
  248 + /// </table>
  249 + /// </p>
  250 + /// <p><br /></p>
  251 + BULK_ENABLETRIGGER,
  252 +
  253 + /// BulkGetData [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
  254 + /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  255 + /// <p>
  256 + /// This command reads data from the hardware:
  257 + /// <table>
  258 + /// <tr>
  259 + /// <td>0x05</td>
  260 + /// <td>0x00</td>
  261 + /// </tr>
  262 + /// </table>
  263 + /// </p>
  264 + /// <p>
  265 + /// The oscilloscope returns the sample data, that will be split if it's
  266 + /// larger than the IN endpoint packet length:
  267 + /// <table>
  268 + /// <tr>
  269 + /// <td>Sample[0]</td>
  270 + /// <td>...</td>
  271 + /// <td>Sample[511]</td>
  272 + /// </tr>
  273 + /// <tr>
  274 + /// <td>Sample[512]</td>
  275 + /// <td>...</td>
  276 + /// <td>Sample[1023]</td>
  277 + /// </tr>
  278 + /// <tr>
  279 + /// <td>Sample[1024]</td>
  280 + /// <td colspan="2">...</td>
  281 + /// </tr>
  282 + /// </table>
  283 + /// Because of the 10 bit data model, the DSO-5200 transmits the two extra
  284 + /// bits for each sample afterwards:
  285 + /// <table>
  286 + /// <tr>
  287 + /// <td>Extra[0] << 2 | Extra[1]</td>
  288 + /// <td>0</td>
  289 + /// <td>Extra[2] << 2 | Extra[3]</td>
  290 + /// <td>0</td>
  291 + /// <td>...</td>
  292 + /// <td>Extra[510] << 2 | Extra[511]</td>
  293 + /// <td>0</td>
  294 + /// </tr>
  295 + /// <tr>
  296 + /// <td>Extra[512] << 2 | Extra[513]</td>
  297 + /// <td colspan="6">...</td>
  298 + /// </tr>
  299 + /// </table>
  300 + /// </p>
  301 + /// <p><br /></p>
  302 + BULK_GETDATA,
  303 +
  304 + /// BulkGetCaptureState [<em>::MODEL_DSO2090, ::MODEL_DSO2150,
  305 + /// ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  306 + /// <p>
  307 + /// This command checks the capture state:
  308 + /// <table>
  309 + /// <tr>
  310 + /// <td>0x06</td>
  311 + /// <td>0x00</td>
  312 + /// </tr>
  313 + /// </table>
  314 + /// </p>
  315 + /// <p>
  316 + /// The oscilloscope returns it's capture state and the trigger point. Not
  317 + /// sure about this, looks like 248 16-bit words with nearly constant
  318 + /// values. These can be converted to the start address of the data in the
  319 + /// buffer (See Hantek::Control::calculateTriggerPoint):
  320 + /// <table>
  321 + /// <tr>
  322 + /// <td>::CaptureState</td>
  323 + /// <td>0x00</td>
  324 + /// <td>TriggerPoint[0]</td>
  325 + /// <td>TriggerPoint[1]</td>
  326 + /// <td>...</td>
  327 + /// </tr>
  328 + /// </table>
  329 + /// </p>
  330 + /// <p><br /></p>
  331 + BULK_GETCAPTURESTATE,
  332 +
  333 + /// BulkSetGain [<em>::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250,
  334 + /// ::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  335 + /// <p>
  336 + /// This command sets the gain:
  337 + /// <table>
  338 + /// <tr>
  339 + /// <td>0x07</td>
  340 + /// <td>0x00</td>
  341 + /// <td>GainBits</td>
  342 + /// <td>0x00</td>
  343 + /// <td>0x00</td>
  344 + /// <td>0x00</td>
  345 + /// <td>0x00</td>
  346 + /// <td>0x00</td>
  347 + /// </tr>
  348 + /// </table>
  349 + /// It is usually used in combination with ::CONTROL_SETRELAYS.
  350 + /// </p>
  351 + /// <p><br /></p>
  352 + BULK_SETGAIN,
  353 +
  354 + /// BulkSetLogicalData [<em></em>]
  355 + /// <p>
  356 + /// This command sets the logical data (Not used in official %Hantek
  357 + /// software):
  358 + /// <table>
  359 + /// <tr>
  360 + /// <td>0x08</td>
  361 + /// <td>0x00</td>
  362 + /// <td>Data | 0x01</td>
  363 + /// <td>0x00</td>
  364 + /// <td>0x00</td>
  365 + /// <td>0x00</td>
  366 + /// <td>0x00</td>
  367 + /// <td>0x00</td>
  368 + /// </tr>
  369 + /// </table>
  370 + /// </p>
  371 + /// <p><br /></p>
  372 + BULK_SETLOGICALDATA,
  373 +
  374 + /// BulkGetLogicalData [<em></em>]
  375 + /// <p>
  376 + /// This command reads the logical data (Not used in official %Hantek
  377 + /// software):
  378 + /// <table>
  379 + /// <tr>
  380 + /// <td>0x09</td>
  381 + /// <td>0x00</td>
  382 + /// </tr>
  383 + /// </table>
  384 + /// </p>
  385 + /// <p>
  386 + /// The oscilloscope returns the logical data, which contains valid data in
  387 + /// the first byte although it is 64 or 512 bytes long:
  388 + /// <table>
  389 + /// <tr>
  390 + /// <td>Data</td>
  391 + /// <td>...</td>
  392 + /// </tr>
  393 + /// </table>
  394 + /// </p>
  395 + /// <p><br /></p>
  396 + BULK_GETLOGICALDATA,
  397 +
  398 + /// [<em></em>]
  399 + /// <p>
  400 + /// This command isn't used for any supported model:
  401 + /// <table>
  402 + /// <tr>
  403 + /// <td>0x0a</td>
  404 + /// <td>...</td>
  405 + /// </tr>
  406 + /// </table>
  407 + /// </p>
  408 + /// <p><br /></p>
  409 + BULK_AUNKNOWN,
  410 +
  411 + /// BulkSetChannels2250 [<em>::MODEL_DSO2250</em>]
  412 + /// <p>
  413 + /// This command sets the activated channels for the DSO-2250:
  414 + /// <table>
  415 + /// <tr>
  416 + /// <td>0x0b</td>
  417 + /// <td>0x00</td>
  418 + /// <td>BUsedChannels</td>
  419 + /// <td>0x00</td>
  420 + /// </tr>
  421 + /// </table>
  422 + /// </p>
  423 + /// <p><br /></p>
  424 + BULK_BSETCHANNELS,
  425 +
  426 + /// BulkSetTrigger2250 [<em>::MODEL_DSO2250</em>]
  427 + /// <p>
  428 + /// This command sets the trigger source for the DSO-2250:
  429 + /// <table>
  430 + /// <tr>
  431 + /// <td>0x0c</td>
  432 + /// <td>0x00</td>
  433 + /// <td>CTriggerBits</td>
  434 + /// <td>0x00</td>
  435 + /// <td>0x00</td>
  436 + /// <td>0x00</td>
  437 + /// <td>0x00</td>
  438 + /// <td>0x00</td>
  439 + /// </tr>
  440 + /// </table>
  441 + /// </p>
  442 + /// <p><br /></p>
  443 + /// BulkSetSamplerate5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  444 + /// <p>
  445 + /// This command sets the sampling rate for the DSO-5200:
  446 + /// <table>
  447 + /// <tr>
  448 + /// <td>0x0c</td>
  449 + /// <td>0x00</td>
  450 + /// <td>SamplerateSlow[0]</td>
  451 + /// <td>SamplerateSlow[1]</td>
  452 + /// <td>SamplerateFast</td>
  453 + /// <td>0x00</td>
  454 + /// </tr>
  455 + /// </table>
  456 + /// </p>
  457 + /// <p>
  458 + /// The samplerate is set relative to the maximum sample rate by a divider
  459 + /// that is set in SamplerateFast and the 16-bit value in the two
  460 + /// SamplerateSlow bytes.<br />
  461 + /// Without using fast rate mode, the samplerate is:<br />
  462 + /// <i>Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 -
  463 + /// SamplerateFast)</i><br />
  464 + /// SamplerateBase is 100 MS/s for the DSO-5200 in normal mode and 200 MS/s
  465 + /// in fast rate mode, the modifications regarding record length are the the
  466 + /// same that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
  467 + /// normal mode and 250 MS/s in fast rate mode, and is reached by setting
  468 + /// SamplerateSlow = 0 and SamplerateFast = 4.
  469 + /// </p>
  470 + /// <p><br /></p>
  471 + BULK_CSETTRIGGERORSAMPLERATE,
  472 +
  473 + /// BulkSetRecordLength2250 [<em>::MODEL_DSO2250</em>]
  474 + /// <p>
  475 + /// This command sets the record length for the DSO-2250:
  476 + /// <table>
  477 + /// <tr>
  478 + /// <td>0x0d</td>
  479 + /// <td>0x00</td>
  480 + /// <td>::RecordLengthId</td>
  481 + /// <td>0x00</td>
  482 + /// </tr>
  483 + /// </table>
  484 + /// </p>
  485 + /// <p><br /></p>
  486 + /// BulkSetBuffer5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  487 + /// <p>
  488 + /// This command sets the trigger position and record length for the
  489 + /// DSO-5200:
  490 + /// <table>
  491 + /// <tr>
  492 + /// <td>0x0d</td>
  493 + /// <td>0x00</td>
  494 + /// <td>TriggerPositionPre[0]</td>
  495 + /// <td>TriggerPositionPre[1]</td>
  496 + /// <td>::DTriggerPositionUsed</td>
  497 + /// </tr>
  498 + /// </table>
  499 + /// <table>
  500 + /// <tr>
  501 + /// <td>0xff</td>
  502 + /// <td>TriggerPositionPost[0]</td>
  503 + /// <td>TriggerPositionPost[1]</td>
  504 + /// <td>DBufferBits</td>
  505 + /// <td>0xff</td>
  506 + /// </tr>
  507 + /// </table>
  508 + /// </p>
  509 + /// <p>
  510 + /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
  511 + /// position. Both values have a range from 0xd7ff (0xc7ff for 14 kiS
  512 + /// buffer) to 0xfffe. On the left side (0 %) the TriggerPositionPre value
  513 + /// is minimal, on the right side (100 %) it is maximal. The
  514 + /// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
  515 + /// </p>
  516 + /// <p><br /></p>
  517 + BULK_DSETBUFFER,
  518 +
  519 + /// BulkSetSamplerate2250 [<em>::MODEL_DSO2250</em>]
  520 + /// <p>
  521 + /// This command sets the samplerate:
  522 + /// <table>
  523 + /// <tr>
  524 + /// <td>0x0e</td>
  525 + /// <td>0x00</td>
  526 + /// <td>ESamplerateBits</td>
  527 + /// <td>0x00</td>
  528 + /// <td>Samplerate[0]</td>
  529 + /// <td>Samplerate[1]</td>
  530 + /// <td>0x00</td>
  531 + /// <td>0x00</td>
  532 + /// </tr>
  533 + /// </table>
  534 + /// </p>
  535 + /// <p>
  536 + /// The downsampler can be activated by setting ESamplerateBits.downsampling
  537 + /// = 1. If this is the case, the value of Downsampler is given by:<br />
  538 + /// <i>Downsampler = 1comp((Base / Samplerate) - 2)</i><br />
  539 + /// Base is 100 MS/s for the DSO-2250 in standard mode and 200 MS/s in fast
  540 + /// rate mode, the modifications regarding record length are the the same
  541 + /// that apply for the DSO-2090. The maximum samplerate is 125 MS/s in
  542 + /// standard mode and 250 MS/s in fast rate mode and is achieved by setting
  543 + /// ESamplerateBits.downsampling = 0.
  544 + /// </p>
  545 + /// <p><br /></p>
  546 + /// BulkSetTrigger5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
  547 + /// <p>
  548 + /// This command sets the channel and trigger settings:
  549 + /// <table>
  550 + /// <tr>
  551 + /// <td>0x0e</td>
  552 + /// <td>0x00</td>
  553 + /// <td>ETsrBits</td>
  554 + /// <td>0x00</td>
  555 + /// <td>0x00</td>
  556 + /// <td>0x00</td>
  557 + /// <td>0x00</td>
  558 + /// <td>0x00</td>
  559 + /// </tr>
  560 + /// </table>
  561 + /// </p>
  562 + /// <p><br /></p>
  563 + BULK_ESETTRIGGERORSAMPLERATE,
  564 +
  565 + /// BulkSetBuffer2250 [<em>::MODEL_DSO2250</em>]
  566 + /// <p>
  567 + /// This command sets the trigger position and buffer configuration for the
  568 + /// DSO-2250:
  569 + /// <table>
  570 + /// <tr>
  571 + /// <td>0x0f</td>
  572 + /// <td>0x00</td>
  573 + /// <td>TriggerPositionPost[0]</td>
  574 + /// <td>TriggerPositionPost[1]</td>
  575 + /// <td>TriggerPositionPost[2]</td>
  576 + /// <td>0x00</td>
  577 + /// </tr>
  578 + /// </table>
  579 + /// <table>
  580 + /// <tr>
  581 + /// <td>TriggerPositionPre[0]</td>
  582 + /// <td>TriggerPositionPre[1]</td>
  583 + /// <td>TriggerPositionPre[2]</td>
  584 + /// <td>0x00</td>
  585 + /// <td>0x00</td>
  586 + /// <td>0x00</td>
  587 + /// </tr>
  588 + /// </table>
  589 + /// </p>
  590 + /// <p>
  591 + /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger
  592 + /// position. Both values have a range from 0x7d800 (0x00000 for 512 kiS
  593 + /// buffer) to 0x7ffff. On the left side (0 %) the TriggerPositionPre value
  594 + /// is minimal, on the right side (100 %) it is maximal. The
  595 + /// TriggerPositionPost value is maximal for 0 % and minimal for 100%.
  596 + /// </p>
  597 + /// <p><br /></p>
  598 + BULK_FSETBUFFER,
  599 +
  600 + BULK_COUNT
  601 + };
  602 +
  603 + //////////////////////////////////////////////////////////////////////////////
  604 + /// \enum ControlCode hantek/types.h
  605 + /// \brief All supported control commands.
  606 + enum ControlCode {
  607 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  608 + /// ::MODEL_DSO5200A]</em>
  609 + /// <p>
  610 + /// The 0xa2 control read/write command gives access to a ::ControlValue.
  611 + /// </p>
  612 + /// <p><br /></p>
  613 + CONTROL_VALUE = 0xa2,
  614 +
  615 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  616 + /// ::MODEL_DSO5200A]</em>
  617 + /// <p>
  618 + /// The 0xb2 control read command gets the speed level of the USB
  619 + /// connection:
  620 + /// <table>
  621 + /// <tr>
  622 + /// <td>::ConnectionSpeed</td>
  623 + /// <td>0x00</td>
  624 + /// <td>0x00</td>
  625 + /// <td>0x00</td>
  626 + /// <td>0x00</td>
  627 + /// <td>0x00</td>
  628 + /// <td>0x00</td>
  629 + /// <td>0x00</td>
  630 + /// <td>0x00</td>
  631 + /// <td>0x00</td>
  632 + /// </tr>
  633 + /// </table>
  634 + /// </p>
  635 + /// <p><br /></p>
  636 + CONTROL_GETSPEED = 0xb2,
  637 +
  638 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  639 + /// ::MODEL_DSO5200A]</em>
  640 + /// <p>
  641 + /// The 0xb3 control write command is sent before any bulk command:
  642 + /// <table>
  643 + /// <tr>
  644 + /// <td>0x0f</td>
  645 + /// <td>::BulkIndex</td>
  646 + /// <td>::BulkIndex</td>
  647 + /// <td>::BulkIndex</td>
  648 + /// <td>0x00</td>
  649 + /// <td>0x00</td>
  650 + /// <td>0x00</td>
  651 + /// <td>0x00</td>
  652 + /// <td>0x00</td>
  653 + /// <td>0x00</td>
  654 + /// </tr>
  655 + /// </table>
  656 + /// </p>
  657 + /// <p><br /></p>
  658 + CONTROL_BEGINCOMMAND = 0xb3,
  659 +
  660 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  661 + /// ::MODEL_DSO5200A]</em>
  662 + /// <p>
  663 + /// The 0xb4 control write command sets the channel offsets:
  664 + /// <table>
  665 + /// <tr>
  666 + /// <td>Ch1Offset[1]</td>
  667 + /// <td>Ch1Offset[0]</td>
  668 + /// <td>Ch2Offset[1]</td>
  669 + /// <td>Ch2Offset[0]</td>
  670 + /// <td>TriggerOffset[1]</td>
  671 + /// <td>TriggerOffset[0]</td>
  672 + /// </tr>
  673 + /// </table>
  674 + /// <table>
  675 + /// <tr>
  676 + /// <td>0x00</td>
  677 + /// <td>0x00</td>
  678 + /// <td>0x00</td>
  679 + /// <td>0x00</td>
  680 + /// <td>0x00</td>
  681 + /// <td>0x00</td>
  682 + /// <td>0x00</td>
  683 + /// <td>0x00</td>
  684 + /// <td>0x00</td>
  685 + /// <td>0x00</td>
  686 + /// <td>0x00</td>
  687 + /// </tr>
  688 + /// </table>
  689 + /// </p>
  690 + /// <p><br /></p>
  691 + CONTROL_SETOFFSET = 0xb4,
  692 +
  693 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  694 + /// ::MODEL_DSO5200A]</em>
  695 + /// <p>
  696 + /// The 0xb5 control write command sets the internal relays:
  697 + /// <table>
  698 + /// <tr>
  699 + /// <td>0x00</td>
  700 + /// <td>0x04 ^ (Ch1Gain < 1 V)</td>
  701 + /// <td>0x08 ^ (Ch1Gain < 100 mV)</td>
  702 + /// <td>0x02 ^ (Ch1Coupling == DC)</td>
  703 + /// </tr>
  704 + /// </table>
  705 + /// <table>
  706 + /// <tr>
  707 + /// <td>0x20 ^ (Ch2Gain < 1 V)</td>
  708 + /// <td>0x40 ^ (Ch2Gain < 100 mV)</td>
  709 + /// <td>0x10 ^ (Ch2Coupling == DC)</td>
  710 + /// <td>0x01 ^ (Trigger == EXT)</td>
  711 + /// </tr>
  712 + /// </table>
  713 + /// <table>
  714 + /// <tr>
  715 + /// <td>0x00</td>
  716 + /// <td>0x00</td>
  717 + /// <td>0x00</td>
  718 + /// <td>0x00</td>
  719 + /// <td>0x00</td>
  720 + /// <td>0x00</td>
  721 + /// <td>0x00</td>
  722 + /// <td>0x00</td>
  723 + /// <td>0x00</td>
  724 + /// </tr>
  725 + /// </table>
  726 + /// </p>
  727 + /// <p>
  728 + /// The limits are <= instead of < for the 10 bit models, since those
  729 + /// support voltages up to 10 V.
  730 + /// </p>
  731 + /// <p><br /></p>
  732 + CONTROL_SETRELAYS = 0xb5,
  733 +
  734 + CONTROL_SETVOLTDIV_CH1 = 0xe0,
  735 + CONTROL_SETVOLTDIV_CH2 = 0xe1,
  736 + CONTROL_SETTIMEDIV = 0xe2,
  737 + CONTROL_ACQUIIRE_HARD_DATA = 0xe3
  738 + };
  739 +
  740 + //////////////////////////////////////////////////////////////////////////////
  741 + /// \enum ControlValue hantek/types.h
  742 + /// \brief All supported values for control commands.
  743 + enum ControlValue {
  744 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  745 + /// ::MODEL_DSO5200A]</em>
  746 + /// <p>
  747 + /// Value 0x08 is the calibration data for the channels offsets. It holds the
  748 + /// offset value for the top and bottom of the scope screen for every gain
  749 + /// step on every channel. The data is stored as a three-dimensional array:<br
  750 + /// />
  751 + /// <i>channelLevels[channel][GainId][::LevelOffset]</i>
  752 + /// </p>
  753 + /// <p><br /></p>
  754 + VALUE_OFFSETLIMITS = 0x08,
  755 +
  756 + /// <em>[::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200,
  757 + /// ::MODEL_DSO5200A]</em>
  758 + /// <p>
  759 + /// Value 0x0a is the address of the device. It has a length of one byte.
  760 + /// </p>
  761 + /// <p><br /></p>
  762 + VALUE_DEVICEADDRESS = 0x0a,
  763 +
  764 + /// <em>[::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A]</em>
  765 + /// <p>
  766 + /// Value 0x60 is the calibration data for the fast rate mode on the DSO-2250,
  767 + /// DSO-5200 and DSO-5200A. It's used to correct the level differences between
  768 + /// the two merged channels to avoid deterministic noise.
  769 + /// </p>
  770 + /// <p><br /></p>
  771 + VALUE_FASTRATECALIBRATION = 0x60,
  772 +
  773 + /// <em>[::MODEL_DSO5200, ::MODEL_DSO5200A]</em>
  774 + /// <p>
  775 + /// Value 0x70 contains correction values for the ETS functionality of the
  776 + /// DSO-5200 and DSO-5200A.
  777 + /// </p>
  778 + /// <p><br /></p>
  779 + VALUE_ETSCORRECTION = 0x70
  780 + };
  781 +
  782 +
  783 + //////////////////////////////////////////////////////////////////////////////
  784 + /// \enum ConnectionSpeed hantek/types.h
  785 + /// \brief The speed level of the USB connection.
  786 + enum ConnectionSpeed {
  787 + CONNECTION_FULLSPEED = 0, ///< FullSpeed USB, 64 byte bulk transfers
  788 + CONNECTION_HIGHSPEED = 1 ///< HighSpeed USB, 512 byte bulk transfers
  789 + };
  790 +
  791 + //////////////////////////////////////////////////////////////////////////////
  792 + /// \enum UsedChannels hantek/types.h
  793 + /// \brief The enabled channels.
  794 + enum UsedChannels {
  795 + USED_CH1, ///< Only channel 1 is activated
  796 + USED_CH2, ///< Only channel 2 is activated
  797 + USED_CH1CH2, ///< Channel 1 and 2 are both activated
  798 + USED_NONE ///< No channels are activated
  799 + };
  800 +
  801 + //////////////////////////////////////////////////////////////////////////////
  802 + /// \enum TriggerSource hantek/types.h
  803 + /// \brief The possible trigger sources.
  804 + enum TriggerSource {
  805 + TRIGGER_CH2,
  806 + TRIGGER_CH1,
  807 + TRIGGER_ALT,
  808 + TRIGGER_EXT,
  809 + TRIGGER_EXT10
  810 + };
  811 +
  812 + //////////////////////////////////////////////////////////////////////////////
  813 + /// \enum RecordLengthId hantek/types.h
  814 + /// \brief The size id for CommandSetTriggerAndSamplerate.
  815 + enum RecordLengthId {
  816 + RECORDLENGTHID_ROLL = 0, ///< Used for the roll mode
  817 + RECORDLENGTHID_SMALL, ///< The standard buffer with 10240 samples
  818 + RECORDLENGTHID_LARGE ///< The large buffer, 32768 samples (14336 for DSO-5200)
  819 + };
  820 +
  821 + //////////////////////////////////////////////////////////////////////////////
  822 + /// \enum CaptureState hantek/types.h
  823 + /// \brief The different capture states which the oscilloscope returns.
  824 + enum CaptureState {
  825 + CAPTURE_WAITING = 0, ///< The scope is waiting for a trigger event
  826 + CAPTURE_SAMPLING = 1, ///< The scope is sampling data after triggering
  827 + CAPTURE_READY = 2, ///< Sampling data is available (DSO-2090/DSO-2150)
  828 + CAPTURE_READY2250 = 3, ///< Sampling data is available (DSO-2250)
  829 + CAPTURE_READY5200 = 7 ///< Sampling data is available (DSO-5200/DSO-5200A)
  830 + };
  831 +
  832 + //////////////////////////////////////////////////////////////////////////////
  833 + /// \enum BulkIndex hantek/types.h
  834 + /// \brief Can be set by CONTROL_BEGINCOMMAND, maybe it allows multiple commands
  835 + /// at the same time?
  836 + enum BulkIndex {
  837 + COMMANDINDEX_0 = 0x03, ///< Used most of the time
  838 + COMMANDINDEX_1 = 0x0a,
  839 + COMMANDINDEX_2 = 0x09,
  840 + COMMANDINDEX_3 = 0x01, ///< Used for ::BULK_SETTRIGGERANDSAMPLERATE sometimes
  841 + COMMANDINDEX_4 = 0x02,
  842 + COMMANDINDEX_5 = 0x08
  843 + };
  844 +
  845 + //////////////////////////////////////////////////////////////////////////////
  846 + /// \enum LevelOffset hantek/types.h
  847 + /// \brief The array indicies for the CalibrationData.
  848 + enum LevelOffset {
  849 + OFFSET_START, ///< The channel level at the bottom of the scope
  850 + OFFSET_END, ///< The channel level at the top of the scope
  851 + OFFSET_COUNT
  852 + };
  853 +
  854 + //////////////////////////////////////////////////////////////////////////////
  855 + /// \enum BUsedChannels hantek/types.h
  856 + /// \brief The enabled channels for the DSO-2250.
  857 + enum BUsedChannels {
  858 + BUSED_CH1, ///< Only channel 1 is activated
  859 + BUSED_NONE, ///< No channels are activated
  860 + BUSED_CH1CH2, ///< Channel 1 and 2 are both activated
  861 + BUSED_CH2 ///< Only channel 2 is activated
  862 + };
  863 +
  864 + //////////////////////////////////////////////////////////////////////////////
  865 + /// \enum DTriggerPositionUsed hantek/types.h
  866 + /// \brief The trigger position states for the 0x0d command.
  867 + enum DTriggerPositionUsed {
  868 + DTRIGGERPOSITION_OFF = 0, ///< Used for Roll mode
  869 + DTRIGGERPOSITION_ON = 7 ///< Used for normal operation
  870 + };
  871 +
  872 + //////////////////////////////////////////////////////////////////////////////
  873 + /// \struct FilterBits hantek/types.h
  874 + /// \brief The bits for BULK_SETFILTER.
  875 + struct FilterBits {
  876 + uint8_t channel1 : 1; ///< Set to true when channel 1 isn't used
  877 + uint8_t channel2 : 1; ///< Set to true when channel 2 isn't used
  878 + uint8_t trigger : 1; ///< Set to true when trigger isn't used
  879 + uint8_t reserved : 5; ///< Unused bits
  880 + };
  881 +
  882 + //////////////////////////////////////////////////////////////////////////////
  883 + /// \struct GainBits hantek/types.h
  884 + /// \brief The gain bits for BULK_SETGAIN.
  885 + struct GainBits {
  886 + uint8_t channel1 : 2; ///< Gain for CH1, 0 = 1e* V, 1 = 2e*, 2 = 5e*
  887 + uint8_t channel2 : 2; ///< Gain for CH1, 0 = 1e* V, 1 = 2e*, 2 = 5e*
  888 + uint8_t reserved : 4; ///< Unused bits
  889 + };
  890 +
  891 + //////////////////////////////////////////////////////////////////////////////
  892 + /// \struct Tsr1Bits hantek/types.h
  893 + /// \brief Trigger and samplerate bits (Byte 1).
  894 + struct Tsr1Bits {
  895 + uint8_t triggerSource : 2; ///< The trigger source, see Hantek::TriggerSource
  896 + uint8_t recordLength : 3; ///< See ::RecordLengthId
  897 + uint8_t samplerateId : 2; ///< Samplerate ID when downsampler is disabled
  898 + uint8_t downsamplingMode : 1; ///< true, if Downsampler is used
  899 + };
  900 +
  901 + //////////////////////////////////////////////////////////////////////////////
  902 + /// \struct Tsr2Bits hantek/types.h
  903 + /// \brief Trigger and samplerate bits (Byte 2).
  904 + struct Tsr2Bits {
  905 + uint8_t usedChannels : 2; ///< Used channels, see Hantek::UsedChannels
  906 + uint8_t fastRate : 1; ///< true, if one channels uses all buffers
  907 + uint8_t triggerSlope : 1; ///< The trigger slope, see Dso::Slope, inverted
  908 + ///when Tsr1Bits.samplerateFast is uneven
  909 + uint8_t reserved : 4; ///< Unused bits
  910 + };
  911 +
  912 + //////////////////////////////////////////////////////////////////////////////
  913 + /// \struct CTriggerBits hantek/types.h
  914 + /// \brief Trigger bits for 0x0c command.
  915 + struct CTriggerBits {
  916 + uint8_t triggerSource : 2; ///< The trigger source, see Hantek::TriggerSource
  917 + uint8_t triggerSlope : 1; ///< The trigger slope, see Dso::Slope
  918 + uint8_t reserved : 5; ///< Unused bits
  919 + };
  920 +
  921 + //////////////////////////////////////////////////////////////////////////////
  922 + /// \struct DBufferBits hantek/types.h
  923 + /// \brief Buffer mode bits for 0x0d command.
  924 + struct DBufferBits {
  925 + uint8_t triggerPositionUsed : 3; ///< See ::DTriggerPositionUsed
  926 + uint8_t recordLength : 3; ///< See ::RecordLengthId
  927 + uint8_t reserved : 2; ///< Unused bits
  928 + };
  929 +
  930 + //////////////////////////////////////////////////////////////////////////////
  931 + /// \struct ESamplerateBits hantek/types.h
  932 + /// \brief Samplerate bits for DSO-2250 0x0e command.
  933 + struct ESamplerateBits {
  934 + uint8_t fastRate : 1; ///< false, if one channels uses all buffers
  935 + uint8_t downsampling : 1; ///< true, if the downsampler is activated
  936 + uint8_t reserved : 4; ///< Unused bits
  937 + };
  938 +
  939 + //////////////////////////////////////////////////////////////////////////////
  940 + /// \struct ETsrBits hantek/types.h
  941 + /// \brief Trigger and samplerate bits for DSO-5200/DSO-5200A 0x0e command.
  942 + struct ETsrBits {
  943 + uint8_t fastRate : 1; ///< false, if one channels uses all buffers
  944 + uint8_t usedChannels : 2; ///< Used channels, see Hantek::UsedChannels
  945 + uint8_t triggerSource : 2; ///< The trigger source, see Hantek::TriggerSource
  946 + uint8_t triggerSlope : 2; ///< The trigger slope, see Dso::Slope
  947 + uint8_t triggerPulse : 1; ///< Pulses are causing trigger events
  948 + };
1281 949 }
1282   -
1283   -#endif
... ...
openhantek/src/hantek/device.cpp deleted
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// hantek/device.cpp
5   -//
6   -// Copyright (C) 2008, 2009 Oleg Khudyakov
7   -// prcoder@potrebitel.ru
8   -// Copyright (C) 2010 - 2012 Oliver Haag
9   -// oliver.haag@gmail.com
10   -//
11   -// This program is free software: you can redistribute it and/or modify it
12   -// under the terms of the GNU General Public License as published by the Free
13   -// Software Foundation, either version 3 of the License, or (at your option)
14   -// any later version.
15   -//
16   -// This program is distributed in the hope that it will be useful, but WITHOUT
17   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19   -// more details.
20   -//
21   -// You should have received a copy of the GNU General Public License along with
22   -// this program. If not, see <http://www.gnu.org/licenses/>.
23   -//
24   -////////////////////////////////////////////////////////////////////////////////
25   -
26   -#include <QList>
27   -
28   -#include "hantek/device.h"
29   -
30   -#include "hantek/types.h"
31   -#include "helper.h"
32   -
33   -namespace Hantek {
34   -////////////////////////////////////////////////////////////////////////////////
35   -// class Hantek::Device
36   -/// \brief Initializes the usb things and lists.
37   -/// \param parent The parent widget.
38   -Device::Device(QObject *parent) : QObject(parent) {
39   - // Product ids and names for the Model enum
40   - this->modelIds << 0x2090 << 0x2150 << 0x2250 << 0x5200 << 0x520A << 0x6022;
41   - this->modelStrings << "DSO-2090"
42   - << "DSO-2150"
43   - << "DSO-2250"
44   - << "DSO-5200"
45   - << "DSO-5200A"
46   - << "DSO-6022BE";
47   - this->model = MODEL_UNKNOWN;
48   -
49   - this->beginCommandControl = new ControlBeginCommand();
50   -
51   - this->handle = 0;
52   - this->interface = -1;
53   -
54   - this->outPacketLength = 0;
55   - this->inPacketLength = 0;
56   -
57   - this->error = LIBUSB_SUCCESS;
58   - this->error = libusb_init(&(this->context));
59   -}
60   -
61   -/// \brief Disconnects the device.
62   -Device::~Device() { this->disconnect(); }
63   -
64   -/// \brief Search for compatible devices.
65   -/// \return A string with the result of the search.
66   -QString Device::search() {
67   - if (this->error)
68   - return tr("Can't search for Hantek oscilloscopes: %1")
69   - .arg(Helper::libUsbErrorString(this->error));
70   -
71   - QString message;
72   - QString deviceAddress;
73   - int errorCode = LIBUSB_SUCCESS;
74   -
75   - libusb_device **deviceList;
76   - libusb_device *device;
77   -
78   - if (this->handle)
79   - libusb_close(this->handle);
80   -
81   - ssize_t deviceCount = libusb_get_device_list(this->context, &deviceList);
82   - if (deviceCount < 0)
83   - return tr("Failed to get device list: %1")
84   - .arg(Helper::libUsbErrorString(errorCode));
85   -
86   - // Iterate through all usb devices
87   - this->model = MODEL_UNKNOWN;
88   - for (ssize_t deviceIterator = 0; deviceIterator < deviceCount;
89   - ++deviceIterator) {
90   - device = deviceList[deviceIterator];
91   - // Get device descriptor
92   - if (libusb_get_device_descriptor(device, &(this->descriptor)) < 0)
93   - continue;
94   -
95   - // Check VID and PID
96   - if (this->descriptor.idVendor == HANTEK_VENDOR_ID) {
97   - this->model = (Model)this->modelIds.indexOf(this->descriptor.idProduct);
98   - if (this->model >= 0)
99   - break; // Found a compatible device, ignore others
100   - }
101   - }
102   -
103   - if (this->model >= 0) {
104   - // Open device
105   - deviceAddress =
106   - QString("%1:%2")
107   - .arg(libusb_get_bus_number(device), 3, 10, QLatin1Char('0'))
108   - .arg(libusb_get_device_address(device), 3, 10, QLatin1Char('0'));
109   - errorCode = libusb_open(device, &(this->handle));
110   - if (errorCode == LIBUSB_SUCCESS) {
111   - libusb_config_descriptor *configDescriptor;
112   - const libusb_interface *interface;
113   - const libusb_interface_descriptor *interfaceDescriptor;
114   -
115   - // Search for the needed interface
116   - libusb_get_config_descriptor(device, 0, &configDescriptor);
117   - for (int interfaceIndex = 0;
118   - interfaceIndex < (int)configDescriptor->bNumInterfaces;
119   - ++interfaceIndex) {
120   - interface = &configDescriptor->interface[interfaceIndex];
121   - if (interface->num_altsetting < 1)
122   - continue;
123   -
124   - interfaceDescriptor = &interface->altsetting[0];
125   - if (interfaceDescriptor->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
126   - interfaceDescriptor->bInterfaceSubClass == 0 &&
127   - interfaceDescriptor->bInterfaceProtocol == 0 &&
128   - interfaceDescriptor->bNumEndpoints == 2) {
129   - // That's the interface we need, claim it
130   - errorCode = libusb_claim_interface(
131   - this->handle, interfaceDescriptor->bInterfaceNumber);
132   - if (errorCode < 0) {
133   - libusb_close(this->handle);
134   - this->handle = 0;
135   - message =
136   - tr("Failed to claim interface %1 of device %2: %3")
137   - .arg(QString::number(interfaceDescriptor->bInterfaceNumber),
138   - deviceAddress, Helper::libUsbErrorString(errorCode));
139   - } else {
140   - this->interface = interfaceDescriptor->bInterfaceNumber;
141   -
142   - // Check the maximum endpoint packet size
143   - const libusb_endpoint_descriptor *endpointDescriptor;
144   - this->outPacketLength = 0;
145   - this->inPacketLength = 0;
146   - for (int endpoint = 0;
147   - endpoint < interfaceDescriptor->bNumEndpoints; ++endpoint) {
148   - endpointDescriptor = &(interfaceDescriptor->endpoint[endpoint]);
149   - switch (endpointDescriptor->bEndpointAddress) {
150   - case HANTEK_EP_OUT:
151   - this->outPacketLength = endpointDescriptor->wMaxPacketSize;
152   - break;
153   - case HANTEK_EP_IN:
154   - if (this->getModel() == MODEL_DSO6022BE)
155   - this->inPacketLength = 16384;
156   - else
157   - this->inPacketLength = endpointDescriptor->wMaxPacketSize;
158   - break;
159   - }
160   - }
161   - message = tr("Device found: Hantek %1 (%2)")
162   - .arg(this->modelStrings[this->model], deviceAddress);
163   - emit connected();
164   - }
165   - }
166   - }
167   -
168   - libusb_free_config_descriptor(configDescriptor);
169   - } else {
170   - this->handle = 0;
171   - message = tr("Couldn't open device %1: %2")
172   - .arg(deviceAddress, Helper::libUsbErrorString(errorCode));
173   - }
174   - } else
175   - message = tr("No Hantek oscilloscope found");
176   -
177   - libusb_free_device_list(deviceList, true);
178   -
179   - return message;
180   -}
181   -
182   -/// \brief Disconnect the device.
183   -void Device::disconnect() {
184   - if (!this->handle)
185   - return;
186   -
187   - // Release claimed interface
188   - libusb_release_interface(this->handle, this->interface);
189   - this->interface = -1;
190   -
191   - // Close device handle
192   - libusb_close(this->handle);
193   - this->handle = 0;
194   -
195   - emit disconnected();
196   -}
197   -
198   -/// \brief Check if the oscilloscope is connected.
199   -/// \return true, if a connection is up.
200   -bool Device::isConnected() { return this->handle != 0; }
201   -
202   -/// \brief Bulk transfer to/from the oscilloscope.
203   -/// \param endpoint Endpoint number, also sets the direction of the transfer.
204   -/// \param data Buffer for the sent/recieved data.
205   -/// \param length The length of the packet.
206   -/// \param attempts The number of attempts, that are done on timeouts.
207   -/// \param timeout The timeout in ms.
208   -/// \return Number of transferred bytes on success, libusb error code on error.
209   -int Device::bulkTransfer(unsigned char endpoint, unsigned char *data,
210   - unsigned int length, int attempts,
211   - unsigned int timeout) {
212   - if (!this->handle)
213   - return LIBUSB_ERROR_NO_DEVICE;
214   -
215   - int errorCode = LIBUSB_ERROR_TIMEOUT;
216   - int transferred;
217   - for (int attempt = 0; (attempt < attempts || attempts == -1) &&
218   - errorCode == LIBUSB_ERROR_TIMEOUT;
219   - ++attempt)
220   - errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length,
221   - &transferred, timeout);
222   -
223   - if (errorCode == LIBUSB_ERROR_NO_DEVICE)
224   - this->disconnect();
225   - if (errorCode < 0)
226   - return errorCode;
227   - else
228   - return transferred;
229   -}
230   -
231   -/// \brief Bulk write to the oscilloscope.
232   -/// \param data Buffer for the sent/recieved data.
233   -/// \param length The length of the packet.
234   -/// \param attempts The number of attempts, that are done on timeouts.
235   -/// \return Number of sent bytes on success, libusb error code on error.
236   -int Device::bulkWrite(unsigned char *data, unsigned int length, int attempts) {
237   - if (!this->handle)
238   - return LIBUSB_ERROR_NO_DEVICE;
239   -
240   - int errorCode = this->getConnectionSpeed();
241   - if (errorCode < 0)
242   - return errorCode;
243   -
244   - return this->bulkTransfer(HANTEK_EP_OUT, data, length, attempts);
245   -}
246   -
247   -/// \brief Bulk read from the oscilloscope.
248   -/// \param data Buffer for the sent/recieved data.
249   -/// \param length The length of the packet.
250   -/// \param attempts The number of attempts, that are done on timeouts.
251   -/// \return Number of received bytes on success, libusb error code on error.
252   -int Device::bulkRead(unsigned char *data, unsigned int length, int attempts) {
253   - if (!this->handle)
254   - return LIBUSB_ERROR_NO_DEVICE;
255   -
256   - int errorCode = this->getConnectionSpeed();
257   - if (errorCode < 0)
258   - return errorCode;
259   -
260   - return this->bulkTransfer(HANTEK_EP_IN, data, length, attempts);
261   -}
262   -
263   -/// \brief Send a bulk command to the oscilloscope.
264   -/// \param command The command, that should be sent.
265   -/// \param attempts The number of attempts, that are done on timeouts.
266   -/// \return Number of sent bytes on success, libusb error code on error.
267   -int Device::bulkCommand(Helper::DataArray<unsigned char> *command,
268   - int attempts) {
269   - if (!this->handle)
270   - return LIBUSB_ERROR_NO_DEVICE;
271   -
272   - // don't send bulk command if dso6022be
273   - if (this->getModel() == MODEL_DSO6022BE)
274   - return 0;
275   -
276   - // Send BeginCommand control command
277   - int errorCode = this->controlWrite(CONTROL_BEGINCOMMAND,
278   - this->beginCommandControl->data(),
279   - this->beginCommandControl->getSize());
280   - if (errorCode < 0)
281   - return errorCode;
282   -
283   - // Send bulk command
284   - return this->bulkWrite(command->data(), command->getSize(), attempts);
285   -}
286   -
287   -/// \brief Multi packet bulk read from the oscilloscope.
288   -/// \param data Buffer for the sent/recieved data.
289   -/// \param length The length of data contained in the packets.
290   -/// \param attempts The number of attempts, that are done on timeouts.
291   -/// \return Number of received bytes on success, libusb error code on error.
292   -int Device::bulkReadMulti(unsigned char *data, unsigned int length,
293   - int attempts) {
294   - if (!this->handle)
295   - return LIBUSB_ERROR_NO_DEVICE;
296   -
297   - int errorCode = 0;
298   -
299   - errorCode = this->getConnectionSpeed();
300   - if (errorCode < 0)
301   - return errorCode;
302   -
303   - errorCode = this->inPacketLength;
304   - unsigned int packet, received = 0;
305   - for (packet = 0; received < length && errorCode == this->inPacketLength;
306   - ++packet) {
307   - errorCode = this->bulkTransfer(
308   - HANTEK_EP_IN, data + packet * this->inPacketLength,
309   - qMin(length - received, (unsigned int)this->inPacketLength), attempts,
310   - HANTEK_TIMEOUT_MULTI);
311   - if (errorCode > 0)
312   - received += errorCode;
313   - }
314   -
315   - if (received > 0)
316   - return received;
317   - else
318   - return errorCode;
319   -}
320   -
321   -/// \brief Control transfer to the oscilloscope.
322   -/// \param type The request type, also sets the direction of the transfer.
323   -/// \param request The request field of the packet.
324   -/// \param data Buffer for the sent/recieved data.
325   -/// \param length The length field of the packet.
326   -/// \param value The value field of the packet.
327   -/// \param index The index field of the packet.
328   -/// \param attempts The number of attempts, that are done on timeouts.
329   -/// \return Number of transferred bytes on success, libusb error code on error.
330   -int Device::controlTransfer(unsigned char type, unsigned char request,
331   - unsigned char *data, unsigned int length, int value,
332   - int index, int attempts) {
333   - if (!this->handle)
334   - return LIBUSB_ERROR_NO_DEVICE;
335   -
336   - int errorCode = LIBUSB_ERROR_TIMEOUT;
337   - for (int attempt = 0; (attempt < attempts || attempts == -1) &&
338   - errorCode == LIBUSB_ERROR_TIMEOUT;
339   - ++attempt)
340   - errorCode = libusb_control_transfer(this->handle, type, request, value,
341   - index, data, length, HANTEK_TIMEOUT);
342   -
343   - if (errorCode == LIBUSB_ERROR_NO_DEVICE)
344   - this->disconnect();
345   - return errorCode;
346   -}
347   -
348   -/// \brief Control write to the oscilloscope.
349   -/// \param request The request field of the packet.
350   -/// \param data Buffer for the sent/recieved data.
351   -/// \param length The length field of the packet.
352   -/// \param value The value field of the packet.
353   -/// \param index The index field of the packet.
354   -/// \param attempts The number of attempts, that are done on timeouts.
355   -/// \return Number of sent bytes on success, libusb error code on error.
356   -int Device::controlWrite(unsigned char request, unsigned char *data,
357   - unsigned int length, int value, int index,
358   - int attempts) {
359   - if (!this->handle)
360   - return LIBUSB_ERROR_NO_DEVICE;
361   -
362   - return this->controlTransfer(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
363   - request, data, length, value, index, attempts);
364   -}
365   -
366   -/// \brief Control read to the oscilloscope.
367   -/// \param request The request field of the packet.
368   -/// \param data Buffer for the sent/recieved data.
369   -/// \param length The length field of the packet.
370   -/// \param value The value field of the packet.
371   -/// \param index The index field of the packet.
372   -/// \param attempts The number of attempts, that are done on timeouts.
373   -/// \return Number of received bytes on success, libusb error code on error.
374   -int Device::controlRead(unsigned char request, unsigned char *data,
375   - unsigned int length, int value, int index,
376   - int attempts) {
377   - if (!this->handle)
378   - return LIBUSB_ERROR_NO_DEVICE;
379   -
380   - return this->controlTransfer(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
381   - request, data, length, value, index, attempts);
382   -}
383   -
384   -/// \brief Gets the speed of the connection.
385   -/// \return The ::ConnectionSpeed of the USB connection.
386   -int Device::getConnectionSpeed() {
387   - int errorCode;
388   - ControlGetSpeed response;
389   -
390   - errorCode =
391   - this->controlRead(CONTROL_GETSPEED, response.data(), response.getSize());
392   - if (errorCode < 0)
393   - return errorCode;
394   -
395   - return response.getSpeed();
396   -}
397   -
398   -/// \brief Gets the maximum size of one packet transmitted via bulk transfer.
399   -/// \return The maximum packet size in bytes, -1 on error.
400   -int Device::getPacketSize() {
401   - switch (this->getConnectionSpeed()) {
402   - case CONNECTION_FULLSPEED:
403   - return 64;
404   - break;
405   - case CONNECTION_HIGHSPEED:
406   - return 512;
407   - break;
408   - default:
409   - return -1;
410   - break;
411   - }
412   -}
413   -
414   -/// \brief Get the oscilloscope model.
415   -/// \return The ::Model of the connected Hantek DSO.
416   -Model Device::getModel() { return this->model; }
417   -}
openhantek/src/hantek/device.h deleted
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file hantek/device.h
5   -/// \brief Declares the Hantek::Device class.
6   -//
7   -/// \copyright (c) 2008, 2009 Oleg Khudyakov <prcoder@potrebitel.ru>
8   -/// \copyright (c) 2010 - 2012 Oliver Haag <oliver.haag@gmail.com>
9   -//
10   -// This program is free software: you can redistribute it and/or modify it
11   -// under the terms of the GNU General Public License as published by the Free
12   -// Software Foundation, either version 3 of the License, or (at your option)
13   -// any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful, but WITHOUT
16   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18   -// more details.
19   -//
20   -// You should have received a copy of the GNU General Public License along with
21   -// this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -////////////////////////////////////////////////////////////////////////////////
24   -
25   -#ifndef HANTEK_DEVICE_H
26   -#define HANTEK_DEVICE_H
27   -
28   -#include <QObject>
29   -#include <QStringList>
30   -#include <libusb-1.0/libusb.h>
31   -
32   -#include "hantek/types.h"
33   -#include "helper.h"
34   -
35   -namespace Hantek {
36   -//////////////////////////////////////////////////////////////////////////////
37   -/// \class Device hantek/device.h
38   -/// \brief This class handles the USB communication with the oscilloscope.
39   -class Device : public QObject {
40   - Q_OBJECT
41   -
42   -public:
43   - Device(QObject *parent = 0);
44   - ~Device();
45   -
46   - QString search();
47   - void disconnect();
48   - bool isConnected();
49   -
50   - // Various methods to handle USB transfers
51   - int bulkTransfer(unsigned char endpoint, unsigned char *data,
52   - unsigned int length, int attempts = HANTEK_ATTEMPTS,
53   - unsigned int timeout = HANTEK_TIMEOUT);
54   - int bulkWrite(unsigned char *data, unsigned int length,
55   - int attempts = HANTEK_ATTEMPTS);
56   - int bulkRead(unsigned char *data, unsigned int length,
57   - int attempts = HANTEK_ATTEMPTS);
58   -
59   - int bulkCommand(Helper::DataArray<unsigned char> *command,
60   - int attempts = HANTEK_ATTEMPTS);
61   - int bulkReadMulti(unsigned char *data, unsigned int length,
62   - int attempts = HANTEK_ATTEMPTS_MULTI);
63   -
64   - int controlTransfer(unsigned char type, unsigned char request,
65   - unsigned char *data, unsigned int length, int value,
66   - int index, int attempts = HANTEK_ATTEMPTS);
67   - int controlWrite(unsigned char request, unsigned char *data,
68   - unsigned int length, int value = 0, int index = 0,
69   - int attempts = HANTEK_ATTEMPTS);
70   - int controlRead(unsigned char request, unsigned char *data,
71   - unsigned int length, int value = 0, int index = 0,
72   - int attempts = HANTEK_ATTEMPTS);
73   -
74   - int getConnectionSpeed();
75   - int getPacketSize();
76   - Model getModel();
77   -
78   -protected:
79   - // Lists for enums
80   - QList<unsigned short int> modelIds; ///< Product ID for each ::Model
81   - QStringList modelStrings; ///< The name as QString for each ::Model
82   -
83   - // Command buffers
84   - ControlBeginCommand *beginCommandControl; ///< Buffer for the
85   - ///CONTROL_BEGINCOMMAND control
86   - ///command
87   -
88   - // Libusb specific variables
89   - libusb_context *context; ///< The usb context used for this device
90   - Model model; ///< The model of the connected oscilloscope
91   - libusb_device_handle *handle; ///< The USB handle for the oscilloscope
92   - libusb_device_descriptor
93   - descriptor; ///< The device descriptor of the oscilloscope
94   - int interface; ///< The number of the claimed interface
95   - int error; ///< The libusb error, that happened on initialization
96   - int outPacketLength; ///< Packet length for the OUT endpoint
97   - int inPacketLength; ///< Packet length for the IN endpoint
98   -
99   -signals:
100   - void connected(); ///< The device has been connected and initialized
101   - void disconnected(); ///< The device has been disconnected
102   -
103   -public slots:
104   -};
105   -}
106   -
107   -#endif
openhantek/src/hantek/control.cpp renamed to openhantek/src/hantek/hantekdsocontrol.cpp
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// hantek/control.cpp
5   -//
6   -// Copyright (C) 2008, 2009 Oleg Khudyakov
7   -// prcoder@potrebitel.ru
8   -// Copyright (C) 2010 - 2012 Oliver Haag
9   -// oliver.haag@gmail.com
10   -//
11   -// This program is free software: you can redistribute it and/or modify it
12   -// under the terms of the GNU General Public License as published by the Free
13   -// Software Foundation, either version 3 of the License, or (at your option)
14   -// any later version.
15   -//
16   -// This program is distributed in the hope that it will be useful, but WITHOUT
17   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19   -// more details.
20   -//
21   -// You should have received a copy of the GNU General Public License along with
22   -// this program. If not, see <http://www.gnu.org/licenses/>.
23   -//
24   -////////////////////////////////////////////////////////////////////////////////
  1 +// SPDX-License-Identifier: GPL-2.0+
25 2  
26 3 #include <cmath>
27 4 #include <limits>
... ... @@ -30,466 +7,752 @@
30 7 #include <QList>
31 8 #include <QMutex>
32 9 #include <QTimer>
  10 +#include <QDebug>
  11 +#include <QEventLoop>
33 12  
34   -#include "hantek/control.h"
  13 +#include "hantek/hantekdsocontrol.h"
35 14  
36   -#include "hantek/device.h"
37   -#include "hantek/types.h"
38   -#include "helper.h"
  15 +#include <stdexcept>
  16 +#include "usb/usbdevice.h"
  17 +#include "utils/printutils.h"
  18 +
  19 +using namespace Hantek;
  20 +
  21 +/// \brief Start sampling process.
  22 +void HantekDsoControl::startSampling() {
  23 + sampling = true;
  24 + emit samplingStarted();
  25 +}
  26 +
  27 +/// \brief Stop sampling process.
  28 +void HantekDsoControl::stopSampling() {
  29 + sampling = false;
  30 + emit samplingStopped();
  31 +}
  32 +
  33 +/// \brief Get a list of the names of the special trigger sources.
  34 +const QStringList *HantekDsoControl::getSpecialTriggerSources() {
  35 + return &(specialTriggerSources);
  36 +}
39 37  
40   -namespace Hantek {
41 38 /// \brief Initializes the command buffers and lists.
42 39 /// \param parent The parent widget.
43   -Control::Control(QTimer *mainTimer, QObject *parent) : DsoControl(parent) {
44   - // Use DSO-2090 specification as default
45   - this->specification.command.bulk.setRecordLength = (BulkCode)-1;
46   - this->specification.command.bulk.setChannels = (BulkCode)-1;
47   - this->specification.command.bulk.setGain = (BulkCode)-1;
48   - this->specification.command.bulk.setSamplerate = (BulkCode)-1;
49   - this->specification.command.bulk.setTrigger = (BulkCode)-1;
50   - this->specification.command.bulk.setPretrigger = (BulkCode)-1;
51   - this->specification.command.control.setOffset = (ControlCode)-1;
52   - this->specification.command.control.setRelays = (ControlCode)-1;
53   - this->specification.command.values.offsetLimits = (ControlValue)-1;
54   - this->specification.command.values.voltageLimits = (ControlValue)-1;
55   -
56   - this->specification.samplerate.single.base = 50e6;
57   - this->specification.samplerate.single.max = 50e6;
58   - this->specification.samplerate.single.recordLengths << 0;
59   - this->specification.samplerate.multi.base = 100e6;
60   - this->specification.samplerate.multi.max = 100e6;
61   - this->specification.samplerate.multi.recordLengths << 0;
62   -
63   - for (unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
64   - for (unsigned int gainId = 0; gainId < 9; ++gainId) {
65   - this->specification.offsetLimit[channel][gainId][OFFSET_START] = 0x0000;
66   - this->specification.offsetLimit[channel][gainId][OFFSET_END] = 0xffff;
  40 +HantekDsoControl::HantekDsoControl(USBDevice* device) : device(device) {
  41 + if (device==nullptr)
  42 + throw new std::runtime_error("No usb device for HantekDsoControl");
  43 +
  44 + // Use DSO-2090 specification as default
  45 + this->specification.command.bulk.setRecordLength = (BulkCode)-1;
  46 + this->specification.command.bulk.setChannels = (BulkCode)-1;
  47 + this->specification.command.bulk.setGain = (BulkCode)-1;
  48 + this->specification.command.bulk.setSamplerate = (BulkCode)-1;
  49 + this->specification.command.bulk.setTrigger = (BulkCode)-1;
  50 + this->specification.command.bulk.setPretrigger = (BulkCode)-1;
  51 + this->specification.command.control.setOffset = (ControlCode)-1;
  52 + this->specification.command.control.setRelays = (ControlCode)-1;
  53 + this->specification.command.values.offsetLimits = (ControlValue)-1;
  54 + this->specification.command.values.voltageLimits = (ControlValue)-1;
  55 +
  56 + this->specification.samplerate.single.base = 50e6;
  57 + this->specification.samplerate.single.max = 50e6;
  58 + this->specification.samplerate.single.recordLengths << 0;
  59 + this->specification.samplerate.multi.base = 100e6;
  60 + this->specification.samplerate.multi.max = 100e6;
  61 + this->specification.samplerate.multi.recordLengths << 0;
  62 +
  63 + for (unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
  64 + for (unsigned int gainId = 0; gainId < 9; ++gainId) {
  65 + this->specification.offsetLimit[channel][gainId][OFFSET_START] = 0x0000;
  66 + this->specification.offsetLimit[channel][gainId][OFFSET_END] = 0xffff;
  67 + }
  68 + }
  69 +
  70 + // Set settings to default values
  71 + this->settings.samplerate.limits = &(this->specification.samplerate.single);
  72 + this->settings.samplerate.downsampler = 1;
  73 + this->settings.samplerate.current = 1e8;
  74 + this->settings.trigger.position = 0;
  75 + this->settings.trigger.point = 0;
  76 + this->settings.trigger.mode = Dso::TRIGGERMODE_NORMAL;
  77 + this->settings.trigger.slope = Dso::SLOPE_POSITIVE;
  78 + this->settings.trigger.special = false;
  79 + this->settings.trigger.source = 0;
  80 + for (unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
  81 + this->settings.trigger.level[channel] = 0.0;
  82 + this->settings.voltage[channel].gain = 0;
  83 + this->settings.voltage[channel].offset = 0.0;
  84 + this->settings.voltage[channel].offsetReal = 0.0;
  85 + this->settings.voltage[channel].used = false;
  86 + }
  87 + this->settings.recordLengthId = 1;
  88 + this->settings.usedChannels = 0;
  89 +
  90 + // Special trigger sources
  91 + this->specialTriggerSources << tr("EXT") << tr("EXT/10");
  92 +
  93 + // Instantiate bulk command later, some are not the same for all models
  94 + for (int command = 0; command < BULK_COUNT; ++command) {
  95 + this->command[command] = 0;
  96 + this->commandPending[command] = false;
  97 + }
  98 +
  99 + // Transmission-ready control commands
  100 + this->control[CONTROLINDEX_SETOFFSET] = new ControlSetOffset();
  101 + this->controlCode[CONTROLINDEX_SETOFFSET] = CONTROL_SETOFFSET;
  102 + this->control[CONTROLINDEX_SETRELAYS] = new ControlSetRelays();
  103 + this->controlCode[CONTROLINDEX_SETRELAYS] = CONTROL_SETRELAYS;
  104 +
  105 + for (int control = 0; control < CONTROLINDEX_COUNT; ++control)
  106 + this->controlPending[control] = false;
  107 +
  108 + // State of the device
  109 + this->captureState = CAPTURE_WAITING;
  110 + this->rollState = 0;
  111 + this->_samplingStarted = false;
  112 + this->lastTriggerMode = (Dso::TriggerMode)-1;
  113 +
  114 + // Sample buffers
  115 + this->samples.resize(HANTEK_CHANNELS);
  116 +
  117 + this->previousSampleCount = 0;
  118 +
  119 + int errorCode;
  120 +
  121 + // Clean up commands and their pending state
  122 + for (int command = 0; command < BULK_COUNT; ++command) {
  123 + if (this->command[command])
  124 + delete this->command[command];
  125 + this->commandPending[command] = false;
  126 + }
  127 + // Instantiate the commands needed for all models
  128 + this->command[BULK_FORCETRIGGER] = new BulkForceTrigger();
  129 + this->command[BULK_STARTSAMPLING] = new BulkCaptureStart();
  130 + this->command[BULK_ENABLETRIGGER] = new BulkTriggerEnabled();
  131 + this->command[BULK_GETDATA] = new BulkGetData();
  132 + this->command[BULK_GETCAPTURESTATE] = new BulkGetCaptureState();
  133 + this->command[BULK_SETGAIN] = new BulkSetGain();
  134 + // Initialize the command versions to the ones used on the DSO-2090
  135 + this->specification.command.bulk.setRecordLength = (BulkCode)-1;
  136 + this->specification.command.bulk.setChannels = (BulkCode)-1;
  137 + this->specification.command.bulk.setGain = BULK_SETGAIN;
  138 + this->specification.command.bulk.setSamplerate = (BulkCode)-1;
  139 + this->specification.command.bulk.setTrigger = (BulkCode)-1;
  140 + this->specification.command.bulk.setPretrigger = (BulkCode)-1;
  141 + this->specification.command.control.setOffset = CONTROL_SETOFFSET;
  142 + this->specification.command.control.setRelays = CONTROL_SETRELAYS;
  143 + this->specification.command.values.offsetLimits = VALUE_OFFSETLIMITS;
  144 + this->specification.command.values.voltageLimits = (ControlValue)-1;
  145 +
  146 + // Determine the command version we need for this model
  147 + bool unsupported = false;
  148 + int lastControlIndex = 0;
  149 + switch (this->device->getUniqueModelID()) {
  150 + case MODEL_DSO2150:
  151 + unsupported = true;
  152 +
  153 + case MODEL_DSO2090:
  154 + // Instantiate additional commands for the DSO-2090
  155 + this->command[BULK_SETTRIGGERANDSAMPLERATE] =
  156 + new BulkSetTriggerAndSamplerate();
  157 + this->specification.command.bulk.setRecordLength =
  158 + BULK_SETTRIGGERANDSAMPLERATE;
  159 + this->specification.command.bulk.setChannels = BULK_SETTRIGGERANDSAMPLERATE;
  160 + this->specification.command.bulk.setSamplerate =
  161 + BULK_SETTRIGGERANDSAMPLERATE;
  162 + this->specification.command.bulk.setTrigger = BULK_SETTRIGGERANDSAMPLERATE;
  163 + this->specification.command.bulk.setPretrigger =
  164 + BULK_SETTRIGGERANDSAMPLERATE;
  165 + lastControlIndex = CONTROLINDEX_SETRELAYS;
  166 + // Initialize those as pending
  167 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  168 + break;
  169 +
  170 + case MODEL_DSO2250:
  171 + // Instantiate additional commands for the DSO-2250
  172 + this->command[BULK_BSETCHANNELS] = new BulkSetChannels2250();
  173 + this->command[BULK_CSETTRIGGERORSAMPLERATE] = new BulkSetTrigger2250();
  174 + this->command[BULK_DSETBUFFER] = new BulkSetRecordLength2250();
  175 + this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetSamplerate2250();
  176 + this->command[BULK_FSETBUFFER] = new BulkSetBuffer2250();
  177 + this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
  178 + this->specification.command.bulk.setChannels = BULK_BSETCHANNELS;
  179 + this->specification.command.bulk.setSamplerate =
  180 + BULK_ESETTRIGGERORSAMPLERATE;
  181 + this->specification.command.bulk.setTrigger = BULK_CSETTRIGGERORSAMPLERATE;
  182 + this->specification.command.bulk.setPretrigger = BULK_FSETBUFFER;
  183 + /// \todo Test if lastControlIndex is correct
  184 + lastControlIndex = CONTROLINDEX_SETRELAYS;
  185 +
  186 + this->commandPending[BULK_BSETCHANNELS] = true;
  187 + this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
  188 + this->commandPending[BULK_DSETBUFFER] = true;
  189 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  190 + this->commandPending[BULK_FSETBUFFER] = true;
  191 +
  192 + break;
  193 +
  194 + case MODEL_DSO5200A:
  195 + unsupported = true;
  196 +
  197 + case MODEL_DSO5200:
  198 + // Instantiate additional commands for the DSO-5200
  199 + this->command[BULK_CSETTRIGGERORSAMPLERATE] = new BulkSetSamplerate5200();
  200 + this->command[BULK_DSETBUFFER] = new BulkSetBuffer5200();
  201 + this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetTrigger5200();
  202 + this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
  203 + this->specification.command.bulk.setChannels = BULK_ESETTRIGGERORSAMPLERATE;
  204 + this->specification.command.bulk.setSamplerate =
  205 + BULK_CSETTRIGGERORSAMPLERATE;
  206 + this->specification.command.bulk.setTrigger = BULK_ESETTRIGGERORSAMPLERATE;
  207 + this->specification.command.bulk.setPretrigger =
  208 + BULK_ESETTRIGGERORSAMPLERATE;
  209 + // this->specification.command.values.voltageLimits = VALUE_ETSCORRECTION;
  210 + /// \todo Test if lastControlIndex is correct
  211 + lastControlIndex = CONTROLINDEX_SETRELAYS;
  212 +
  213 + this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
  214 + this->commandPending[BULK_DSETBUFFER] = true;
  215 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  216 +
  217 + break;
  218 +
  219 + case MODEL_DSO6022BE:
  220 + // 6022BE do not support any bulk commands
  221 + this->control[CONTROLINDEX_SETVOLTDIV_CH1] = new ControlSetVoltDIV_CH1();
  222 + this->controlCode[CONTROLINDEX_SETVOLTDIV_CH1] = CONTROL_SETVOLTDIV_CH1;
  223 + this->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true;
  224 +
  225 + this->control[CONTROLINDEX_SETVOLTDIV_CH2] = new ControlSetVoltDIV_CH2();
  226 + this->controlCode[CONTROLINDEX_SETVOLTDIV_CH2] = CONTROL_SETVOLTDIV_CH2;
  227 + this->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true;
  228 +
  229 + this->control[CONTROLINDEX_SETTIMEDIV] = new ControlSetTimeDIV();
  230 + this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
  231 + this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
  232 +
  233 + this->control[CONTROLINDEX_ACQUIIRE_HARD_DATA] =
  234 + new ControlAcquireHardData();
  235 + this->controlCode[CONTROLINDEX_ACQUIIRE_HARD_DATA] =
  236 + CONTROL_ACQUIIRE_HARD_DATA;
  237 + this->controlPending[CONTROLINDEX_ACQUIIRE_HARD_DATA] = true;
  238 + /// \todo Test if lastControlIndex is correct
  239 + lastControlIndex = CONTROLINDEX_ACQUIIRE_HARD_DATA;
  240 + break;
  241 +
  242 + default:
  243 + this->device->disconnect();
  244 + emit statusMessage(tr("Unknown model"), 0);
  245 + return;
  246 + }
  247 +
  248 + if (unsupported)
  249 + qWarning("Warning: This Hantek DSO model isn't supported officially, so it "
  250 + "may not be working as expected. Reports about your experiences "
  251 + "are very welcome though (Please open a feature request in the "
  252 + "tracker at https://sf.net/projects/openhantek/ or email me "
  253 + "directly to oliver.haag@gmail.com). If it's working perfectly I "
  254 + "can remove this warning, if not it should be possible to get it "
  255 + "working with your help soon.");
  256 +
  257 + for (int control = 0; control <= lastControlIndex; ++control)
  258 + this->controlPending[control] = true;
  259 +
  260 + // Disable controls not supported by 6022BE
  261 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE) {
  262 + this->controlPending[CONTROLINDEX_SETOFFSET] = false;
  263 + this->controlPending[CONTROLINDEX_SETRELAYS] = false;
  264 + }
  265 +
  266 + // Maximum possible samplerate for a single channel and dividers for record
  267 + // lengths
  268 + this->specification.bufferDividers.clear();
  269 + this->specification.samplerate.single.recordLengths.clear();
  270 + this->specification.samplerate.multi.recordLengths.clear();
  271 + this->specification.gainSteps.clear();
  272 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
  273 + this->specification.voltageLimit[channel].clear();
  274 +
  275 + switch (this->device->getUniqueModelID()) {
  276 + case MODEL_DSO5200:
  277 + case MODEL_DSO5200A:
  278 + this->specification.samplerate.single.base = 100e6;
  279 + this->specification.samplerate.single.max = 125e6;
  280 + this->specification.samplerate.single.maxDownsampler = 131072;
  281 + this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
  282 + << 14336;
  283 + this->specification.samplerate.multi.base = 200e6;
  284 + this->specification.samplerate.multi.max = 250e6;
  285 + this->specification.samplerate.multi.maxDownsampler = 131072;
  286 + this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
  287 + << 28672;
  288 + this->specification.bufferDividers << 1000 << 1 << 1;
  289 + this->specification.gainSteps << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0
  290 + << 16.0 << 40.0 << 80.0;
  291 + /// \todo Use calibration data to get the DSO-5200(A) sample ranges
  292 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
  293 + this->specification.voltageLimit[channel]
  294 + << 368 << 454 << 908 << 368 << 454 << 908 << 368 << 454 << 908;
  295 + this->specification.gainIndex << 1 << 0 << 0 << 1 << 0 << 0 << 1 << 0 << 0;
  296 + this->specification.sampleSize = 10;
  297 + break;
  298 +
  299 + case MODEL_DSO2250:
  300 + this->specification.samplerate.single.base = 100e6;
  301 + this->specification.samplerate.single.max = 100e6;
  302 + this->specification.samplerate.single.maxDownsampler = 65536;
  303 + this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
  304 + << 524288;
  305 + this->specification.samplerate.multi.base = 200e6;
  306 + this->specification.samplerate.multi.max = 250e6;
  307 + this->specification.samplerate.multi.maxDownsampler = 65536;
  308 + this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
  309 + << 1048576;
  310 + this->specification.bufferDividers << 1000 << 1 << 1;
  311 + this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
  312 + << 4.00 << 8.0 << 16.0 << 40.0;
  313 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
  314 + this->specification.voltageLimit[channel]
  315 + << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255;
  316 + this->specification.gainIndex << 0 << 2 << 3 << 0 << 2 << 3 << 0 << 2 << 3;
  317 + this->specification.sampleSize = 8;
  318 + break;
  319 +
  320 + case MODEL_DSO2150:
  321 + this->specification.samplerate.single.base = 50e6;
  322 + this->specification.samplerate.single.max = 75e6;
  323 + this->specification.samplerate.single.maxDownsampler = 131072;
  324 + this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
  325 + << 32768;
  326 + this->specification.samplerate.multi.base = 100e6;
  327 + this->specification.samplerate.multi.max = 150e6;
  328 + this->specification.samplerate.multi.maxDownsampler = 131072;
  329 + this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
  330 + << 65536;
  331 + this->specification.bufferDividers << 1000 << 1 << 1;
  332 + this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
  333 + << 4.00 << 8.0 << 16.0 << 40.0;
  334 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
  335 + this->specification.voltageLimit[channel]
  336 + << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255;
  337 + this->specification.gainIndex << 0 << 1 << 2 << 0 << 1 << 2 << 0 << 1 << 2;
  338 + this->specification.sampleSize = 8;
  339 + break;
  340 +
  341 + case MODEL_DSO6022BE:
  342 + this->specification.samplerate.single.base = 1e6;
  343 + this->specification.samplerate.single.max = 48e6;
  344 + this->specification.samplerate.single.maxDownsampler = 10;
  345 + this->specification.samplerate.single.recordLengths << UINT_MAX << 10240;
  346 + this->specification.samplerate.multi.base = 1e6;
  347 + this->specification.samplerate.multi.max = 48e6;
  348 + this->specification.samplerate.multi.maxDownsampler = 10;
  349 + this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480;
  350 + this->specification.bufferDividers << 1000 << 1 << 1;
  351 + this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
  352 + << 4.00 << 8.0 << 16.0 << 40.0;
  353 + // This data was based on testing and depends on Divider.
  354 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
  355 + this->specification.voltageLimit[channel] << 25 << 51 << 103 << 206 << 412
  356 + << 196 << 392 << 784 << 1000;
  357 + // Divider. Tested and calculated results are different!
  358 + this->specification.gainDiv << 10 << 10 << 10 << 10 << 10 << 2 << 2 << 2
  359 + << 1;
  360 + this->specification.sampleSteps << 1e5 << 2e5 << 5e5 << 1e6 << 2e6 << 4e6
  361 + << 8e6 << 16e6 << 24e6 << 48e6;
  362 + this->specification.sampleDiv << 10 << 20 << 50 << 1 << 2 << 4 << 8 << 16
  363 + << 24 << 48;
  364 + this->specification.sampleSize = 8;
  365 + break;
  366 +
  367 + default:
  368 + this->specification.samplerate.single.base = 50e6;
  369 + this->specification.samplerate.single.max = 50e6;
  370 + this->specification.samplerate.single.maxDownsampler = 131072;
  371 + this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
  372 + << 32768;
  373 + this->specification.samplerate.multi.base = 100e6;
  374 + this->specification.samplerate.multi.max = 100e6;
  375 + this->specification.samplerate.multi.maxDownsampler = 131072;
  376 + this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
  377 + << 65536;
  378 + this->specification.bufferDividers << 1000 << 1 << 1;
  379 + this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
  380 + << 4.00 << 8.0 << 16.0 << 40.0;
  381 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
  382 + this->specification.voltageLimit[channel]
  383 + << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255;
  384 + this->specification.gainIndex << 0 << 1 << 2 << 0 << 1 << 2 << 0 << 1 << 2;
  385 + this->specification.sampleSize = 8;
  386 + break;
67 387 }
68   - }
69   -
70   - // Set settings to default values
71   - this->settings.samplerate.limits = &(this->specification.samplerate.single);
72   - this->settings.samplerate.downsampler = 1;
73   - this->settings.samplerate.current = 1e8;
74   - this->settings.trigger.position = 0;
75   - this->settings.trigger.point = 0;
76   - this->settings.trigger.mode = Dso::TRIGGERMODE_NORMAL;
77   - this->settings.trigger.slope = Dso::SLOPE_POSITIVE;
78   - this->settings.trigger.special = false;
79   - this->settings.trigger.source = 0;
80   - for (unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
81   - this->settings.trigger.level[channel] = 0.0;
82   - this->settings.voltage[channel].gain = 0;
83   - this->settings.voltage[channel].offset = 0.0;
84   - this->settings.voltage[channel].offsetReal = 0.0;
85   - this->settings.voltage[channel].used = false;
86   - }
87   - this->settings.recordLengthId = 1;
88   - this->settings.usedChannels = 0;
89   -
90   - // Special trigger sources
91   - this->specialTriggerSources << tr("EXT") << tr("EXT/10");
92   -
93   - // Instantiate bulk command later, some are not the same for all models
94   - for (int command = 0; command < BULK_COUNT; ++command) {
95   - this->command[command] = 0;
96   - this->commandPending[command] = false;
97   - }
98   -
99   - // Transmission-ready control commands
100   - this->control[CONTROLINDEX_SETOFFSET] = new ControlSetOffset();
101   - this->controlCode[CONTROLINDEX_SETOFFSET] = CONTROL_SETOFFSET;
102   - this->control[CONTROLINDEX_SETRELAYS] = new ControlSetRelays();
103   - this->controlCode[CONTROLINDEX_SETRELAYS] = CONTROL_SETRELAYS;
104   -
105   - for (int control = 0; control < CONTROLINDEX_COUNT; ++control)
106   - this->controlPending[control] = false;
107   -
108   - // USB device
109   - this->device = new Device(this);
110   -
111   - // Thread execution timer
112   - this->timer = mainTimer;
113   -
114   - // State of the device
115   - this->captureState = CAPTURE_WAITING;
116   - this->rollState = 0;
117   - this->samplingStarted = false;
118   - this->lastTriggerMode = (Dso::TriggerMode)-1;
119   -
120   - // Sample buffers
121   - this->samples.resize(HANTEK_CHANNELS);
122   -
123   - this->previousSampleCount = 0;
124   -
125   - connect(this->device, SIGNAL(disconnected()), this, SLOT(disconnectDevice()));
  388 + this->settings.recordLengthId = 1;
  389 + this->settings.samplerate.limits = &(this->specification.samplerate.single);
  390 + this->settings.samplerate.downsampler = 1;
  391 + this->previousSampleCount = 0;
  392 +
  393 + // Get channel level data
  394 + errorCode = this->device->controlRead(
  395 + CONTROL_VALUE, (unsigned char *)&(this->specification.offsetLimit),
  396 + sizeof(this->specification.offsetLimit), (int)VALUE_OFFSETLIMITS);
  397 + if (errorCode < 0) {
  398 + this->device->disconnect();
  399 + emit statusMessage(tr("Couldn't get channel level data from oscilloscope"),
  400 + 0);
  401 + return;
  402 + }
  403 +
  404 + // Emit signals for initial settings
  405 + emit availableRecordLengthsChanged(
  406 + this->settings.samplerate.limits->recordLengths);
  407 + updateSamplerateLimits();
  408 + emit recordLengthChanged(this->settings.samplerate.limits
  409 + ->recordLengths[this->settings.recordLengthId]);
  410 + if (this->settings.samplerate.limits
  411 + ->recordLengths[this->settings.recordLengthId] != UINT_MAX)
  412 + emit recordTimeChanged((double)this->settings.samplerate.limits
  413 + ->recordLengths[this->settings.recordLengthId] /
  414 + this->settings.samplerate.current);
  415 + emit samplerateChanged(this->settings.samplerate.current);
  416 +
  417 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE) {
  418 + QList<double> sampleSteps;
  419 + sampleSteps << 1.0 << 2.0 << 5.0 << 10.0 << 20.0 << 40.0 << 80.0 << 160.0
  420 + << 240.0 << 480.0;
  421 + emit samplerateSet(1, sampleSteps);
  422 + }
  423 +
  424 + sampling = false;
126 425 }
127 426  
128 427 /// \brief Disconnects the device.
129   -Control::~Control() {
130   - this->device->disconnect();
131   -
132   - // Clean up commands
133   - for (int command = 0; command < BULK_COUNT; ++command) {
134   - if (this->command[command])
135   - delete this->command[command];
136   - }
  428 +HantekDsoControl::~HantekDsoControl() {
  429 + // Clean up commands
  430 + for (int command = 0; command < BULK_COUNT; ++command) {
  431 + if (this->command[command])
  432 + delete this->command[command];
  433 + }
137 434 }
138 435  
139 436 /// \brief Gets the physical channel count for this oscilloscope.
140 437 /// \return The number of physical channels.
141   -unsigned int Control::getChannelCount() { return HANTEK_CHANNELS; }
  438 +unsigned int HantekDsoControl::getChannelCount() { return HANTEK_CHANNELS; }
142 439  
143 440 /// \brief Get available record lengths for this oscilloscope.
144 441 /// \return The number of physical channels, empty list for continuous.
145   -QList<unsigned int> *Control::getAvailableRecordLengths() {
146   - return &this->settings.samplerate.limits->recordLengths;
  442 +QList<unsigned int> *HantekDsoControl::getAvailableRecordLengths() {
  443 + return &this->settings.samplerate.limits->recordLengths;
147 444 }
148 445  
149 446 /// \brief Get minimum samplerate for this oscilloscope.
150 447 /// \return The minimum samplerate for the current configuration in S/s.
151   -double Control::getMinSamplerate() {
152   - return (double)this->specification.samplerate.single.base /
153   - this->specification.samplerate.single.maxDownsampler;
  448 +double HantekDsoControl::getMinSamplerate() {
  449 + return (double)this->specification.samplerate.single.base /
  450 + this->specification.samplerate.single.maxDownsampler;
154 451 }
155 452  
156 453 /// \brief Get maximum samplerate for this oscilloscope.
157 454 /// \return The maximum samplerate for the current configuration in S/s.
158   -double Control::getMaxSamplerate() {
159   - ControlSamplerateLimits *limits =
160   - (this->settings.usedChannels <= 1)
161   - ? &this->specification.samplerate.multi
162   - : &this->specification.samplerate.single;
163   - return limits->max;
164   -}
165   -
166   -/// \brief Handles all USB things until the device gets disconnected.
167   -void Control::run() {
168   - // Initialize communication thread state
169   - this->captureState = CAPTURE_WAITING;
170   - this->rollState = 0;
171   - this->samplingStarted = false;
172   - this->lastTriggerMode = (Dso::TriggerMode)-1;
173   -
174   - this->cycleCounter = 0;
175   - this->startCycle = 0;
176   -
177   - this->updateInterval();
178   - this->timer->start();
179   -
180   - // The control loop is running until the device is disconnected
181   - exec();
182   -
183   - this->timer->stop();
184   - this->device->disconnect();
185   -
186   - delete this->timer;
187   - this->timer = 0;
188   -
189   - emit statusMessage(tr("The device has been disconnected"), 0);
  455 +double HantekDsoControl::getMaxSamplerate() {
  456 + ControlSamplerateLimits *limits =
  457 + (this->settings.usedChannels <= 1)
  458 + ? &this->specification.samplerate.multi
  459 + : &this->specification.samplerate.single;
  460 + return limits->max;
190 461 }
191 462  
192 463 /// \brief Updates the interval of the periodic thread timer.
193   -void Control::updateInterval() {
194   - if (!this->timer)
195   - return;
196   -
197   - int cycleTime;
198   -
199   - // Check the current oscilloscope state everytime 25% of the time the buffer
200   - // should be refilled
201   - if (this->settings.samplerate.limits
202   - ->recordLengths[this->settings.recordLengthId] == UINT_MAX)
203   - cycleTime = (int)((double)this->device->getPacketSize() /
204   - ((this->settings.samplerate.limits ==
205   - &this->specification.samplerate.multi)
  464 +void HantekDsoControl::updateInterval() {
  465 + // Check the current oscilloscope state everytime 25% of the time the buffer
  466 + // should be refilled
  467 + if (this->settings.samplerate.limits
  468 + ->recordLengths[this->settings.recordLengthId] == UINT_MAX)
  469 + cycleTime = (int)((double)this->device->getPacketSize() /
  470 + ((this->settings.samplerate.limits ==
  471 + &this->specification.samplerate.multi)
206 472 ? 1
207 473 : HANTEK_CHANNELS) /
208   - this->settings.samplerate.current * 250);
209   - else
210   - cycleTime = (int)((double)this->settings.samplerate.limits
  474 + this->settings.samplerate.current * 250);
  475 + else
  476 + cycleTime = (int)((double)this->settings.samplerate.limits
211 477 ->recordLengths[this->settings.recordLengthId] /
212   - this->settings.samplerate.current * 250);
  478 + this->settings.samplerate.current * 250);
213 479  
214   - // Not more often than every 10 ms though but at least once every second
215   - cycleTime = qBound(10, cycleTime, 1000);
216   -
217   - this->timer->setInterval(cycleTime);
  480 + // Not more often than every 10 ms though but at least once every second
  481 + cycleTime = qBound(10, cycleTime, 1000);
218 482 }
219 483  
220 484 /// \brief Calculates the trigger point from the CommandGetCaptureState data.
221 485 /// \param value The data value that contains the trigger point.
222 486 /// \return The calculated trigger point for the given data.
223   -unsigned int Control::calculateTriggerPoint(unsigned int value) {
224   - unsigned int result = value;
  487 +unsigned int HantekDsoControl::calculateTriggerPoint(unsigned int value) {
  488 + unsigned int result = value;
225 489  
226   - // Each set bit inverts all bits with a lower value
227   - for (unsigned int bitValue = 1; bitValue; bitValue <<= 1)
228   - if (result & bitValue)
229   - result ^= bitValue - 1;
  490 + // Each set bit inverts all bits with a lower value
  491 + for (unsigned int bitValue = 1; bitValue; bitValue <<= 1)
  492 + if (result & bitValue)
  493 + result ^= bitValue - 1;
230 494  
231   - return result;
  495 + return result;
232 496 }
233 497  
234 498 /// \brief Gets the current state.
235 499 /// \return The current CaptureState of the oscilloscope, libusb error code on
236 500 /// error.
237   -int Control::getCaptureState() {
238   - int errorCode;
  501 +int HantekDsoControl::getCaptureState() {
  502 + int errorCode;
239 503  
240   - // Command not supported by this model
241   - if (this->device->getModel() == MODEL_DSO6022BE)
242   - return CAPTURE_READY;
  504 + // Command not supported by this model
  505 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE)
  506 + return CAPTURE_READY;
243 507  
244   - errorCode = this->device->bulkCommand(this->command[BULK_GETCAPTURESTATE], 1);
245   - if (errorCode < 0)
246   - return errorCode;
  508 + errorCode = this->device->bulkCommand(this->command[BULK_GETCAPTURESTATE], 1);
  509 + if (errorCode < 0)
  510 + return errorCode;
247 511  
248   - BulkResponseGetCaptureState response;
249   - errorCode = this->device->bulkRead(response.data(), response.getSize());
250   - if (errorCode < 0)
251   - return errorCode;
  512 + BulkResponseGetCaptureState response;
  513 + errorCode = this->device->bulkRead(response.data(), response.getSize());
  514 + if (errorCode < 0)
  515 + return errorCode;
252 516  
253   - this->settings.trigger.point =
254   - this->calculateTriggerPoint(response.getTriggerPoint());
  517 + this->settings.trigger.point =
  518 + this->calculateTriggerPoint(response.getTriggerPoint());
255 519  
256   - return (int)response.getCaptureState();
  520 + return (int)response.getCaptureState();
257 521 }
258 522  
259 523 /// \brief Gets sample data from the oscilloscope and converts it.
260 524 /// \return sample count on success, libusb error code on error.
261   -int Control::getSamples(bool process) {
262   - int errorCode;
  525 +int HantekDsoControl::getSamples(bool process) {
  526 + int errorCode;
263 527  
264   - const unsigned int DROP_DSO6022_HEAD = 0x410;
265   - const unsigned int DROP_DSO6022_TAIL = 0x3F0;
  528 + const unsigned int DROP_DSO6022_HEAD = 0x410;
  529 + const unsigned int DROP_DSO6022_TAIL = 0x3F0;
266 530  
267   - if (this->device->getModel() != MODEL_DSO6022BE) {
268   - // Request data
269   - errorCode = this->device->bulkCommand(this->command[BULK_GETDATA], 1);
270   - if (errorCode < 0)
271   - return errorCode;
272   - }
273   -
274   - // Save raw data to temporary buffer
275   - bool fastRate = false;
276   - unsigned int totalSampleCount = this->getSampleCount(&fastRate);
277   - if (totalSampleCount == UINT_MAX)
278   - return LIBUSB_ERROR_INVALID_PARAM;
279   -
280   - // To make sure no samples will remain in the scope buffer, also check the
281   - // sample count before the last sampling started
282   - if (totalSampleCount < this->previousSampleCount) {
283   - unsigned int currentSampleCount = totalSampleCount;
284   - totalSampleCount = this->previousSampleCount;
285   - this->previousSampleCount =
286   - currentSampleCount; // Using sampleCount as temporary buffer since it
287   - // was set to totalSampleCount
288   - } else {
289   - this->previousSampleCount = totalSampleCount;
290   - }
291   -
292   - unsigned int sampleCount = totalSampleCount;
293   - if (!fastRate)
294   - sampleCount /= HANTEK_CHANNELS;
295   - unsigned int dataLength = totalSampleCount;
296   - if (this->specification.sampleSize > 8)
297   - dataLength *= 2;
298   -
299   - std::vector<unsigned char> data(dataLength);
300   - errorCode = this->device->bulkReadMulti(data.data(), dataLength);
301   - if (errorCode < 0)
302   - return errorCode;
  531 + if (this->device->getUniqueModelID() != MODEL_DSO6022BE) {
  532 + // Request data
  533 + errorCode = this->device->bulkCommand(this->command[BULK_GETDATA], 1);
  534 + if (errorCode < 0)
  535 + return errorCode;
  536 + }
303 537  
304   - // Process the data only if we want it
305   - if (process) {
306   - // How much data did we really receive?
307   - dataLength = errorCode;
  538 + // Save raw data to temporary buffer
  539 + bool fastRate = false;
  540 + unsigned int totalSampleCount = this->getSampleCount(&fastRate);
  541 + if (totalSampleCount == UINT_MAX)
  542 + return LIBUSB_ERROR_INVALID_PARAM;
  543 +
  544 + // To make sure no samples will remain in the scope buffer, also check the
  545 + // sample count before the last sampling started
  546 + if (totalSampleCount < this->previousSampleCount) {
  547 + unsigned int currentSampleCount = totalSampleCount;
  548 + totalSampleCount = this->previousSampleCount;
  549 + this->previousSampleCount =
  550 + currentSampleCount; // Using sampleCount as temporary buffer since it
  551 + // was set to totalSampleCount
  552 + } else {
  553 + this->previousSampleCount = totalSampleCount;
  554 + }
  555 +
  556 + unsigned int sampleCount = totalSampleCount;
  557 + if (!fastRate)
  558 + sampleCount /= HANTEK_CHANNELS;
  559 + unsigned int dataLength = totalSampleCount;
308 560 if (this->specification.sampleSize > 8)
309   - totalSampleCount = dataLength / 2;
310   - else
311   - totalSampleCount = dataLength;
312   -
313   - this->samplesMutex.lock();
314   -
315   - // Convert channel data
316   - if (fastRate) {
317   - // Fast rate mode, one channel is using all buffers
318   - sampleCount = totalSampleCount;
319   - int channel = 0;
320   - for (; channel < HANTEK_CHANNELS; ++channel) {
321   - if (this->settings.voltage[channel].used)
322   - break;
323   - }
324   -
325   - // Clear unused channels
326   - for (int channelCounter = 0; channelCounter < HANTEK_CHANNELS;
327   - ++channelCounter)
328   - if (channelCounter != channel) {
329   -
330   - this->samples[channelCounter].clear();
331   - }
  561 + dataLength *= 2;
332 562  
333   - if (channel < HANTEK_CHANNELS) {
334   - // Resize sample vector
335   - this->samples[channel].resize(sampleCount);
336   -
337   - // Convert data from the oscilloscope and write it into the sample
338   - // buffer
339   - unsigned int bufferPosition = this->settings.trigger.point * 2;
340   - if (this->specification.sampleSize > 8) {
341   - // Additional most significant bits after the normal data
342   - unsigned int extraBitsPosition; // Track the position of the extra
343   - // bits in the additional byte
344   - unsigned int extraBitsSize =
345   - this->specification.sampleSize - 8; // Number of extra bits
346   - unsigned short int extraBitsMask =
347   - (0x00ff << extraBitsSize) &
348   - 0xff00; // Mask for extra bits extraction
349   -
350   - for (unsigned int realPosition = 0; realPosition < sampleCount;
351   - ++realPosition, ++bufferPosition) {
352   - if (bufferPosition >= sampleCount)
353   - bufferPosition %= sampleCount;
354   -
355   - extraBitsPosition = bufferPosition % HANTEK_CHANNELS;
356   -
357   - this->samples[channel][realPosition] =
358   - ((double)((unsigned short int)data[bufferPosition] +
359   - (((unsigned short int)
360   - data[sampleCount + bufferPosition -
361   - extraBitsPosition]
362   - << (8 -
363   - (HANTEK_CHANNELS - 1 - extraBitsPosition) *
364   - extraBitsSize)) &
365   - extraBitsMask)) /
366   - this->specification
367   - .voltageLimit[channel]
368   - [this->settings.voltage[channel].gain] -
369   - this->settings.voltage[channel].offsetReal) *
370   - this->specification
371   - .gainSteps[this->settings.voltage[channel].gain];
372   - }
373   - } else {
374   - for (unsigned int realPosition = 0; realPosition < sampleCount;
375   - ++realPosition, ++bufferPosition) {
376   - if (bufferPosition >= sampleCount)
377   - bufferPosition %= sampleCount;
378   -
379   - double dataBuf = (double)((int)data[bufferPosition]);
380   - this->samples[channel][realPosition] =
381   - (dataBuf /
382   - this->specification
383   - .voltageLimit[channel]
384   - [this->settings.voltage[channel].gain] -
385   - this->settings.voltage[channel].offsetReal) *
386   - this->specification
387   - .gainSteps[this->settings.voltage[channel].gain];
388   - }
389   - }
390   - }
391   - } else {
392   - // Normal mode, channels are using their separate buffers
393   - sampleCount = totalSampleCount / HANTEK_CHANNELS;
394   - // if device is 6022BE, drop heading & trailing samples
395   - if (this->device->getModel() == MODEL_DSO6022BE)
396   - sampleCount -= (DROP_DSO6022_HEAD + DROP_DSO6022_TAIL);
397   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
398   - if (this->settings.voltage[channel].used) {
399   - // Resize sample vector
400   - if (samples[channel].size() < sampleCount) {
401   - this->samples[channel].resize(sampleCount);
402   - }
403   -
404   - // Convert data from the oscilloscope and write it into the sample
405   - // buffer
406   - unsigned int bufferPosition = this->settings.trigger.point * 2;
407   - if (this->specification.sampleSize > 8) {
408   - // Additional most significant bits after the normal data
409   - unsigned int extraBitsSize =
410   - this->specification.sampleSize - 8; // Number of extra bits
411   - unsigned short int extraBitsMask =
412   - (0x00ff << extraBitsSize) &
413   - 0xff00; // Mask for extra bits extraction
414   - unsigned int extraBitsIndex =
415   - 8 -
416   - channel * 2; // Bit position offset for extra bits extraction
417   -
418   - for (unsigned int realPosition = 0; realPosition < sampleCount;
419   - ++realPosition, bufferPosition += HANTEK_CHANNELS) {
420   - if (bufferPosition >= totalSampleCount)
421   - bufferPosition %= totalSampleCount;
422   -
423   - this->samples[channel][realPosition] =
424   - ((double)((unsigned short int)
425   - data[bufferPosition + HANTEK_CHANNELS - 1 -
426   - channel] +
427   - (((unsigned short int)
428   - data[totalSampleCount + bufferPosition]
429   - << extraBitsIndex) &
430   - extraBitsMask)) /
431   - this->specification
432   - .voltageLimit[channel]
433   - [this->settings.voltage[channel].gain] -
434   - this->settings.voltage[channel].offsetReal) *
435   - this->specification
436   - .gainSteps[this->settings.voltage[channel].gain];
  563 + std::vector<unsigned char> data(dataLength);
  564 + errorCode = this->device->bulkReadMulti(data.data(), dataLength);
  565 + if (errorCode < 0)
  566 + return errorCode;
  567 +
  568 + // Process the data only if we want it
  569 + if (process) {
  570 + // How much data did we really receive?
  571 + dataLength = errorCode;
  572 + if (this->specification.sampleSize > 8)
  573 + totalSampleCount = dataLength / 2;
  574 + else
  575 + totalSampleCount = dataLength;
  576 +
  577 + QMutexLocker locker(&samplesMutex);
  578 +
  579 + // Convert channel data
  580 + if (fastRate) {
  581 + // Fast rate mode, one channel is using all buffers
  582 + sampleCount = totalSampleCount;
  583 + int channel = 0;
  584 + for (; channel < HANTEK_CHANNELS; ++channel) {
  585 + if (this->settings.voltage[channel].used)
  586 + break;
437 587 }
438   - } else {
439   - if (this->device->getModel() == MODEL_DSO6022BE) {
440   - bufferPosition += channel;
441   - // if device is 6022BE, offset DROP_DSO6022_HEAD incrementally
442   - bufferPosition += DROP_DSO6022_HEAD * 2;
443   - } else
444   - bufferPosition += HANTEK_CHANNELS - 1 - channel;
445   -
446   - for (unsigned int realPosition = 0; realPosition < sampleCount;
447   - ++realPosition, bufferPosition += HANTEK_CHANNELS) {
448   - if (bufferPosition >= totalSampleCount)
449   - bufferPosition %= totalSampleCount;
450   -
451   - if (this->device->getModel() == MODEL_DSO6022BE) {
452   - double dataBuf = (double)((int)(data[bufferPosition] - 0x83));
453   - this->samples[channel][realPosition] =
454   - (dataBuf /
455   - this->specification
456   - .voltageLimit[channel]
457   - [this->settings.voltage[channel].gain]) *
458   - this->specification
459   - .gainSteps[this->settings.voltage[channel].gain];
460   - } else {
461   - double dataBuf = (double)((int)(data[bufferPosition]));
462   - this->samples[channel][realPosition] =
463   - (dataBuf /
464   - this->specification.voltageLimit
465   - [channel][this->settings.voltage[channel].gain] -
466   - this->settings.voltage[channel].offsetReal) *
467   - this->specification
468   - .gainSteps[this->settings.voltage[channel].gain];
469   - }
  588 +
  589 + // Clear unused channels
  590 + for (int channelCounter = 0; channelCounter < HANTEK_CHANNELS;
  591 + ++channelCounter)
  592 + if (channelCounter != channel) {
  593 +
  594 + this->samples[channelCounter].clear();
  595 + }
  596 +
  597 + if (channel < HANTEK_CHANNELS) {
  598 + // Resize sample vector
  599 + this->samples[channel].resize(sampleCount);
  600 +
  601 + // Convert data from the oscilloscope and write it into the sample
  602 + // buffer
  603 + unsigned int bufferPosition = this->settings.trigger.point * 2;
  604 + if (this->specification.sampleSize > 8) {
  605 + // Additional most significant bits after the normal data
  606 + unsigned int extraBitsPosition; // Track the position of the extra
  607 + // bits in the additional byte
  608 + unsigned int extraBitsSize =
  609 + this->specification.sampleSize - 8; // Number of extra bits
  610 + unsigned short int extraBitsMask =
  611 + (0x00ff << extraBitsSize) &
  612 + 0xff00; // Mask for extra bits extraction
  613 +
  614 + for (unsigned int realPosition = 0; realPosition < sampleCount;
  615 + ++realPosition, ++bufferPosition) {
  616 + if (bufferPosition >= sampleCount)
  617 + bufferPosition %= sampleCount;
  618 +
  619 + extraBitsPosition = bufferPosition % HANTEK_CHANNELS;
  620 +
  621 + this->samples[channel][realPosition] =
  622 + ((double)((unsigned short int)data[bufferPosition] +
  623 + (((unsigned short int)
  624 + data[sampleCount + bufferPosition -
  625 + extraBitsPosition]
  626 + << (8 -
  627 + (HANTEK_CHANNELS - 1 - extraBitsPosition) *
  628 + extraBitsSize)) &
  629 + extraBitsMask)) /
  630 + this->specification
  631 + .voltageLimit[channel]
  632 + [this->settings.voltage[channel].gain] -
  633 + this->settings.voltage[channel].offsetReal) *
  634 + this->specification
  635 + .gainSteps[this->settings.voltage[channel].gain];
  636 + }
  637 + } else {
  638 + for (unsigned int realPosition = 0; realPosition < sampleCount;
  639 + ++realPosition, ++bufferPosition) {
  640 + if (bufferPosition >= sampleCount)
  641 + bufferPosition %= sampleCount;
  642 +
  643 + double dataBuf = (double)((int)data[bufferPosition]);
  644 + this->samples[channel][realPosition] =
  645 + (dataBuf /
  646 + this->specification
  647 + .voltageLimit[channel]
  648 + [this->settings.voltage[channel].gain] -
  649 + this->settings.voltage[channel].offsetReal) *
  650 + this->specification
  651 + .gainSteps[this->settings.voltage[channel].gain];
  652 + }
  653 + }
470 654 }
471   - }
472 655 } else {
473   - // Clear unused channels
474   - this->samples[channel].clear();
  656 + // Normal mode, channels are using their separate buffers
  657 + sampleCount = totalSampleCount / HANTEK_CHANNELS;
  658 + // if device is 6022BE, drop heading & trailing samples
  659 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE)
  660 + sampleCount -= (DROP_DSO6022_HEAD + DROP_DSO6022_TAIL);
  661 + for (int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
  662 + if (this->settings.voltage[channel].used) {
  663 + // Resize sample vector
  664 + if (samples[channel].size() < sampleCount) {
  665 + this->samples[channel].resize(sampleCount);
  666 + }
  667 +
  668 + // Convert data from the oscilloscope and write it into the sample
  669 + // buffer
  670 + unsigned int bufferPosition = this->settings.trigger.point * 2;
  671 + if (this->specification.sampleSize > 8) {
  672 + // Additional most significant bits after the normal data
  673 + unsigned int extraBitsSize =
  674 + this->specification.sampleSize - 8; // Number of extra bits
  675 + unsigned short int extraBitsMask =
  676 + (0x00ff << extraBitsSize) &
  677 + 0xff00; // Mask for extra bits extraction
  678 + unsigned int extraBitsIndex =
  679 + 8 -
  680 + channel * 2; // Bit position offset for extra bits extraction
  681 +
  682 + for (unsigned int realPosition = 0; realPosition < sampleCount;
  683 + ++realPosition, bufferPosition += HANTEK_CHANNELS) {
  684 + if (bufferPosition >= totalSampleCount)
  685 + bufferPosition %= totalSampleCount;
  686 +
  687 + this->samples[channel][realPosition] =
  688 + ((double)((unsigned short int)
  689 + data[bufferPosition + HANTEK_CHANNELS - 1 -
  690 + channel] +
  691 + (((unsigned short int)
  692 + data[totalSampleCount + bufferPosition]
  693 + << extraBitsIndex) &
  694 + extraBitsMask)) /
  695 + this->specification
  696 + .voltageLimit[channel]
  697 + [this->settings.voltage[channel].gain] -
  698 + this->settings.voltage[channel].offsetReal) *
  699 + this->specification
  700 + .gainSteps[this->settings.voltage[channel].gain];
  701 + }
  702 + } else {
  703 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE) {
  704 + bufferPosition += channel;
  705 + // if device is 6022BE, offset DROP_DSO6022_HEAD incrementally
  706 + bufferPosition += DROP_DSO6022_HEAD * 2;
  707 + } else
  708 + bufferPosition += HANTEK_CHANNELS - 1 - channel;
  709 +
  710 + for (unsigned int realPosition = 0; realPosition < sampleCount;
  711 + ++realPosition, bufferPosition += HANTEK_CHANNELS) {
  712 + if (bufferPosition >= totalSampleCount)
  713 + bufferPosition %= totalSampleCount;
  714 +
  715 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE) {
  716 + double dataBuf = (double)((int)(data[bufferPosition] - 0x83));
  717 + this->samples[channel][realPosition] =
  718 + (dataBuf /
  719 + this->specification
  720 + .voltageLimit[channel]
  721 + [this->settings.voltage[channel].gain]) *
  722 + this->specification
  723 + .gainSteps[this->settings.voltage[channel].gain];
  724 + } else {
  725 + double dataBuf = (double)((int)(data[bufferPosition]));
  726 + this->samples[channel][realPosition] =
  727 + (dataBuf /
  728 + this->specification.voltageLimit
  729 + [channel][this->settings.voltage[channel].gain] -
  730 + this->settings.voltage[channel].offsetReal) *
  731 + this->specification
  732 + .gainSteps[this->settings.voltage[channel].gain];
  733 + }
  734 + }
  735 + }
  736 + } else {
  737 + // Clear unused channels
  738 + this->samples[channel].clear();
  739 + }
  740 + }
475 741 }
476   - }
477   - }
478 742  
479   - this->samplesMutex.unlock();
480 743 #ifdef DEBUG
481   - static unsigned int id = 0;
482   - ++id;
483   - Helper::timestampDebug(QString("Received packet %1").arg(id));
  744 + static unsigned int id = 0;
  745 + ++id;
  746 + timestampDebug(QString("Received packet %1").arg(id));
484 747 #endif
485   - emit samplesAvailable(
486   - &(this->samples), this->settings.samplerate.current,
487   - this->settings.samplerate.limits
488   - ->recordLengths[this->settings.recordLengthId] == UINT_MAX,
489   - &(this->samplesMutex));
490   - }
491   -
492   - return errorCode;
  748 + emit samplesAvailable(
  749 + &(this->samples), this->settings.samplerate.current,
  750 + this->settings.samplerate.limits
  751 + ->recordLengths[this->settings.recordLengthId] == UINT_MAX,
  752 + &(this->samplesMutex));
  753 + }
  754 +
  755 + return errorCode;
493 756 }
494 757  
495 758 /// \brief Calculated the nearest samplerate supported by the oscilloscope.
... ... @@ -501,196 +764,196 @@ int Control::getSamples(bool process) {
501 764 /// \param downsampler Pointer to where the selected downsampling factor should
502 765 /// be written.
503 766 /// \return The nearest samplerate supported, 0.0 on error.
504   -double Control::getBestSamplerate(double samplerate, bool fastRate,
505   - bool maximum, unsigned int *downsampler) {
506   - // Abort if the input value is invalid
507   - if (samplerate <= 0.0)
508   - return 0.0;
509   -
510   - double bestSamplerate = 0.0;
511   -
512   - // Get samplerate specifications for this mode and model
513   - ControlSamplerateLimits *limits;
514   - if (fastRate)
515   - limits = &(this->specification.samplerate.multi);
516   - else
517   - limits = &(this->specification.samplerate.single);
518   -
519   - // Get downsampling factor that would provide the requested rate
520   - double bestDownsampler =
521   - (double)limits->base /
522   - this->specification.bufferDividers[this->settings.recordLengthId] /
523   - samplerate;
524   - // Base samplerate sufficient, or is the maximum better?
525   - if (bestDownsampler < 1.0 &&
526   - (samplerate <= limits->max /
527   - this->specification
528   - .bufferDividers[this->settings.recordLengthId] ||
529   - !maximum)) {
530   - bestDownsampler = 0.0;
531   - bestSamplerate =
532   - limits->max /
533   - this->specification.bufferDividers[this->settings.recordLengthId];
534   - } else {
535   - switch (this->specification.command.bulk.setSamplerate) {
536   - case BULK_SETTRIGGERANDSAMPLERATE:
537   - // DSO-2090 supports the downsampling factors 1, 2, 4 and 5 using
538   - // valueFast or all even values above using valueSlow
539   - if ((maximum && bestDownsampler <= 5.0) ||
540   - (!maximum && bestDownsampler < 6.0)) {
541   - // valueFast is used
542   - if (maximum) {
543   - // The samplerate shall not be higher, so we round up
544   - bestDownsampler = ceil(bestDownsampler);
545   - if (bestDownsampler > 2.0) // 3 and 4 not possible with the DSO-2090
546   - bestDownsampler = 5.0;
547   - } else {
548   - // The samplerate shall not be lower, so we round down
549   - bestDownsampler = floor(bestDownsampler);
550   - if (bestDownsampler > 2.0 &&
551   - bestDownsampler < 5.0) // 3 and 4 not possible with the DSO-2090
552   - bestDownsampler = 2.0;
553   - }
554   - } else {
555   - // valueSlow is used
556   - if (maximum) {
557   - bestDownsampler =
558   - ceil(bestDownsampler / 2.0) * 2.0; // Round up to next even value
559   - } else {
560   - bestDownsampler = floor(bestDownsampler / 2.0) *
  767 +double HantekDsoControl::getBestSamplerate(double samplerate, bool fastRate,
  768 + bool maximum, unsigned int *downsampler) {
  769 + // Abort if the input value is invalid
  770 + if (samplerate <= 0.0)
  771 + return 0.0;
  772 +
  773 + double bestSamplerate = 0.0;
  774 +
  775 + // Get samplerate specifications for this mode and model
  776 + ControlSamplerateLimits *limits;
  777 + if (fastRate)
  778 + limits = &(this->specification.samplerate.multi);
  779 + else
  780 + limits = &(this->specification.samplerate.single);
  781 +
  782 + // Get downsampling factor that would provide the requested rate
  783 + double bestDownsampler =
  784 + (double)limits->base /
  785 + this->specification.bufferDividers[this->settings.recordLengthId] /
  786 + samplerate;
  787 + // Base samplerate sufficient, or is the maximum better?
  788 + if (bestDownsampler < 1.0 &&
  789 + (samplerate <= limits->max /
  790 + this->specification
  791 + .bufferDividers[this->settings.recordLengthId] ||
  792 + !maximum)) {
  793 + bestDownsampler = 0.0;
  794 + bestSamplerate =
  795 + limits->max /
  796 + this->specification.bufferDividers[this->settings.recordLengthId];
  797 + } else {
  798 + switch (this->specification.command.bulk.setSamplerate) {
  799 + case BULK_SETTRIGGERANDSAMPLERATE:
  800 + // DSO-2090 supports the downsampling factors 1, 2, 4 and 5 using
  801 + // valueFast or all even values above using valueSlow
  802 + if ((maximum && bestDownsampler <= 5.0) ||
  803 + (!maximum && bestDownsampler < 6.0)) {
  804 + // valueFast is used
  805 + if (maximum) {
  806 + // The samplerate shall not be higher, so we round up
  807 + bestDownsampler = ceil(bestDownsampler);
  808 + if (bestDownsampler > 2.0) // 3 and 4 not possible with the DSO-2090
  809 + bestDownsampler = 5.0;
  810 + } else {
  811 + // The samplerate shall not be lower, so we round down
  812 + bestDownsampler = floor(bestDownsampler);
  813 + if (bestDownsampler > 2.0 &&
  814 + bestDownsampler < 5.0) // 3 and 4 not possible with the DSO-2090
  815 + bestDownsampler = 2.0;
  816 + }
  817 + } else {
  818 + // valueSlow is used
  819 + if (maximum) {
  820 + bestDownsampler =
  821 + ceil(bestDownsampler / 2.0) * 2.0; // Round up to next even value
  822 + } else {
  823 + bestDownsampler = floor(bestDownsampler / 2.0) *
561 824 2.0; // Round down to next even value
562   - }
563   - if (bestDownsampler > 2.0 * 0x10001) // Check for overflow
564   - bestDownsampler = 2.0 * 0x10001;
565   - }
566   - break;
  825 + }
  826 + if (bestDownsampler > 2.0 * 0x10001) // Check for overflow
  827 + bestDownsampler = 2.0 * 0x10001;
  828 + }
  829 + break;
567 830  
568   - case BULK_CSETTRIGGERORSAMPLERATE:
569   - // DSO-5200 may not supports all downsampling factors, requires testing
570   - if (maximum) {
571   - bestDownsampler =
572   - ceil(bestDownsampler); // Round up to next integer value
573   - } else {
574   - bestDownsampler =
575   - floor(bestDownsampler); // Round down to next integer value
576   - }
577   - break;
  831 + case BULK_CSETTRIGGERORSAMPLERATE:
  832 + // DSO-5200 may not supports all downsampling factors, requires testing
  833 + if (maximum) {
  834 + bestDownsampler =
  835 + ceil(bestDownsampler); // Round up to next integer value
  836 + } else {
  837 + bestDownsampler =
  838 + floor(bestDownsampler); // Round down to next integer value
  839 + }
  840 + break;
578 841  
579   - case BULK_ESETTRIGGERORSAMPLERATE:
580   - // DSO-2250 doesn't have a fast value, so it supports all downsampling
581   - // factors
582   - if (maximum) {
583   - bestDownsampler =
584   - ceil(bestDownsampler); // Round up to next integer value
585   - } else {
586   - bestDownsampler =
587   - floor(bestDownsampler); // Round down to next integer value
588   - }
589   - break;
  842 + case BULK_ESETTRIGGERORSAMPLERATE:
  843 + // DSO-2250 doesn't have a fast value, so it supports all downsampling
  844 + // factors
  845 + if (maximum) {
  846 + bestDownsampler =
  847 + ceil(bestDownsampler); // Round up to next integer value
  848 + } else {
  849 + bestDownsampler =
  850 + floor(bestDownsampler); // Round down to next integer value
  851 + }
  852 + break;
590 853  
591   - default:
592   - return 0.0;
593   - }
  854 + default:
  855 + return 0.0;
  856 + }
594 857  
595   - // Limit maximum downsampler value to avoid overflows in the sent commands
596   - if (bestDownsampler > limits->maxDownsampler)
597   - bestDownsampler = limits->maxDownsampler;
  858 + // Limit maximum downsampler value to avoid overflows in the sent commands
  859 + if (bestDownsampler > limits->maxDownsampler)
  860 + bestDownsampler = limits->maxDownsampler;
598 861  
599   - bestSamplerate =
600   - limits->base / bestDownsampler /
601   - this->specification.bufferDividers[this->settings.recordLengthId];
602   - }
  862 + bestSamplerate =
  863 + limits->base / bestDownsampler /
  864 + this->specification.bufferDividers[this->settings.recordLengthId];
  865 + }
603 866  
604   - if (downsampler)
605   - *downsampler = (unsigned int)bestDownsampler;
606   - return bestSamplerate;
  867 + if (downsampler)
  868 + *downsampler = (unsigned int)bestDownsampler;
  869 + return bestSamplerate;
607 870 }
608 871  
609 872 /// \brief Get the count of samples that are expected returned by the scope.
610 873 /// \param fastRate Is set to the state of the fast rate mode when provided.
611 874 /// \return The total number of samples the scope should return.
612   -unsigned int Control::getSampleCount(bool *fastRate) {
613   - unsigned int totalSampleCount =
614   - this->settings.samplerate.limits
615   - ->recordLengths[this->settings.recordLengthId];
616   - bool fastRateEnabled =
617   - this->settings.samplerate.limits == &this->specification.samplerate.multi;
618   -
619   - if (totalSampleCount == UINT_MAX) {
620   - // Roll mode
621   - const int packetSize = this->device->getPacketSize();
622   - if (packetSize < 0)
623   - totalSampleCount = UINT_MAX;
624   - else
625   - totalSampleCount = packetSize;
626   - } else {
627   - if (!fastRateEnabled)
628   - totalSampleCount *= HANTEK_CHANNELS;
629   - }
630   - if (fastRate)
631   - *fastRate = fastRateEnabled;
632   - return totalSampleCount;
  875 +unsigned int HantekDsoControl::getSampleCount(bool *fastRate) {
  876 + unsigned int totalSampleCount =
  877 + this->settings.samplerate.limits
  878 + ->recordLengths[this->settings.recordLengthId];
  879 + bool fastRateEnabled =
  880 + this->settings.samplerate.limits == &this->specification.samplerate.multi;
  881 +
  882 + if (totalSampleCount == UINT_MAX) {
  883 + // Roll mode
  884 + const int packetSize = this->device->getPacketSize();
  885 + if (packetSize < 0)
  886 + totalSampleCount = UINT_MAX;
  887 + else
  888 + totalSampleCount = packetSize;
  889 + } else {
  890 + if (!fastRateEnabled)
  891 + totalSampleCount *= HANTEK_CHANNELS;
  892 + }
  893 + if (fastRate)
  894 + *fastRate = fastRateEnabled;
  895 + return totalSampleCount;
633 896 }
634 897  
635 898 /// \brief Sets the size of the sample buffer without updating dependencies.
636 899 /// \param index The record length index that should be set.
637 900 /// \return The record length that has been set, 0 on error.
638   -unsigned int Control::updateRecordLength(unsigned int index) {
639   - if (index >=
640   - (unsigned int)this->settings.samplerate.limits->recordLengths.size())
641   - return 0;
  901 +unsigned int HantekDsoControl::updateRecordLength(unsigned int index) {
  902 + if (index >=
  903 + (unsigned int)this->settings.samplerate.limits->recordLengths.size())
  904 + return 0;
642 905  
643   - switch (this->specification.command.bulk.setRecordLength) {
644   - case BULK_SETTRIGGERANDSAMPLERATE:
645   - // SetTriggerAndSamplerate bulk command for record length
646   - static_cast<BulkSetTriggerAndSamplerate *>(
647   - this->command[BULK_SETTRIGGERANDSAMPLERATE])
648   - ->setRecordLength(index);
649   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  906 + switch (this->specification.command.bulk.setRecordLength) {
  907 + case BULK_SETTRIGGERANDSAMPLERATE:
  908 + // SetTriggerAndSamplerate bulk command for record length
  909 + static_cast<BulkSetTriggerAndSamplerate *>(
  910 + this->command[BULK_SETTRIGGERANDSAMPLERATE])
  911 + ->setRecordLength(index);
  912 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
650 913  
651   - break;
  914 + break;
652 915  
653   - case BULK_DSETBUFFER:
654   - if (this->specification.command.bulk.setPretrigger == BULK_FSETBUFFER) {
655   - // Pointers to needed commands
656   - BulkSetRecordLength2250 *commandSetRecordLength2250 =
657   - static_cast<BulkSetRecordLength2250 *>(
658   - this->command[BULK_DSETBUFFER]);
  916 + case BULK_DSETBUFFER:
  917 + if (this->specification.command.bulk.setPretrigger == BULK_FSETBUFFER) {
  918 + // Pointers to needed commands
  919 + BulkSetRecordLength2250 *commandSetRecordLength2250 =
  920 + static_cast<BulkSetRecordLength2250 *>(
  921 + this->command[BULK_DSETBUFFER]);
659 922  
660   - commandSetRecordLength2250->setRecordLength(index);
661   - } else {
662   - // SetBuffer5200 bulk command for record length
663   - BulkSetBuffer5200 *commandSetBuffer5200 =
664   - static_cast<BulkSetBuffer5200 *>(this->command[BULK_DSETBUFFER]);
  923 + commandSetRecordLength2250->setRecordLength(index);
  924 + } else {
  925 + // SetBuffer5200 bulk command for record length
  926 + BulkSetBuffer5200 *commandSetBuffer5200 =
  927 + static_cast<BulkSetBuffer5200 *>(this->command[BULK_DSETBUFFER]);
665 928  
666   - commandSetBuffer5200->setUsedPre(DTRIGGERPOSITION_ON);
667   - commandSetBuffer5200->setUsedPost(DTRIGGERPOSITION_ON);
668   - commandSetBuffer5200->setRecordLength(index);
669   - }
  929 + commandSetBuffer5200->setUsedPre(DTRIGGERPOSITION_ON);
  930 + commandSetBuffer5200->setUsedPost(DTRIGGERPOSITION_ON);
  931 + commandSetBuffer5200->setRecordLength(index);
  932 + }
670 933  
671   - this->commandPending[BULK_DSETBUFFER] = true;
  934 + this->commandPending[BULK_DSETBUFFER] = true;
672 935  
673   - break;
  936 + break;
674 937  
675   - default:
676   - return 0;
677   - }
  938 + default:
  939 + return 0;
  940 + }
678 941  
679   - // Check if the divider has changed and adapt samplerate limits accordingly
680   - bool bDividerChanged =
681   - this->specification.bufferDividers[index] !=
682   - this->specification.bufferDividers[this->settings.recordLengthId];
  942 + // Check if the divider has changed and adapt samplerate limits accordingly
  943 + bool bDividerChanged =
  944 + this->specification.bufferDividers[index] !=
  945 + this->specification.bufferDividers[this->settings.recordLengthId];
683 946  
684   - this->settings.recordLengthId = index;
  947 + this->settings.recordLengthId = index;
685 948  
686   - if (bDividerChanged) {
687   - this->updateSamplerateLimits();
  949 + if (bDividerChanged) {
  950 + this->updateSamplerateLimits();
688 951  
689   - // Samplerate dividers changed, recalculate it
690   - this->restoreTargets();
691   - }
  952 + // Samplerate dividers changed, recalculate it
  953 + this->restoreTargets();
  954 + }
692 955  
693   - return this->settings.samplerate.limits->recordLengths[index];
  956 + return this->settings.samplerate.limits->recordLengths[index];
694 957 }
695 958  
696 959 /// \brief Sets the samplerate based on the parameters calculated by
... ... @@ -698,1114 +961,800 @@ unsigned int Control::updateRecordLength(unsigned int index) {
698 961 /// \param downsampler The downsampling factor.
699 962 /// \param fastRate true, if one channel uses all buffers.
700 963 /// \return The downsampling factor that has been set.
701   -unsigned int Control::updateSamplerate(unsigned int downsampler,
702   - bool fastRate) {
703   - // Get samplerate limits
704   - Hantek::ControlSamplerateLimits *limits =
705   - fastRate ? &this->specification.samplerate.multi
706   - : &this->specification.samplerate.single;
707   -
708   - // Set the calculated samplerate
709   - switch (this->specification.command.bulk.setSamplerate) {
710   - case BULK_SETTRIGGERANDSAMPLERATE: {
711   - short int downsamplerValue = 0;
712   - unsigned char samplerateId = 0;
713   - bool downsampling = false;
714   -
715   - if (downsampler <= 5) {
716   - // All dividers up to 5 are done using the special samplerate IDs
717   - if (downsampler == 0 && limits->base >= limits->max)
718   - samplerateId = 1;
719   - else if (downsampler <= 2)
720   - samplerateId = downsampler;
721   - else { // Downsampling factors 3 and 4 are not supported
722   - samplerateId = 3;
723   - downsampler = 5;
724   - downsamplerValue = (short int)0xffff;
725   - }
726   - } else {
727   - // For any dividers above the downsampling factor can be set directly
728   - downsampler &= ~0x0001; // Only even values possible
729   - downsamplerValue = (short int)(0x10001 - (downsampler >> 1));
  964 +unsigned int HantekDsoControl::updateSamplerate(unsigned int downsampler,
  965 + bool fastRate) {
  966 + // Get samplerate limits
  967 + Hantek::ControlSamplerateLimits *limits =
  968 + fastRate ? &this->specification.samplerate.multi
  969 + : &this->specification.samplerate.single;
  970 +
  971 + // Set the calculated samplerate
  972 + switch (this->specification.command.bulk.setSamplerate) {
  973 + case BULK_SETTRIGGERANDSAMPLERATE: {
  974 + short int downsamplerValue = 0;
  975 + unsigned char samplerateId = 0;
  976 + bool downsampling = false;
  977 +
  978 + if (downsampler <= 5) {
  979 + // All dividers up to 5 are done using the special samplerate IDs
  980 + if (downsampler == 0 && limits->base >= limits->max)
  981 + samplerateId = 1;
  982 + else if (downsampler <= 2)
  983 + samplerateId = downsampler;
  984 + else { // Downsampling factors 3 and 4 are not supported
  985 + samplerateId = 3;
  986 + downsampler = 5;
  987 + downsamplerValue = (short int)0xffff;
  988 + }
  989 + } else {
  990 + // For any dividers above the downsampling factor can be set directly
  991 + downsampler &= ~0x0001; // Only even values possible
  992 + downsamplerValue = (short int)(0x10001 - (downsampler >> 1));
730 993  
731   - downsampling = true;
  994 + downsampling = true;
  995 + }
  996 +
  997 + // Pointers to needed commands
  998 + BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate =
  999 + static_cast<BulkSetTriggerAndSamplerate *>(
  1000 + this->command[BULK_SETTRIGGERANDSAMPLERATE]);
  1001 +
  1002 + // Store if samplerate ID or downsampling factor is used
  1003 + commandSetTriggerAndSamplerate->setDownsamplingMode(downsampling);
  1004 + // Store samplerate ID
  1005 + commandSetTriggerAndSamplerate->setSamplerateId(samplerateId);
  1006 + // Store downsampling factor
  1007 + commandSetTriggerAndSamplerate->setDownsampler(downsamplerValue);
  1008 + // Set fast rate when used
  1009 + commandSetTriggerAndSamplerate->setFastRate(false /*fastRate*/);
  1010 +
  1011 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  1012 +
  1013 + break;
732 1014 }
  1015 + case BULK_CSETTRIGGERORSAMPLERATE: {
  1016 + // Split the resulting divider into the values understood by the device
  1017 + // The fast value is kept at 4 (or 3) for slow sample rates
  1018 + long int valueSlow = qMax(((long int)downsampler - 3) / 2, (long int)0);
  1019 + unsigned char valueFast = downsampler - valueSlow * 2;
  1020 +
  1021 + // Pointers to needed commands
  1022 + BulkSetSamplerate5200 *commandSetSamplerate5200 =
  1023 + static_cast<BulkSetSamplerate5200 *>(
  1024 + this->command[BULK_CSETTRIGGERORSAMPLERATE]);
  1025 + BulkSetTrigger5200 *commandSetTrigger5200 =
  1026 + static_cast<BulkSetTrigger5200 *>(
  1027 + this->command[BULK_ESETTRIGGERORSAMPLERATE]);
  1028 +
  1029 + // Store samplerate fast value
  1030 + commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
  1031 + // Store samplerate slow value (two's complement)
  1032 + commandSetSamplerate5200->setSamplerateSlow(
  1033 + valueSlow == 0 ? 0 : 0xffff - valueSlow);
  1034 + // Set fast rate when used
  1035 + commandSetTrigger5200->setFastRate(fastRate);
  1036 +
  1037 + this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
  1038 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
733 1039  
734   - // Pointers to needed commands
735   - BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate =
736   - static_cast<BulkSetTriggerAndSamplerate *>(
737   - this->command[BULK_SETTRIGGERANDSAMPLERATE]);
738   -
739   - // Store if samplerate ID or downsampling factor is used
740   - commandSetTriggerAndSamplerate->setDownsamplingMode(downsampling);
741   - // Store samplerate ID
742   - commandSetTriggerAndSamplerate->setSamplerateId(samplerateId);
743   - // Store downsampling factor
744   - commandSetTriggerAndSamplerate->setDownsampler(downsamplerValue);
745   - // Set fast rate when used
746   - commandSetTriggerAndSamplerate->setFastRate(false /*fastRate*/);
747   -
748   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
749   -
750   - break;
751   - }
752   - case BULK_CSETTRIGGERORSAMPLERATE: {
753   - // Split the resulting divider into the values understood by the device
754   - // The fast value is kept at 4 (or 3) for slow sample rates
755   - long int valueSlow = qMax(((long int)downsampler - 3) / 2, (long int)0);
756   - unsigned char valueFast = downsampler - valueSlow * 2;
757   -
758   - // Pointers to needed commands
759   - BulkSetSamplerate5200 *commandSetSamplerate5200 =
760   - static_cast<BulkSetSamplerate5200 *>(
761   - this->command[BULK_CSETTRIGGERORSAMPLERATE]);
762   - BulkSetTrigger5200 *commandSetTrigger5200 =
763   - static_cast<BulkSetTrigger5200 *>(
764   - this->command[BULK_ESETTRIGGERORSAMPLERATE]);
765   -
766   - // Store samplerate fast value
767   - commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
768   - // Store samplerate slow value (two's complement)
769   - commandSetSamplerate5200->setSamplerateSlow(
770   - valueSlow == 0 ? 0 : 0xffff - valueSlow);
771   - // Set fast rate when used
772   - commandSetTrigger5200->setFastRate(fastRate);
773   -
774   - this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
775   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
776   -
777   - break;
778   - }
779   - case BULK_ESETTRIGGERORSAMPLERATE: {
780   - // Pointers to needed commands
781   - BulkSetSamplerate2250 *commandSetSamplerate2250 =
782   - static_cast<BulkSetSamplerate2250 *>(
783   - this->command[BULK_ESETTRIGGERORSAMPLERATE]);
784   -
785   - bool downsampling = downsampler >= 1;
786   - // Store downsampler state value
787   - commandSetSamplerate2250->setDownsampling(downsampling);
788   - // Store samplerate value
789   - commandSetSamplerate2250->setSamplerate(
790   - downsampler > 1 ? 0x10001 - downsampler : 0);
791   - // Set fast rate when used
792   - commandSetSamplerate2250->setFastRate(fastRate);
793   -
794   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
795   -
796   - break;
797   - }
798   - default:
799   - return UINT_MAX;
800   - }
801   -
802   - // Update settings
803   - bool fastRateChanged = fastRate != (this->settings.samplerate.limits ==
804   - &this->specification.samplerate.multi);
805   - if (fastRateChanged) {
806   - this->settings.samplerate.limits = limits;
807   - }
808   -
809   - this->settings.samplerate.downsampler = downsampler;
810   - if (downsampler)
811   - this->settings.samplerate.current =
812   - this->settings.samplerate.limits->base /
813   - this->specification.bufferDividers[this->settings.recordLengthId] /
814   - downsampler;
815   - else
816   - this->settings.samplerate.current =
817   - this->settings.samplerate.limits->max /
818   - this->specification.bufferDividers[this->settings.recordLengthId];
819   -
820   - // Update dependencies
821   - this->setPretriggerPosition(this->settings.trigger.position);
822   -
823   - // Emit signals for changed settings
824   - if (fastRateChanged) {
825   - emit availableRecordLengthsChanged(
826   - this->settings.samplerate.limits->recordLengths);
827   - emit recordLengthChanged(
828   - this->settings.samplerate.limits
829   - ->recordLengths[this->settings.recordLengthId]);
830   - }
831   -
832   - // Check for Roll mode
833   - if (this->settings.samplerate.limits
834   - ->recordLengths[this->settings.recordLengthId] != UINT_MAX)
835   - emit recordTimeChanged((double)this->settings.samplerate.limits
  1040 + break;
  1041 + }
  1042 + case BULK_ESETTRIGGERORSAMPLERATE: {
  1043 + // Pointers to needed commands
  1044 + BulkSetSamplerate2250 *commandSetSamplerate2250 =
  1045 + static_cast<BulkSetSamplerate2250 *>(
  1046 + this->command[BULK_ESETTRIGGERORSAMPLERATE]);
  1047 +
  1048 + bool downsampling = downsampler >= 1;
  1049 + // Store downsampler state value
  1050 + commandSetSamplerate2250->setDownsampling(downsampling);
  1051 + // Store samplerate value
  1052 + commandSetSamplerate2250->setSamplerate(
  1053 + downsampler > 1 ? 0x10001 - downsampler : 0);
  1054 + // Set fast rate when used
  1055 + commandSetSamplerate2250->setFastRate(fastRate);
  1056 +
  1057 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  1058 +
  1059 + break;
  1060 + }
  1061 + default:
  1062 + return UINT_MAX;
  1063 + }
  1064 +
  1065 + // Update settings
  1066 + bool fastRateChanged = fastRate != (this->settings.samplerate.limits ==
  1067 + &this->specification.samplerate.multi);
  1068 + if (fastRateChanged) {
  1069 + this->settings.samplerate.limits = limits;
  1070 + }
  1071 +
  1072 + this->settings.samplerate.downsampler = downsampler;
  1073 + if (downsampler)
  1074 + this->settings.samplerate.current =
  1075 + this->settings.samplerate.limits->base /
  1076 + this->specification.bufferDividers[this->settings.recordLengthId] /
  1077 + downsampler;
  1078 + else
  1079 + this->settings.samplerate.current =
  1080 + this->settings.samplerate.limits->max /
  1081 + this->specification.bufferDividers[this->settings.recordLengthId];
  1082 +
  1083 + // Update dependencies
  1084 + this->setPretriggerPosition(this->settings.trigger.position);
  1085 +
  1086 + // Emit signals for changed settings
  1087 + if (fastRateChanged) {
  1088 + emit availableRecordLengthsChanged(
  1089 + this->settings.samplerate.limits->recordLengths);
  1090 + emit recordLengthChanged(
  1091 + this->settings.samplerate.limits
  1092 + ->recordLengths[this->settings.recordLengthId]);
  1093 + }
  1094 +
  1095 + // Check for Roll mode
  1096 + if (this->settings.samplerate.limits
  1097 + ->recordLengths[this->settings.recordLengthId] != UINT_MAX)
  1098 + emit recordTimeChanged((double)this->settings.samplerate.limits
836 1099 ->recordLengths[this->settings.recordLengthId] /
837   - this->settings.samplerate.current);
838   - emit samplerateChanged(this->settings.samplerate.current);
  1100 + this->settings.samplerate.current);
  1101 + emit samplerateChanged(this->settings.samplerate.current);
839 1102  
840   - return downsampler;
  1103 + return downsampler;
841 1104 }
842 1105  
843 1106 /// \brief Restore the samplerate/timebase targets after divider updates.
844   -void Control::restoreTargets() {
845   - if (this->settings.samplerate.target.samplerateSet)
846   - this->setSamplerate();
847   - else
848   - this->setRecordTime();
  1107 +void HantekDsoControl::restoreTargets() {
  1108 + if (this->settings.samplerate.target.samplerateSet)
  1109 + this->setSamplerate();
  1110 + else
  1111 + this->setRecordTime();
849 1112 }
850 1113  
851 1114 /// \brief Update the minimum and maximum supported samplerate.
852   -void Control::updateSamplerateLimits() {
853   - // Works only if the minimum samplerate for normal mode is lower than for fast
854   - // rate mode, which is the case for all models
855   - ControlSamplerateLimits *limits =
856   - (this->settings.usedChannels <= 1)
857   - ? &this->specification.samplerate.multi
858   - : &this->specification.samplerate.single;
859   - emit samplerateLimitsChanged(
860   - (double)this->specification.samplerate.single.base /
861   - this->specification.samplerate.single.maxDownsampler /
862   - this->specification.bufferDividers[this->settings.recordLengthId],
863   - limits->max /
864   - this->specification.bufferDividers[this->settings.recordLengthId]);
865   -}
866   -
867   -/// \brief Try to connect to the oscilloscope.
868   -void Control::connectDevice() {
869   - int errorCode;
870   -
871   - emit statusMessage(this->device->search(), 0);
872   - if (!this->device->isConnected())
873   - return;
874   -
875   - // Clean up commands and their pending state
876   - for (int command = 0; command < BULK_COUNT; ++command) {
877   - if (this->command[command])
878   - delete this->command[command];
879   - this->commandPending[command] = false;
880   - }
881   - // Instantiate the commands needed for all models
882   - this->command[BULK_FORCETRIGGER] = new BulkForceTrigger();
883   - this->command[BULK_STARTSAMPLING] = new BulkCaptureStart();
884   - this->command[BULK_ENABLETRIGGER] = new BulkTriggerEnabled();
885   - this->command[BULK_GETDATA] = new BulkGetData();
886   - this->command[BULK_GETCAPTURESTATE] = new BulkGetCaptureState();
887   - this->command[BULK_SETGAIN] = new BulkSetGain();
888   - // Initialize the command versions to the ones used on the DSO-2090
889   - this->specification.command.bulk.setRecordLength = (BulkCode)-1;
890   - this->specification.command.bulk.setChannels = (BulkCode)-1;
891   - this->specification.command.bulk.setGain = BULK_SETGAIN;
892   - this->specification.command.bulk.setSamplerate = (BulkCode)-1;
893   - this->specification.command.bulk.setTrigger = (BulkCode)-1;
894   - this->specification.command.bulk.setPretrigger = (BulkCode)-1;
895   - this->specification.command.control.setOffset = CONTROL_SETOFFSET;
896   - this->specification.command.control.setRelays = CONTROL_SETRELAYS;
897   - this->specification.command.values.offsetLimits = VALUE_OFFSETLIMITS;
898   - this->specification.command.values.voltageLimits = (ControlValue)-1;
899   -
900   - // Determine the command version we need for this model
901   - bool unsupported = false;
902   - int lastControlIndex = 0;
903   - switch (this->device->getModel()) {
904   - case MODEL_DSO2150:
905   - unsupported = true;
906   -
907   - case MODEL_DSO2090:
908   - // Instantiate additional commands for the DSO-2090
909   - this->command[BULK_SETTRIGGERANDSAMPLERATE] =
910   - new BulkSetTriggerAndSamplerate();
911   - this->specification.command.bulk.setRecordLength =
912   - BULK_SETTRIGGERANDSAMPLERATE;
913   - this->specification.command.bulk.setChannels = BULK_SETTRIGGERANDSAMPLERATE;
914   - this->specification.command.bulk.setSamplerate =
915   - BULK_SETTRIGGERANDSAMPLERATE;
916   - this->specification.command.bulk.setTrigger = BULK_SETTRIGGERANDSAMPLERATE;
917   - this->specification.command.bulk.setPretrigger =
918   - BULK_SETTRIGGERANDSAMPLERATE;
919   - lastControlIndex = CONTROLINDEX_SETRELAYS;
920   - // Initialize those as pending
921   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
922   - break;
923   -
924   - case MODEL_DSO2250:
925   - // Instantiate additional commands for the DSO-2250
926   - this->command[BULK_BSETCHANNELS] = new BulkSetChannels2250();
927   - this->command[BULK_CSETTRIGGERORSAMPLERATE] = new BulkSetTrigger2250();
928   - this->command[BULK_DSETBUFFER] = new BulkSetRecordLength2250();
929   - this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetSamplerate2250();
930   - this->command[BULK_FSETBUFFER] = new BulkSetBuffer2250();
931   - this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
932   - this->specification.command.bulk.setChannels = BULK_BSETCHANNELS;
933   - this->specification.command.bulk.setSamplerate =
934   - BULK_ESETTRIGGERORSAMPLERATE;
935   - this->specification.command.bulk.setTrigger = BULK_CSETTRIGGERORSAMPLERATE;
936   - this->specification.command.bulk.setPretrigger = BULK_FSETBUFFER;
937   - /// \todo Test if lastControlIndex is correct
938   - lastControlIndex = CONTROLINDEX_SETRELAYS;
939   -
940   - this->commandPending[BULK_BSETCHANNELS] = true;
941   - this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
942   - this->commandPending[BULK_DSETBUFFER] = true;
943   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
944   - this->commandPending[BULK_FSETBUFFER] = true;
945   -
946   - break;
947   -
948   - case MODEL_DSO5200A:
949   - unsupported = true;
950   -
951   - case MODEL_DSO5200:
952   - // Instantiate additional commands for the DSO-5200
953   - this->command[BULK_CSETTRIGGERORSAMPLERATE] = new BulkSetSamplerate5200();
954   - this->command[BULK_DSETBUFFER] = new BulkSetBuffer5200();
955   - this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetTrigger5200();
956   - this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
957   - this->specification.command.bulk.setChannels = BULK_ESETTRIGGERORSAMPLERATE;
958   - this->specification.command.bulk.setSamplerate =
959   - BULK_CSETTRIGGERORSAMPLERATE;
960   - this->specification.command.bulk.setTrigger = BULK_ESETTRIGGERORSAMPLERATE;
961   - this->specification.command.bulk.setPretrigger =
962   - BULK_ESETTRIGGERORSAMPLERATE;
963   - // this->specification.command.values.voltageLimits = VALUE_ETSCORRECTION;
964   - /// \todo Test if lastControlIndex is correct
965   - lastControlIndex = CONTROLINDEX_SETRELAYS;
966   -
967   - this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
968   - this->commandPending[BULK_DSETBUFFER] = true;
969   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
970   -
971   - break;
972   -
973   - case MODEL_DSO6022BE:
974   - // 6022BE do not support any bulk commands
975   - this->control[CONTROLINDEX_SETVOLTDIV_CH1] = new ControlSetVoltDIV_CH1();
976   - this->controlCode[CONTROLINDEX_SETVOLTDIV_CH1] = CONTROL_SETVOLTDIV_CH1;
977   - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true;
978   -
979   - this->control[CONTROLINDEX_SETVOLTDIV_CH2] = new ControlSetVoltDIV_CH2();
980   - this->controlCode[CONTROLINDEX_SETVOLTDIV_CH2] = CONTROL_SETVOLTDIV_CH2;
981   - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true;
982   -
983   - this->control[CONTROLINDEX_SETTIMEDIV] = new ControlSetTimeDIV();
984   - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
985   - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
986   -
987   - this->control[CONTROLINDEX_ACQUIIRE_HARD_DATA] =
988   - new ControlAcquireHardData();
989   - this->controlCode[CONTROLINDEX_ACQUIIRE_HARD_DATA] =
990   - CONTROL_ACQUIIRE_HARD_DATA;
991   - this->controlPending[CONTROLINDEX_ACQUIIRE_HARD_DATA] = true;
992   - /// \todo Test if lastControlIndex is correct
993   - lastControlIndex = CONTROLINDEX_ACQUIIRE_HARD_DATA;
994   - break;
995   -
996   - default:
997   - this->device->disconnect();
998   - emit statusMessage(tr("Unknown model"), 0);
999   - return;
1000   - }
1001   -
1002   - if (unsupported)
1003   - qWarning("Warning: This Hantek DSO model isn't supported officially, so it "
1004   - "may not be working as expected. Reports about your experiences "
1005   - "are very welcome though (Please open a feature request in the "
1006   - "tracker at https://sf.net/projects/openhantek/ or email me "
1007   - "directly to oliver.haag@gmail.com). If it's working perfectly I "
1008   - "can remove this warning, if not it should be possible to get it "
1009   - "working with your help soon.");
1010   -
1011   - for (int control = 0; control <= lastControlIndex; ++control)
1012   - this->controlPending[control] = true;
1013   -
1014   - // Disable controls not supported by 6022BE
1015   - if (this->device->getModel() == MODEL_DSO6022BE) {
1016   - this->controlPending[CONTROLINDEX_SETOFFSET] = false;
1017   - this->controlPending[CONTROLINDEX_SETRELAYS] = false;
1018   - }
1019   -
1020   - // Maximum possible samplerate for a single channel and dividers for record
1021   - // lengths
1022   - this->specification.bufferDividers.clear();
1023   - this->specification.samplerate.single.recordLengths.clear();
1024   - this->specification.samplerate.multi.recordLengths.clear();
1025   - this->specification.gainSteps.clear();
1026   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
1027   - this->specification.voltageLimit[channel].clear();
1028   -
1029   - switch (this->device->getModel()) {
1030   - case MODEL_DSO5200:
1031   - case MODEL_DSO5200A:
1032   - this->specification.samplerate.single.base = 100e6;
1033   - this->specification.samplerate.single.max = 125e6;
1034   - this->specification.samplerate.single.maxDownsampler = 131072;
1035   - this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
1036   - << 14336;
1037   - this->specification.samplerate.multi.base = 200e6;
1038   - this->specification.samplerate.multi.max = 250e6;
1039   - this->specification.samplerate.multi.maxDownsampler = 131072;
1040   - this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
1041   - << 28672;
1042   - this->specification.bufferDividers << 1000 << 1 << 1;
1043   - this->specification.gainSteps << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0
1044   - << 16.0 << 40.0 << 80.0;
1045   - /// \todo Use calibration data to get the DSO-5200(A) sample ranges
1046   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
1047   - this->specification.voltageLimit[channel]
1048   - << 368 << 454 << 908 << 368 << 454 << 908 << 368 << 454 << 908;
1049   - this->specification.gainIndex << 1 << 0 << 0 << 1 << 0 << 0 << 1 << 0 << 0;
1050   - this->specification.sampleSize = 10;
1051   - break;
1052   -
1053   - case MODEL_DSO2250:
1054   - this->specification.samplerate.single.base = 100e6;
1055   - this->specification.samplerate.single.max = 100e6;
1056   - this->specification.samplerate.single.maxDownsampler = 65536;
1057   - this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
1058   - << 524288;
1059   - this->specification.samplerate.multi.base = 200e6;
1060   - this->specification.samplerate.multi.max = 250e6;
1061   - this->specification.samplerate.multi.maxDownsampler = 65536;
1062   - this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
1063   - << 1048576;
1064   - this->specification.bufferDividers << 1000 << 1 << 1;
1065   - this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
1066   - << 4.00 << 8.0 << 16.0 << 40.0;
1067   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
1068   - this->specification.voltageLimit[channel]
1069   - << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255;
1070   - this->specification.gainIndex << 0 << 2 << 3 << 0 << 2 << 3 << 0 << 2 << 3;
1071   - this->specification.sampleSize = 8;
1072   - break;
1073   -
1074   - case MODEL_DSO2150:
1075   - this->specification.samplerate.single.base = 50e6;
1076   - this->specification.samplerate.single.max = 75e6;
1077   - this->specification.samplerate.single.maxDownsampler = 131072;
1078   - this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
1079   - << 32768;
1080   - this->specification.samplerate.multi.base = 100e6;
1081   - this->specification.samplerate.multi.max = 150e6;
1082   - this->specification.samplerate.multi.maxDownsampler = 131072;
1083   - this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
1084   - << 65536;
1085   - this->specification.bufferDividers << 1000 << 1 << 1;
1086   - this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
1087   - << 4.00 << 8.0 << 16.0 << 40.0;
1088   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
1089   - this->specification.voltageLimit[channel]
1090   - << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255;
1091   - this->specification.gainIndex << 0 << 1 << 2 << 0 << 1 << 2 << 0 << 1 << 2;
1092   - this->specification.sampleSize = 8;
1093   - break;
1094   -
1095   - case MODEL_DSO6022BE:
1096   - this->specification.samplerate.single.base = 1e6;
1097   - this->specification.samplerate.single.max = 48e6;
1098   - this->specification.samplerate.single.maxDownsampler = 10;
1099   - this->specification.samplerate.single.recordLengths << UINT_MAX << 10240;
1100   - this->specification.samplerate.multi.base = 1e6;
1101   - this->specification.samplerate.multi.max = 48e6;
1102   - this->specification.samplerate.multi.maxDownsampler = 10;
1103   - this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480;
1104   - this->specification.bufferDividers << 1000 << 1 << 1;
1105   - this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
1106   - << 4.00 << 8.0 << 16.0 << 40.0;
1107   - // This data was based on testing and depends on Divider.
1108   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
1109   - this->specification.voltageLimit[channel] << 25 << 51 << 103 << 206 << 412
1110   - << 196 << 392 << 784 << 1000;
1111   - // Divider. Tested and calculated results are different!
1112   - this->specification.gainDiv << 10 << 10 << 10 << 10 << 10 << 2 << 2 << 2
1113   - << 1;
1114   - this->specification.sampleSteps << 1e5 << 2e5 << 5e5 << 1e6 << 2e6 << 4e6
1115   - << 8e6 << 16e6 << 24e6 << 48e6;
1116   - this->specification.sampleDiv << 10 << 20 << 50 << 1 << 2 << 4 << 8 << 16
1117   - << 24 << 48;
1118   - this->specification.sampleSize = 8;
1119   - break;
1120   -
1121   - default:
1122   - this->specification.samplerate.single.base = 50e6;
1123   - this->specification.samplerate.single.max = 50e6;
1124   - this->specification.samplerate.single.maxDownsampler = 131072;
1125   - this->specification.samplerate.single.recordLengths << UINT_MAX << 10240
1126   - << 32768;
1127   - this->specification.samplerate.multi.base = 100e6;
1128   - this->specification.samplerate.multi.max = 100e6;
1129   - this->specification.samplerate.multi.maxDownsampler = 131072;
1130   - this->specification.samplerate.multi.recordLengths << UINT_MAX << 20480
1131   - << 65536;
1132   - this->specification.bufferDividers << 1000 << 1 << 1;
1133   - this->specification.gainSteps << 0.08 << 0.16 << 0.40 << 0.80 << 1.60
1134   - << 4.00 << 8.0 << 16.0 << 40.0;
1135   - for (int channel = 0; channel < HANTEK_CHANNELS; ++channel)
1136   - this->specification.voltageLimit[channel]
1137   - << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255 << 255;
1138   - this->specification.gainIndex << 0 << 1 << 2 << 0 << 1 << 2 << 0 << 1 << 2;
1139   - this->specification.sampleSize = 8;
1140   - break;
1141   - }
1142   - this->settings.recordLengthId = 1;
1143   - this->settings.samplerate.limits = &(this->specification.samplerate.single);
1144   - this->settings.samplerate.downsampler = 1;
1145   - this->previousSampleCount = 0;
1146   -
1147   - // Get channel level data
1148   - errorCode = this->device->controlRead(
1149   - CONTROL_VALUE, (unsigned char *)&(this->specification.offsetLimit),
1150   - sizeof(this->specification.offsetLimit), (int)VALUE_OFFSETLIMITS);
1151   - if (errorCode < 0) {
1152   - this->device->disconnect();
1153   - emit statusMessage(tr("Couldn't get channel level data from oscilloscope"),
1154   - 0);
1155   - return;
1156   - }
1157   -
1158   - // Emit signals for initial settings
1159   - emit availableRecordLengthsChanged(
1160   - this->settings.samplerate.limits->recordLengths);
1161   - updateSamplerateLimits();
1162   - emit recordLengthChanged(this->settings.samplerate.limits
1163   - ->recordLengths[this->settings.recordLengthId]);
1164   - if (this->settings.samplerate.limits
1165   - ->recordLengths[this->settings.recordLengthId] != UINT_MAX)
1166   - emit recordTimeChanged((double)this->settings.samplerate.limits
1167   - ->recordLengths[this->settings.recordLengthId] /
1168   - this->settings.samplerate.current);
1169   - emit samplerateChanged(this->settings.samplerate.current);
1170   -
1171   - if (this->device->getModel() == MODEL_DSO6022BE) {
1172   - QList<double> sampleSteps;
1173   - sampleSteps << 1.0 << 2.0 << 5.0 << 10.0 << 20.0 << 40.0 << 80.0 << 160.0
1174   - << 240.0 << 480.0;
1175   - emit samplerateSet(1, sampleSteps);
1176   - }
1177   -
1178   - DsoControl::connectDevice();
  1115 +void HantekDsoControl::updateSamplerateLimits() {
  1116 + // Works only if the minimum samplerate for normal mode is lower than for fast
  1117 + // rate mode, which is the case for all models
  1118 + ControlSamplerateLimits *limits =
  1119 + (this->settings.usedChannels <= 1)
  1120 + ? &this->specification.samplerate.multi
  1121 + : &this->specification.samplerate.single;
  1122 + emit samplerateLimitsChanged(
  1123 + (double)this->specification.samplerate.single.base /
  1124 + this->specification.samplerate.single.maxDownsampler /
  1125 + this->specification.bufferDividers[this->settings.recordLengthId],
  1126 + limits->max /
  1127 + this->specification.bufferDividers[this->settings.recordLengthId]);
1179 1128 }
1180 1129  
1181 1130 /// \brief Sets the size of the oscilloscopes sample buffer.
1182 1131 /// \param index The record length index that should be set.
1183 1132 /// \return The record length that has been set, 0 on error.
1184   -unsigned int Control::setRecordLength(unsigned int index) {
1185   - if (!this->device->isConnected())
1186   - return 0;
  1133 +unsigned int HantekDsoControl::setRecordLength(unsigned int index) {
  1134 + if (!this->device->isConnected())
  1135 + return 0;
1187 1136  
1188   - if (!this->updateRecordLength(index))
1189   - return 0;
  1137 + if (!this->updateRecordLength(index))
  1138 + return 0;
1190 1139  
1191   - this->restoreTargets();
1192   - this->setPretriggerPosition(this->settings.trigger.position);
  1140 + this->restoreTargets();
  1141 + this->setPretriggerPosition(this->settings.trigger.position);
1193 1142  
1194   - emit recordLengthChanged(this->settings.samplerate.limits
1195   - ->recordLengths[this->settings.recordLengthId]);
1196   - return this->settings.samplerate.limits
1197   - ->recordLengths[this->settings.recordLengthId];
  1143 + emit recordLengthChanged(this->settings.samplerate.limits
  1144 + ->recordLengths[this->settings.recordLengthId]);
  1145 + return this->settings.samplerate.limits
  1146 + ->recordLengths[this->settings.recordLengthId];
1198 1147 }
1199 1148  
1200 1149 /// \brief Sets the samplerate of the oscilloscope.
1201 1150 /// \param samplerate The samplerate that should be met (S/s), 0.0 to restore
1202 1151 /// current samplerate.
1203 1152 /// \return The samplerate that has been set, 0.0 on error.
1204   -double Control::setSamplerate(double samplerate) {
1205   - if (!this->device->isConnected())
1206   - return 0.0;
1207   -
1208   - if (samplerate == 0.0) {
1209   - samplerate = this->settings.samplerate.target.samplerate;
1210   - } else {
1211   - this->settings.samplerate.target.samplerate = samplerate;
1212   - this->settings.samplerate.target.samplerateSet = true;
1213   - }
1214   -
1215   - if (this->device->getModel() != MODEL_DSO6022BE) {
1216   - // When possible, enable fast rate if it is required to reach the requested
1217   - // samplerate
1218   - bool fastRate =
1219   - (this->settings.usedChannels <= 1) &&
1220   - (samplerate >
1221   - this->specification.samplerate.single.max /
1222   - this->specification.bufferDividers[this->settings.recordLengthId]);
1223   -
1224   - // What is the nearest, at least as high samplerate the scope can provide?
1225   - unsigned int downsampler = 0;
1226   - double bestSamplerate =
1227   - getBestSamplerate(samplerate, fastRate, false, &(downsampler));
  1153 +double HantekDsoControl::setSamplerate(double samplerate) {
  1154 + if (!this->device->isConnected())
  1155 + return 0.0;
1228 1156  
1229   - // Set the calculated samplerate
1230   - if (this->updateSamplerate(downsampler, fastRate) == UINT_MAX)
1231   - return 0.0;
1232   - else {
1233   - return bestSamplerate;
  1157 + if (samplerate == 0.0) {
  1158 + samplerate = this->settings.samplerate.target.samplerate;
  1159 + } else {
  1160 + this->settings.samplerate.target.samplerate = samplerate;
  1161 + this->settings.samplerate.target.samplerateSet = true;
1234 1162 }
1235   - } else {
1236   - int sampleId;
1237   - for (sampleId = 0; sampleId < this->specification.sampleSteps.count() - 1;
1238   - ++sampleId)
1239   - if (this->specification.sampleSteps[sampleId] == samplerate)
1240   - break;
1241   - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
1242   - static_cast<ControlSetTimeDIV *>(this->control[CONTROLINDEX_SETTIMEDIV])
1243   - ->setDiv(this->specification.sampleDiv[sampleId]);
1244   - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
1245   - this->settings.samplerate.current = samplerate;
1246   -
1247   - // Provide margin for SW trigger
1248   - unsigned int sampleMargin = 2000;
1249   - // Check for Roll mode
1250   - if (this->settings.samplerate.limits
1251   - ->recordLengths[this->settings.recordLengthId] != UINT_MAX)
1252   - emit recordTimeChanged(
1253   - (double)(this->settings.samplerate.limits
1254   - ->recordLengths[this->settings.recordLengthId] - sampleMargin) /
1255   - this->settings.samplerate.current);
1256   - emit samplerateChanged(this->settings.samplerate.current);
1257 1163  
1258   - return samplerate;
1259   - }
  1164 + if (this->device->getUniqueModelID() != MODEL_DSO6022BE) {
  1165 + // When possible, enable fast rate if it is required to reach the requested
  1166 + // samplerate
  1167 + bool fastRate =
  1168 + (this->settings.usedChannels <= 1) &&
  1169 + (samplerate >
  1170 + this->specification.samplerate.single.max /
  1171 + this->specification.bufferDividers[this->settings.recordLengthId]);
  1172 +
  1173 + // What is the nearest, at least as high samplerate the scope can provide?
  1174 + unsigned int downsampler = 0;
  1175 + double bestSamplerate =
  1176 + getBestSamplerate(samplerate, fastRate, false, &(downsampler));
  1177 +
  1178 + // Set the calculated samplerate
  1179 + if (this->updateSamplerate(downsampler, fastRate) == UINT_MAX)
  1180 + return 0.0;
  1181 + else {
  1182 + return bestSamplerate;
  1183 + }
  1184 + } else {
  1185 + int sampleId;
  1186 + for (sampleId = 0; sampleId < this->specification.sampleSteps.count() - 1;
  1187 + ++sampleId)
  1188 + if (this->specification.sampleSteps[sampleId] == samplerate)
  1189 + break;
  1190 + this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
  1191 + static_cast<ControlSetTimeDIV *>(this->control[CONTROLINDEX_SETTIMEDIV])
  1192 + ->setDiv(this->specification.sampleDiv[sampleId]);
  1193 + this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
  1194 + this->settings.samplerate.current = samplerate;
  1195 +
  1196 + // Provide margin for SW trigger
  1197 + unsigned int sampleMargin = 2000;
  1198 + // Check for Roll mode
  1199 + if (this->settings.samplerate.limits
  1200 + ->recordLengths[this->settings.recordLengthId] != UINT_MAX)
  1201 + emit recordTimeChanged(
  1202 + (double)(this->settings.samplerate.limits
  1203 + ->recordLengths[this->settings.recordLengthId] - sampleMargin) /
  1204 + this->settings.samplerate.current);
  1205 + emit samplerateChanged(this->settings.samplerate.current);
  1206 +
  1207 + return samplerate;
  1208 + }
1260 1209 }
1261 1210  
1262 1211 /// \brief Sets the time duration of one aquisition by adapting the samplerate.
1263 1212 /// \param duration The record time duration that should be met (s), 0.0 to
1264 1213 /// restore current record time.
1265 1214 /// \return The record time duration that has been set, 0.0 on error.
1266   -double Control::setRecordTime(double duration) {
1267   - if (!this->device->isConnected())
1268   - return 0.0;
1269   -
1270   - if (duration == 0.0) {
1271   - duration = this->settings.samplerate.target.duration;
1272   - } else {
1273   - this->settings.samplerate.target.duration = duration;
1274   - this->settings.samplerate.target.samplerateSet = false;
1275   - }
1276   -
1277   - if (this->device->getModel() != MODEL_DSO6022BE) {
1278   - // Calculate the maximum samplerate that would still provide the requested
1279   - // duration
1280   - double maxSamplerate = (double)this->specification.samplerate.single
1281   - .recordLengths[this->settings.recordLengthId] /
1282   - duration;
1283   -
1284   - // When possible, enable fast rate if the record time can't be set that low
1285   - // to improve resolution
1286   - bool fastRate =
1287   - (this->settings.usedChannels <= 1) &&
1288   - (maxSamplerate >=
1289   - this->specification.samplerate.multi.base /
1290   - this->specification.bufferDividers[this->settings.recordLengthId]);
1291   -
1292   - // What is the nearest, at most as high samplerate the scope can provide?
1293   - unsigned int downsampler = 0;
1294   - double bestSamplerate =
1295   - getBestSamplerate(maxSamplerate, fastRate, true, &(downsampler));
  1215 +double HantekDsoControl::setRecordTime(double duration) {
  1216 + if (!this->device->isConnected())
  1217 + return 0.0;
1296 1218  
1297   - // Set the calculated samplerate
1298   - if (this->updateSamplerate(downsampler, fastRate) == UINT_MAX)
1299   - return 0.0;
1300   - else {
1301   - return (double)this->settings.samplerate.limits
1302   - ->recordLengths[this->settings.recordLengthId] /
1303   - bestSamplerate;
1304   - }
1305   - } else {
1306   - // For now - we go for the 10240 size sampling - the other seems not to be
1307   - // supported
1308   - // Find highest samplerate using less than 10240 samples to obtain our
1309   - // duration.
1310   - // Better add some margin for our SW trigger
1311   - unsigned int sampleMargin = 2000;
1312   - unsigned int sampleCount = 10240;
1313   - int bestId = 0;
1314   - int sampleId;
1315   - for (sampleId = 0; sampleId < this->specification.sampleSteps.count();
1316   - ++sampleId) {
1317   - if (this->specification.sampleSteps[sampleId] * duration <
1318   - (sampleCount - sampleMargin))
1319   - bestId = sampleId;
  1219 + if (duration == 0.0) {
  1220 + duration = this->settings.samplerate.target.duration;
  1221 + } else {
  1222 + this->settings.samplerate.target.duration = duration;
  1223 + this->settings.samplerate.target.samplerateSet = false;
1320 1224 }
1321   - sampleId = bestId;
1322   - // Usable sample value
1323   - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
1324   - static_cast<ControlSetTimeDIV *>(this->control[CONTROLINDEX_SETTIMEDIV])
1325   - ->setDiv(this->specification.sampleDiv[sampleId]);
1326   - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
1327   - this->settings.samplerate.current =
1328   - this->specification.sampleSteps[sampleId];
1329 1225  
1330   - emit samplerateChanged(this->settings.samplerate.current);
1331   - return this->settings.samplerate.current;
1332   - }
  1226 + if (this->device->getUniqueModelID() != MODEL_DSO6022BE) {
  1227 + // Calculate the maximum samplerate that would still provide the requested
  1228 + // duration
  1229 + double maxSamplerate = (double)this->specification.samplerate.single
  1230 + .recordLengths[this->settings.recordLengthId] /
  1231 + duration;
  1232 +
  1233 + // When possible, enable fast rate if the record time can't be set that low
  1234 + // to improve resolution
  1235 + bool fastRate =
  1236 + (this->settings.usedChannels <= 1) &&
  1237 + (maxSamplerate >=
  1238 + this->specification.samplerate.multi.base /
  1239 + this->specification.bufferDividers[this->settings.recordLengthId]);
  1240 +
  1241 + // What is the nearest, at most as high samplerate the scope can provide?
  1242 + unsigned int downsampler = 0;
  1243 + double bestSamplerate =
  1244 + getBestSamplerate(maxSamplerate, fastRate, true, &(downsampler));
  1245 +
  1246 + // Set the calculated samplerate
  1247 + if (this->updateSamplerate(downsampler, fastRate) == UINT_MAX)
  1248 + return 0.0;
  1249 + else {
  1250 + return (double)this->settings.samplerate.limits
  1251 + ->recordLengths[this->settings.recordLengthId] /
  1252 + bestSamplerate;
  1253 + }
  1254 + } else {
  1255 + // For now - we go for the 10240 size sampling - the other seems not to be
  1256 + // supported
  1257 + // Find highest samplerate using less than 10240 samples to obtain our
  1258 + // duration.
  1259 + // Better add some margin for our SW trigger
  1260 + unsigned int sampleMargin = 2000;
  1261 + unsigned int sampleCount = 10240;
  1262 + int bestId = 0;
  1263 + int sampleId;
  1264 + for (sampleId = 0; sampleId < this->specification.sampleSteps.count();
  1265 + ++sampleId) {
  1266 + if (this->specification.sampleSteps[sampleId] * duration <
  1267 + (sampleCount - sampleMargin))
  1268 + bestId = sampleId;
  1269 + }
  1270 + sampleId = bestId;
  1271 + // Usable sample value
  1272 + this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV;
  1273 + static_cast<ControlSetTimeDIV *>(this->control[CONTROLINDEX_SETTIMEDIV])
  1274 + ->setDiv(this->specification.sampleDiv[sampleId]);
  1275 + this->controlPending[CONTROLINDEX_SETTIMEDIV] = true;
  1276 + this->settings.samplerate.current =
  1277 + this->specification.sampleSteps[sampleId];
  1278 +
  1279 + emit samplerateChanged(this->settings.samplerate.current);
  1280 + return this->settings.samplerate.current;
  1281 + }
1333 1282 }
1334 1283  
1335 1284 /// \brief Enables/disables filtering of the given channel.
1336 1285 /// \param channel The channel that should be set.
1337 1286 /// \param used true if the channel should be sampled.
1338 1287 /// \return See ::Dso::ErrorCode.
1339   -int Control::setChannelUsed(unsigned int channel, bool used) {
1340   - if (!this->device->isConnected())
1341   - return Dso::ERROR_CONNECTION;
1342   -
1343   - if (channel >= HANTEK_CHANNELS)
1344   - return Dso::ERROR_PARAMETER;
1345   -
1346   - // Update settings
1347   - this->settings.voltage[channel].used = used;
1348   - unsigned int channelCount = 0;
1349   - for (int channelCounter = 0; channelCounter < HANTEK_CHANNELS;
1350   - ++channelCounter) {
1351   - if (this->settings.voltage[channelCounter].used)
1352   - ++channelCount;
1353   - }
1354   -
1355   - // Calculate the UsedChannels field for the command
1356   - unsigned char usedChannels = USED_CH1;
1357   -
1358   - if (this->settings.voltage[1].used) {
1359   - if (this->settings.voltage[0].used) {
1360   - usedChannels = USED_CH1CH2;
1361   - } else {
1362   - // DSO-2250 uses a different value for channel 2
1363   - if (this->specification.command.bulk.setChannels == BULK_BSETCHANNELS)
1364   - usedChannels = BUSED_CH2;
1365   - else
1366   - usedChannels = USED_CH2;
  1288 +int HantekDsoControl::setChannelUsed(unsigned int channel, bool used) {
  1289 + if (!this->device->isConnected())
  1290 + return Dso::ERROR_CONNECTION;
  1291 +
  1292 + if (channel >= HANTEK_CHANNELS)
  1293 + return Dso::ERROR_PARAMETER;
  1294 +
  1295 + // Update settings
  1296 + this->settings.voltage[channel].used = used;
  1297 + unsigned int channelCount = 0;
  1298 + for (int channelCounter = 0; channelCounter < HANTEK_CHANNELS;
  1299 + ++channelCounter) {
  1300 + if (this->settings.voltage[channelCounter].used)
  1301 + ++channelCount;
  1302 + }
  1303 +
  1304 + // Calculate the UsedChannels field for the command
  1305 + unsigned char usedChannels = USED_CH1;
  1306 +
  1307 + if (this->settings.voltage[1].used) {
  1308 + if (this->settings.voltage[0].used) {
  1309 + usedChannels = USED_CH1CH2;
  1310 + } else {
  1311 + // DSO-2250 uses a different value for channel 2
  1312 + if (this->specification.command.bulk.setChannels == BULK_BSETCHANNELS)
  1313 + usedChannels = BUSED_CH2;
  1314 + else
  1315 + usedChannels = USED_CH2;
  1316 + }
  1317 + }
  1318 +
  1319 + switch (this->specification.command.bulk.setChannels) {
  1320 + case BULK_SETTRIGGERANDSAMPLERATE: {
  1321 + // SetTriggerAndSamplerate bulk command for trigger source
  1322 + static_cast<BulkSetTriggerAndSamplerate *>(
  1323 + this->command[BULK_SETTRIGGERANDSAMPLERATE])
  1324 + ->setUsedChannels(usedChannels);
  1325 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  1326 + break;
1367 1327 }
1368   - }
1369   -
1370   - switch (this->specification.command.bulk.setChannels) {
1371   - case BULK_SETTRIGGERANDSAMPLERATE: {
1372   - // SetTriggerAndSamplerate bulk command for trigger source
1373   - static_cast<BulkSetTriggerAndSamplerate *>(
1374   - this->command[BULK_SETTRIGGERANDSAMPLERATE])
1375   - ->setUsedChannels(usedChannels);
1376   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
1377   - break;
1378   - }
1379   - case BULK_BSETCHANNELS: {
1380   - // SetChannels2250 bulk command for active channels
1381   - static_cast<BulkSetChannels2250 *>(this->command[BULK_BSETCHANNELS])
1382   - ->setUsedChannels(usedChannels);
1383   - this->commandPending[BULK_BSETCHANNELS] = true;
1384   -
1385   - break;
1386   - }
1387   - case BULK_ESETTRIGGERORSAMPLERATE: {
1388   - // SetTrigger5200s bulk command for trigger source
1389   - static_cast<BulkSetTrigger5200 *>(
1390   - this->command[BULK_ESETTRIGGERORSAMPLERATE])
1391   - ->setUsedChannels(usedChannels);
1392   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
1393   - break;
1394   - }
1395   - default:
1396   - break;
1397   - }
1398   -
1399   - // Check if fast rate mode availability changed
1400   - bool fastRateChanged =
1401   - (this->settings.usedChannels <= 1) != (channelCount <= 1);
1402   - this->settings.usedChannels = channelCount;
1403   -
1404   - if (fastRateChanged)
1405   - this->updateSamplerateLimits();
1406   -
1407   - return Dso::ERROR_NONE;
  1328 + case BULK_BSETCHANNELS: {
  1329 + // SetChannels2250 bulk command for active channels
  1330 + static_cast<BulkSetChannels2250 *>(this->command[BULK_BSETCHANNELS])
  1331 + ->setUsedChannels(usedChannels);
  1332 + this->commandPending[BULK_BSETCHANNELS] = true;
  1333 +
  1334 + break;
  1335 + }
  1336 + case BULK_ESETTRIGGERORSAMPLERATE: {
  1337 + // SetTrigger5200s bulk command for trigger source
  1338 + static_cast<BulkSetTrigger5200 *>(
  1339 + this->command[BULK_ESETTRIGGERORSAMPLERATE])
  1340 + ->setUsedChannels(usedChannels);
  1341 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  1342 + break;
  1343 + }
  1344 + default:
  1345 + break;
  1346 + }
  1347 +
  1348 + // Check if fast rate mode availability changed
  1349 + bool fastRateChanged =
  1350 + (this->settings.usedChannels <= 1) != (channelCount <= 1);
  1351 + this->settings.usedChannels = channelCount;
  1352 +
  1353 + if (fastRateChanged)
  1354 + this->updateSamplerateLimits();
  1355 +
  1356 + return Dso::ERROR_NONE;
1408 1357 }
1409 1358  
1410 1359 /// \brief Set the coupling for the given channel.
1411 1360 /// \param channel The channel that should be set.
1412 1361 /// \param coupling The new coupling for the channel.
1413 1362 /// \return See ::Dso::ErrorCode.
1414   -int Control::setCoupling(unsigned int channel, Dso::Coupling coupling) {
1415   - if (!this->device->isConnected())
1416   - return Dso::ERROR_CONNECTION;
  1363 +int HantekDsoControl::setCoupling(unsigned int channel, Dso::Coupling coupling) {
  1364 + if (!this->device->isConnected())
  1365 + return Dso::ERROR_CONNECTION;
1417 1366  
1418   - if (channel >= HANTEK_CHANNELS)
1419   - return Dso::ERROR_PARAMETER;
  1367 + if (channel >= HANTEK_CHANNELS)
  1368 + return Dso::ERROR_PARAMETER;
1420 1369  
1421   - // if (this->device->getModel() == MODEL_DSO6022BE)
1422   - // Dso::ERROR_NONE;
  1370 + // if (this->device->getModel() == MODEL_DSO6022BE)
  1371 + // Dso::ERROR_NONE;
1423 1372  
1424   - // SetRelays control command for coupling relays
1425   - if (this->device->getModel() != MODEL_DSO6022BE) {
1426   - static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS])
1427   - ->setCoupling(channel, coupling != Dso::COUPLING_AC);
1428   - this->controlPending[CONTROLINDEX_SETRELAYS] = true;
1429   - }
  1373 + // SetRelays control command for coupling relays
  1374 + if (this->device->getUniqueModelID() != MODEL_DSO6022BE) {
  1375 + static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS])
  1376 + ->setCoupling(channel, coupling != Dso::COUPLING_AC);
  1377 + this->controlPending[CONTROLINDEX_SETRELAYS] = true;
  1378 + }
1430 1379  
1431   - return Dso::ERROR_NONE;
  1380 + return Dso::ERROR_NONE;
1432 1381 }
1433 1382  
1434 1383 /// \brief Sets the gain for the given channel.
1435 1384 /// \param channel The channel that should be set.
1436 1385 /// \param gain The gain that should be met (V/div).
1437 1386 /// \return The gain that has been set, ::Dso::ErrorCode on error.
1438   -double Control::setGain(unsigned int channel, double gain) {
1439   - if (!this->device->isConnected())
1440   - return Dso::ERROR_CONNECTION;
1441   -
1442   - if (channel >= HANTEK_CHANNELS)
1443   - return Dso::ERROR_PARAMETER;
1444   -
1445   - // Find lowest gain voltage thats at least as high as the requested
1446   - int gainId;
1447   - for (gainId = 0; gainId < this->specification.gainSteps.count() - 1; ++gainId)
1448   - if (this->specification.gainSteps[gainId] >= gain)
1449   - break;
1450   -
1451   - // Fixme, shoulb be some kind of protocol check instead of model check.
1452   - if (this->device->getModel() == MODEL_DSO6022BE) {
1453   - if (channel == 0) {
1454   - static_cast<ControlSetVoltDIV_CH1 *>(
1455   - this->control[CONTROLINDEX_SETVOLTDIV_CH1])
1456   - ->setDiv(this->specification.gainDiv[gainId]);
1457   - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true;
1458   - } else if (channel == 1) {
1459   - static_cast<ControlSetVoltDIV_CH2 *>(
1460   - this->control[CONTROLINDEX_SETVOLTDIV_CH2])
1461   - ->setDiv(this->specification.gainDiv[gainId]);
1462   - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true;
1463   - } else
1464   - qDebug("%s: Unsuported channel: %i\n", __func__, channel);
1465   - } else {
1466   - // SetGain bulk command for gain
1467   - static_cast<BulkSetGain *>(this->command[BULK_SETGAIN])
1468   - ->setGain(channel, this->specification.gainIndex[gainId]);
1469   - this->commandPending[BULK_SETGAIN] = true;
1470   -
1471   - // SetRelays control command for gain relays
1472   - ControlSetRelays *controlSetRelays =
1473   - static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS]);
1474   - controlSetRelays->setBelow1V(channel, gainId < 3);
1475   - controlSetRelays->setBelow100mV(channel, gainId < 6);
1476   - this->controlPending[CONTROLINDEX_SETRELAYS] = true;
1477   - }
  1387 +double HantekDsoControl::setGain(unsigned int channel, double gain) {
  1388 + if (!this->device->isConnected())
  1389 + return Dso::ERROR_CONNECTION;
  1390 +
  1391 + if (channel >= HANTEK_CHANNELS)
  1392 + return Dso::ERROR_PARAMETER;
  1393 +
  1394 + // Find lowest gain voltage thats at least as high as the requested
  1395 + int gainId;
  1396 + for (gainId = 0; gainId < this->specification.gainSteps.count() - 1; ++gainId)
  1397 + if (this->specification.gainSteps[gainId] >= gain)
  1398 + break;
1478 1399  
1479   - this->settings.voltage[channel].gain = gainId;
  1400 + // Fixme, shoulb be some kind of protocol check instead of model check.
  1401 + if (this->device->getUniqueModelID() == MODEL_DSO6022BE) {
  1402 + if (channel == 0) {
  1403 + static_cast<ControlSetVoltDIV_CH1 *>(
  1404 + this->control[CONTROLINDEX_SETVOLTDIV_CH1])
  1405 + ->setDiv(this->specification.gainDiv[gainId]);
  1406 + this->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true;
  1407 + } else if (channel == 1) {
  1408 + static_cast<ControlSetVoltDIV_CH2 *>(
  1409 + this->control[CONTROLINDEX_SETVOLTDIV_CH2])
  1410 + ->setDiv(this->specification.gainDiv[gainId]);
  1411 + this->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true;
  1412 + } else
  1413 + qDebug("%s: Unsuported channel: %i\n", __func__, channel);
  1414 + } else {
  1415 + // SetGain bulk command for gain
  1416 + static_cast<BulkSetGain *>(this->command[BULK_SETGAIN])
  1417 + ->setGain(channel, this->specification.gainIndex[gainId]);
  1418 + this->commandPending[BULK_SETGAIN] = true;
  1419 +
  1420 + // SetRelays control command for gain relays
  1421 + ControlSetRelays *controlSetRelays =
  1422 + static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS]);
  1423 + controlSetRelays->setBelow1V(channel, gainId < 3);
  1424 + controlSetRelays->setBelow100mV(channel, gainId < 6);
  1425 + this->controlPending[CONTROLINDEX_SETRELAYS] = true;
  1426 + }
1480 1427  
1481   - this->setOffset(channel, this->settings.voltage[channel].offset);
  1428 + this->settings.voltage[channel].gain = gainId;
1482 1429  
1483   - return this->specification.gainSteps[gainId];
  1430 + this->setOffset(channel, this->settings.voltage[channel].offset);
  1431 +
  1432 + return this->specification.gainSteps[gainId];
1484 1433 }
1485 1434  
1486 1435 /// \brief Set the offset for the given channel.
1487 1436 /// \param channel The channel that should be set.
1488 1437 /// \param offset The new offset value (0.0 - 1.0).
1489 1438 /// \return The offset that has been set, ::Dso::ErrorCode on error.
1490   -double Control::setOffset(unsigned int channel, double offset) {
1491   - if (!this->device->isConnected())
1492   - return Dso::ERROR_CONNECTION;
1493   -
1494   - if (channel >= HANTEK_CHANNELS)
1495   - return Dso::ERROR_PARAMETER;
1496   -
1497   - // Calculate the offset value
1498   - // The range is given by the calibration data (convert from big endian)
1499   - unsigned short int minimum =
1500   - ((unsigned short int)*((unsigned char *)&(
1501   - this->specification
1502   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1503   - [OFFSET_START]))
1504   - << 8) +
1505   - *((unsigned char *)&(
1506   - this->specification
1507   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1508   - [OFFSET_START]) +
1509   - 1);
1510   - unsigned short int maximum =
1511   - ((unsigned short int)*((unsigned char *)&(
1512   - this->specification
1513   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1514   - [OFFSET_END]))
1515   - << 8) +
1516   - *((unsigned char *)&(
1517   - this->specification
1518   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1519   - [OFFSET_END]) +
1520   - 1);
1521   - unsigned short int offsetValue = offset * (maximum - minimum) + minimum + 0.5;
1522   - double offsetReal = (double)(offsetValue - minimum) / (maximum - minimum);
1523   -
1524   - // SetOffset control command for channel offset
1525   - // Don't set control command if 6022be.
1526   - // Otherwise, pipe error messages will be appeared.
1527   - if (this->device->getModel() != MODEL_DSO6022BE) {
1528   - static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])
1529   - ->setChannel(channel, offsetValue);
1530   - this->controlPending[CONTROLINDEX_SETOFFSET] = true;
1531   - }
1532   -
1533   - this->settings.voltage[channel].offset = offset;
1534   - this->settings.voltage[channel].offsetReal = offsetReal;
1535   -
1536   - this->setTriggerLevel(channel, this->settings.trigger.level[channel]);
1537   -
1538   - return offsetReal;
  1439 +double HantekDsoControl::setOffset(unsigned int channel, double offset) {
  1440 + if (!this->device->isConnected())
  1441 + return Dso::ERROR_CONNECTION;
  1442 +
  1443 + if (channel >= HANTEK_CHANNELS)
  1444 + return Dso::ERROR_PARAMETER;
  1445 +
  1446 + // Calculate the offset value
  1447 + // The range is given by the calibration data (convert from big endian)
  1448 + unsigned short int minimum =
  1449 + ((unsigned short int)*((unsigned char *)&(
  1450 + this->specification
  1451 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1452 + [OFFSET_START]))
  1453 + << 8) +
  1454 + *((unsigned char *)&(
  1455 + this->specification
  1456 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1457 + [OFFSET_START]) +
  1458 + 1);
  1459 + unsigned short int maximum =
  1460 + ((unsigned short int)*((unsigned char *)&(
  1461 + this->specification
  1462 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1463 + [OFFSET_END]))
  1464 + << 8) +
  1465 + *((unsigned char *)&(
  1466 + this->specification
  1467 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1468 + [OFFSET_END]) +
  1469 + 1);
  1470 + unsigned short int offsetValue = offset * (maximum - minimum) + minimum + 0.5;
  1471 + double offsetReal = (double)(offsetValue - minimum) / (maximum - minimum);
  1472 +
  1473 + // SetOffset control command for channel offset
  1474 + // Don't set control command if 6022be.
  1475 + // Otherwise, pipe error messages will be appeared.
  1476 + if (this->device->getUniqueModelID() != MODEL_DSO6022BE) {
  1477 + static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])
  1478 + ->setChannel(channel, offsetValue);
  1479 + this->controlPending[CONTROLINDEX_SETOFFSET] = true;
  1480 + }
  1481 +
  1482 + this->settings.voltage[channel].offset = offset;
  1483 + this->settings.voltage[channel].offsetReal = offsetReal;
  1484 +
  1485 + this->setTriggerLevel(channel, this->settings.trigger.level[channel]);
  1486 +
  1487 + return offsetReal;
1539 1488 }
1540 1489  
1541 1490 /// \brief Set the trigger mode.
1542 1491 /// \return See ::Dso::ErrorCode.
1543   -int Control::setTriggerMode(Dso::TriggerMode mode) {
1544   - if (!this->device->isConnected())
1545   - return Dso::ERROR_CONNECTION;
  1492 +int HantekDsoControl::setTriggerMode(Dso::TriggerMode mode) {
  1493 + if (!this->device->isConnected())
  1494 + return Dso::ERROR_CONNECTION;
1546 1495  
1547   - if (mode < Dso::TRIGGERMODE_AUTO || mode >= Dso::TRIGGERMODE_COUNT)
1548   - return Dso::ERROR_PARAMETER;
  1496 + if (mode < Dso::TRIGGERMODE_AUTO || mode >= Dso::TRIGGERMODE_COUNT)
  1497 + return Dso::ERROR_PARAMETER;
1549 1498  
1550   - this->settings.trigger.mode = mode;
1551   - return Dso::ERROR_NONE;
  1499 + this->settings.trigger.mode = mode;
  1500 + return Dso::ERROR_NONE;
1552 1501 }
1553 1502  
1554 1503 /// \brief Set the trigger source.
1555 1504 /// \param special true for a special channel (EXT, ...) as trigger source.
1556 1505 /// \param id The number of the channel, that should be used as trigger.
1557 1506 /// \return See ::Dso::ErrorCode.
1558   -int Control::setTriggerSource(bool special, unsigned int id) {
1559   - if (!this->device->isConnected())
1560   - return Dso::ERROR_CONNECTION;
1561   -
1562   - if ((!special && id >= HANTEK_CHANNELS) ||
1563   - (special && id >= HANTEK_SPECIAL_CHANNELS))
1564   - return Dso::ERROR_PARAMETER;
1565   -
1566   - switch (this->specification.command.bulk.setTrigger) {
1567   - case BULK_SETTRIGGERANDSAMPLERATE:
1568   - // SetTriggerAndSamplerate bulk command for trigger source
1569   - static_cast<BulkSetTriggerAndSamplerate *>(
1570   - this->command[BULK_SETTRIGGERANDSAMPLERATE])
1571   - ->setTriggerSource(special ? 3 + id : 1 - id);
1572   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
1573   - break;
1574   -
1575   - case BULK_CSETTRIGGERORSAMPLERATE:
1576   - // SetTrigger2250 bulk command for trigger source
1577   - static_cast<BulkSetTrigger2250 *>(
1578   - this->command[BULK_CSETTRIGGERORSAMPLERATE])
1579   - ->setTriggerSource(special ? 0 : 2 + id);
1580   - this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
1581   - break;
1582   -
1583   - case BULK_ESETTRIGGERORSAMPLERATE:
1584   - // SetTrigger5200 bulk command for trigger source
1585   - static_cast<BulkSetTrigger5200 *>(
1586   - this->command[BULK_ESETTRIGGERORSAMPLERATE])
1587   - ->setTriggerSource(special ? 3 + id : 1 - id);
1588   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
1589   - break;
1590   -
1591   - default:
1592   - return Dso::ERROR_UNSUPPORTED;
1593   - }
1594   -
1595   - // SetRelays control command for external trigger relay
1596   - static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS])
1597   - ->setTrigger(special);
1598   - this->controlPending[CONTROLINDEX_SETRELAYS] = true;
1599   -
1600   - this->settings.trigger.special = special;
1601   - this->settings.trigger.source = id;
1602   -
1603   - // Apply trigger level of the new source
1604   - if (special) {
1605   - // SetOffset control command for changed trigger level
1606   - static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])
1607   - ->setTrigger(0x7f);
1608   - this->controlPending[CONTROLINDEX_SETOFFSET] = true;
1609   - } else
1610   - this->setTriggerLevel(id, this->settings.trigger.level[id]);
1611   -
1612   - return Dso::ERROR_NONE;
  1507 +int HantekDsoControl::setTriggerSource(bool special, unsigned int id) {
  1508 + if (!this->device->isConnected())
  1509 + return Dso::ERROR_CONNECTION;
  1510 +
  1511 + if ((!special && id >= HANTEK_CHANNELS) ||
  1512 + (special && id >= HANTEK_SPECIAL_CHANNELS))
  1513 + return Dso::ERROR_PARAMETER;
  1514 +
  1515 + switch (this->specification.command.bulk.setTrigger) {
  1516 + case BULK_SETTRIGGERANDSAMPLERATE:
  1517 + // SetTriggerAndSamplerate bulk command for trigger source
  1518 + static_cast<BulkSetTriggerAndSamplerate *>(
  1519 + this->command[BULK_SETTRIGGERANDSAMPLERATE])
  1520 + ->setTriggerSource(special ? 3 + id : 1 - id);
  1521 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  1522 + break;
  1523 +
  1524 + case BULK_CSETTRIGGERORSAMPLERATE:
  1525 + // SetTrigger2250 bulk command for trigger source
  1526 + static_cast<BulkSetTrigger2250 *>(
  1527 + this->command[BULK_CSETTRIGGERORSAMPLERATE])
  1528 + ->setTriggerSource(special ? 0 : 2 + id);
  1529 + this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
  1530 + break;
  1531 +
  1532 + case BULK_ESETTRIGGERORSAMPLERATE:
  1533 + // SetTrigger5200 bulk command for trigger source
  1534 + static_cast<BulkSetTrigger5200 *>(
  1535 + this->command[BULK_ESETTRIGGERORSAMPLERATE])
  1536 + ->setTriggerSource(special ? 3 + id : 1 - id);
  1537 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  1538 + break;
  1539 +
  1540 + default:
  1541 + return Dso::ERROR_UNSUPPORTED;
  1542 + }
  1543 +
  1544 + // SetRelays control command for external trigger relay
  1545 + static_cast<ControlSetRelays *>(this->control[CONTROLINDEX_SETRELAYS])
  1546 + ->setTrigger(special);
  1547 + this->controlPending[CONTROLINDEX_SETRELAYS] = true;
  1548 +
  1549 + this->settings.trigger.special = special;
  1550 + this->settings.trigger.source = id;
  1551 +
  1552 + // Apply trigger level of the new source
  1553 + if (special) {
  1554 + // SetOffset control command for changed trigger level
  1555 + static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])
  1556 + ->setTrigger(0x7f);
  1557 + this->controlPending[CONTROLINDEX_SETOFFSET] = true;
  1558 + } else
  1559 + this->setTriggerLevel(id, this->settings.trigger.level[id]);
  1560 +
  1561 + return Dso::ERROR_NONE;
1613 1562 }
1614 1563  
1615 1564 /// \brief Set the trigger level.
1616 1565 /// \param channel The channel that should be set.
1617 1566 /// \param level The new trigger level (V).
1618 1567 /// \return The trigger level that has been set, ::Dso::ErrorCode on error.
1619   -double Control::setTriggerLevel(unsigned int channel, double level) {
1620   - if (!this->device->isConnected())
1621   - return Dso::ERROR_CONNECTION;
1622   -
1623   - if (channel >= HANTEK_CHANNELS)
1624   - return Dso::ERROR_PARAMETER;
1625   -
1626   - // if (this->device->getModel() == MODEL_DSO6022BE)
1627   - // return Dso::ERROR_NONE;
1628   -
1629   - // Calculate the trigger level value
1630   - unsigned short int minimum, maximum;
1631   - switch (this->device->getModel()) {
1632   - case MODEL_DSO5200:
1633   - case MODEL_DSO5200A:
1634   - // The range is the same as used for the offsets for 10 bit models
1635   - minimum =
1636   - ((unsigned short int)*((unsigned char *)&(
1637   - this->specification
1638   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1639   - [OFFSET_START]))
1640   - << 8) +
1641   - *((unsigned char *)&(
1642   - this->specification
1643   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1644   - [OFFSET_START]) +
1645   - 1);
1646   - maximum =
1647   - ((unsigned short int)*((unsigned char *)&(
1648   - this->specification
1649   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1650   - [OFFSET_END]))
1651   - << 8) +
1652   - *((unsigned char *)&(
1653   - this->specification
1654   - .offsetLimit[channel][this->settings.voltage[channel].gain]
1655   - [OFFSET_END]) +
1656   - 1);
1657   - break;
1658   -
1659   - default:
1660   - // It's from 0x00 to 0xfd for the 8 bit models
1661   - minimum = 0x00;
1662   - maximum = 0xfd;
1663   - break;
1664   - }
1665   -
1666   - // Never get out of the limits
1667   - unsigned short int levelValue = qBound(
1668   - (long int)minimum,
1669   - (long int)((this->settings.voltage[channel].offsetReal +
1670   - level /
  1568 +double HantekDsoControl::setTriggerLevel(unsigned int channel, double level) {
  1569 + if (!this->device->isConnected())
  1570 + return Dso::ERROR_CONNECTION;
  1571 +
  1572 + if (channel >= HANTEK_CHANNELS)
  1573 + return Dso::ERROR_PARAMETER;
  1574 +
  1575 + // if (this->device->getModel() == MODEL_DSO6022BE)
  1576 + // return Dso::ERROR_NONE;
  1577 +
  1578 + // Calculate the trigger level value
  1579 + unsigned short int minimum, maximum;
  1580 + switch (this->device->getUniqueModelID()) {
  1581 + case MODEL_DSO5200:
  1582 + case MODEL_DSO5200A:
  1583 + // The range is the same as used for the offsets for 10 bit models
  1584 + minimum =
  1585 + ((unsigned short int)*((unsigned char *)&(
  1586 + this->specification
  1587 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1588 + [OFFSET_START]))
  1589 + << 8) +
  1590 + *((unsigned char *)&(
  1591 + this->specification
  1592 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1593 + [OFFSET_START]) +
  1594 + 1);
  1595 + maximum =
  1596 + ((unsigned short int)*((unsigned char *)&(
  1597 + this->specification
  1598 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1599 + [OFFSET_END]))
  1600 + << 8) +
  1601 + *((unsigned char *)&(
1671 1602 this->specification
1672   - .gainSteps[this->settings.voltage[channel].gain]) *
1673   - (maximum - minimum) +
1674   - 0.5) +
1675   - minimum,
1676   - (long int)maximum);
1677   -
1678   - // Check if the set channel is the trigger source
1679   - if (!this->settings.trigger.special &&
1680   - channel == this->settings.trigger.source &&
1681   - this->device->getModel() != MODEL_DSO6022BE) {
1682   - // SetOffset control command for trigger level
1683   - static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])
1684   - ->setTrigger(levelValue);
1685   - this->controlPending[CONTROLINDEX_SETOFFSET] = true;
1686   - }
1687   -
1688   - /// \todo Get alternating trigger in here
1689   -
1690   - this->settings.trigger.level[channel] = level;
1691   - return (double)((levelValue - minimum) / (maximum - minimum) -
1692   - this->settings.voltage[channel].offsetReal) *
1693   - this->specification.gainSteps[this->settings.voltage[channel].gain];
  1603 + .offsetLimit[channel][this->settings.voltage[channel].gain]
  1604 + [OFFSET_END]) +
  1605 + 1);
  1606 + break;
  1607 +
  1608 + default:
  1609 + // It's from 0x00 to 0xfd for the 8 bit models
  1610 + minimum = 0x00;
  1611 + maximum = 0xfd;
  1612 + break;
  1613 + }
  1614 +
  1615 + // Never get out of the limits
  1616 + unsigned short int levelValue = qBound(
  1617 + (long int)minimum,
  1618 + (long int)((this->settings.voltage[channel].offsetReal +
  1619 + level /
  1620 + this->specification
  1621 + .gainSteps[this->settings.voltage[channel].gain]) *
  1622 + (maximum - minimum) +
  1623 + 0.5) +
  1624 + minimum,
  1625 + (long int)maximum);
  1626 +
  1627 + // Check if the set channel is the trigger source
  1628 + if (!this->settings.trigger.special &&
  1629 + channel == this->settings.trigger.source &&
  1630 + this->device->getUniqueModelID() != MODEL_DSO6022BE) {
  1631 + // SetOffset control command for trigger level
  1632 + static_cast<ControlSetOffset *>(this->control[CONTROLINDEX_SETOFFSET])
  1633 + ->setTrigger(levelValue);
  1634 + this->controlPending[CONTROLINDEX_SETOFFSET] = true;
  1635 + }
  1636 +
  1637 + /// \todo Get alternating trigger in here
  1638 +
  1639 + this->settings.trigger.level[channel] = level;
  1640 + return (double)((levelValue - minimum) / (maximum - minimum) -
  1641 + this->settings.voltage[channel].offsetReal) *
  1642 + this->specification.gainSteps[this->settings.voltage[channel].gain];
1694 1643 }
1695 1644  
1696 1645 /// \brief Set the trigger slope.
1697 1646 /// \param slope The Slope that should cause a trigger.
1698 1647 /// \return See ::Dso::ErrorCode.
1699   -int Control::setTriggerSlope(Dso::Slope slope) {
1700   - if (!this->device->isConnected())
1701   - return Dso::ERROR_CONNECTION;
1702   -
1703   - if (slope != Dso::SLOPE_NEGATIVE && slope != Dso::SLOPE_POSITIVE)
1704   - return Dso::ERROR_PARAMETER;
1705   -
1706   - switch (this->specification.command.bulk.setTrigger) {
1707   - case BULK_SETTRIGGERANDSAMPLERATE: {
1708   - // SetTriggerAndSamplerate bulk command for trigger slope
1709   - static_cast<BulkSetTriggerAndSamplerate *>(
1710   - this->command[BULK_SETTRIGGERANDSAMPLERATE])
1711   - ->setTriggerSlope(slope);
1712   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
1713   - break;
1714   - }
1715   - case BULK_CSETTRIGGERORSAMPLERATE: {
1716   - // SetTrigger2250 bulk command for trigger slope
1717   - static_cast<BulkSetTrigger2250 *>(
1718   - this->command[BULK_CSETTRIGGERORSAMPLERATE])
1719   - ->setTriggerSlope(slope);
1720   - this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
1721   - break;
1722   - }
1723   - case BULK_ESETTRIGGERORSAMPLERATE: {
1724   - // SetTrigger5200 bulk command for trigger slope
1725   - static_cast<BulkSetTrigger5200 *>(
1726   - this->command[BULK_ESETTRIGGERORSAMPLERATE])
1727   - ->setTriggerSlope(slope);
1728   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
1729   - break;
1730   - }
1731   - default:
1732   - return Dso::ERROR_UNSUPPORTED;
1733   - }
  1648 +int HantekDsoControl::setTriggerSlope(Dso::Slope slope) {
  1649 + if (!this->device->isConnected())
  1650 + return Dso::ERROR_CONNECTION;
1734 1651  
1735   - this->settings.trigger.slope = slope;
1736   - return Dso::ERROR_NONE;
  1652 + if (slope != Dso::SLOPE_NEGATIVE && slope != Dso::SLOPE_POSITIVE)
  1653 + return Dso::ERROR_PARAMETER;
  1654 +
  1655 + switch (this->specification.command.bulk.setTrigger) {
  1656 + case BULK_SETTRIGGERANDSAMPLERATE: {
  1657 + // SetTriggerAndSamplerate bulk command for trigger slope
  1658 + static_cast<BulkSetTriggerAndSamplerate *>(
  1659 + this->command[BULK_SETTRIGGERANDSAMPLERATE])
  1660 + ->setTriggerSlope(slope);
  1661 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  1662 + break;
  1663 + }
  1664 + case BULK_CSETTRIGGERORSAMPLERATE: {
  1665 + // SetTrigger2250 bulk command for trigger slope
  1666 + static_cast<BulkSetTrigger2250 *>(
  1667 + this->command[BULK_CSETTRIGGERORSAMPLERATE])
  1668 + ->setTriggerSlope(slope);
  1669 + this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
  1670 + break;
  1671 + }
  1672 + case BULK_ESETTRIGGERORSAMPLERATE: {
  1673 + // SetTrigger5200 bulk command for trigger slope
  1674 + static_cast<BulkSetTrigger5200 *>(
  1675 + this->command[BULK_ESETTRIGGERORSAMPLERATE])
  1676 + ->setTriggerSlope(slope);
  1677 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  1678 + break;
  1679 + }
  1680 + default:
  1681 + return Dso::ERROR_UNSUPPORTED;
  1682 + }
  1683 +
  1684 + this->settings.trigger.slope = slope;
  1685 + return Dso::ERROR_NONE;
1737 1686 }
1738 1687  
1739   -int Control::forceTrigger() {
1740   - this->commandPending[BULK_FORCETRIGGER] = true;
1741   - return 0;
  1688 +int HantekDsoControl::forceTrigger() {
  1689 + this->commandPending[BULK_FORCETRIGGER] = true;
  1690 + return 0;
1742 1691 }
1743 1692  
1744 1693 /// \brief Set the trigger position.
1745 1694 /// \param position The new trigger position (in s).
1746 1695 /// \return The trigger position that has been set.
1747   -double Control::setPretriggerPosition(double position) {
1748   - if (!this->device->isConnected())
1749   - return -2;
1750   -
1751   - // All trigger positions are measured in samples
1752   - unsigned int positionSamples = position * this->settings.samplerate.current;
1753   - unsigned int recordLength =
1754   - this->settings.samplerate.limits
1755   - ->recordLengths[this->settings.recordLengthId];
1756   - bool rollMode = recordLength == UINT_MAX;
1757   - // Fast rate mode uses both channels
1758   - if (this->settings.samplerate.limits == &this->specification.samplerate.multi)
1759   - positionSamples /= HANTEK_CHANNELS;
1760   -
1761   - switch (this->specification.command.bulk.setPretrigger) {
1762   - case BULK_SETTRIGGERANDSAMPLERATE: {
1763   - // Calculate the position value (Start point depending on record length)
1764   - unsigned int position =
1765   - rollMode ? 0x1 : 0x7ffff - recordLength + positionSamples;
1766   -
1767   - // SetTriggerAndSamplerate bulk command for trigger position
1768   - static_cast<BulkSetTriggerAndSamplerate *>(
1769   - this->command[BULK_SETTRIGGERANDSAMPLERATE])
1770   - ->setTriggerPosition(position);
1771   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
1772   -
1773   - break;
1774   - }
1775   - case BULK_FSETBUFFER: {
1776   - // Calculate the position values (Inverse, maximum is 0x7ffff)
1777   - unsigned int positionPre = 0x7ffff - recordLength + positionSamples;
1778   - unsigned int positionPost = 0x7ffff - positionSamples;
1779   -
1780   - // SetBuffer2250 bulk command for trigger position
1781   - BulkSetBuffer2250 *commandSetBuffer2250 =
1782   - static_cast<BulkSetBuffer2250 *>(this->command[BULK_FSETBUFFER]);
1783   - commandSetBuffer2250->setTriggerPositionPre(positionPre);
1784   - commandSetBuffer2250->setTriggerPositionPost(positionPost);
1785   - this->commandPending[BULK_FSETBUFFER] = true;
1786   -
1787   - break;
1788   - }
1789   - case BULK_ESETTRIGGERORSAMPLERATE: {
1790   - // Calculate the position values (Inverse, maximum is 0xffff)
1791   - unsigned short int positionPre = 0xffff - recordLength + positionSamples;
1792   - unsigned short int positionPost = 0xffff - positionSamples;
1793   -
1794   - // SetBuffer5200 bulk command for trigger position
1795   - BulkSetBuffer5200 *commandSetBuffer5200 =
1796   - static_cast<BulkSetBuffer5200 *>(this->command[BULK_DSETBUFFER]);
1797   - commandSetBuffer5200->setTriggerPositionPre(positionPre);
1798   - commandSetBuffer5200->setTriggerPositionPost(positionPost);
1799   - this->commandPending[BULK_DSETBUFFER] = true;
1800   -
1801   - break;
1802   - }
1803   - default:
1804   - return Dso::ERROR_UNSUPPORTED;
1805   - }
  1696 +double HantekDsoControl::setPretriggerPosition(double position) {
  1697 + if (!this->device->isConnected())
  1698 + return -2;
  1699 +
  1700 + // All trigger positions are measured in samples
  1701 + unsigned int positionSamples = position * this->settings.samplerate.current;
  1702 + unsigned int recordLength =
  1703 + this->settings.samplerate.limits
  1704 + ->recordLengths[this->settings.recordLengthId];
  1705 + bool rollMode = recordLength == UINT_MAX;
  1706 + // Fast rate mode uses both channels
  1707 + if (this->settings.samplerate.limits == &this->specification.samplerate.multi)
  1708 + positionSamples /= HANTEK_CHANNELS;
  1709 +
  1710 + switch (this->specification.command.bulk.setPretrigger) {
  1711 + case BULK_SETTRIGGERANDSAMPLERATE: {
  1712 + // Calculate the position value (Start point depending on record length)
  1713 + unsigned int position =
  1714 + rollMode ? 0x1 : 0x7ffff - recordLength + positionSamples;
  1715 +
  1716 + // SetTriggerAndSamplerate bulk command for trigger position
  1717 + static_cast<BulkSetTriggerAndSamplerate *>(
  1718 + this->command[BULK_SETTRIGGERANDSAMPLERATE])
  1719 + ->setTriggerPosition(position);
  1720 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
1806 1721  
1807   - this->settings.trigger.position = position;
1808   - return (double)positionSamples / this->settings.samplerate.current;
  1722 + break;
  1723 + }
  1724 + case BULK_FSETBUFFER: {
  1725 + // Calculate the position values (Inverse, maximum is 0x7ffff)
  1726 + unsigned int positionPre = 0x7ffff - recordLength + positionSamples;
  1727 + unsigned int positionPost = 0x7ffff - positionSamples;
  1728 +
  1729 + // SetBuffer2250 bulk command for trigger position
  1730 + BulkSetBuffer2250 *commandSetBuffer2250 =
  1731 + static_cast<BulkSetBuffer2250 *>(this->command[BULK_FSETBUFFER]);
  1732 + commandSetBuffer2250->setTriggerPositionPre(positionPre);
  1733 + commandSetBuffer2250->setTriggerPositionPost(positionPost);
  1734 + this->commandPending[BULK_FSETBUFFER] = true;
  1735 +
  1736 + break;
  1737 + }
  1738 + case BULK_ESETTRIGGERORSAMPLERATE: {
  1739 + // Calculate the position values (Inverse, maximum is 0xffff)
  1740 + unsigned short int positionPre = 0xffff - recordLength + positionSamples;
  1741 + unsigned short int positionPost = 0xffff - positionSamples;
  1742 +
  1743 + // SetBuffer5200 bulk command for trigger position
  1744 + BulkSetBuffer5200 *commandSetBuffer5200 =
  1745 + static_cast<BulkSetBuffer5200 *>(this->command[BULK_DSETBUFFER]);
  1746 + commandSetBuffer5200->setTriggerPositionPre(positionPre);
  1747 + commandSetBuffer5200->setTriggerPositionPost(positionPost);
  1748 + this->commandPending[BULK_DSETBUFFER] = true;
  1749 +
  1750 + break;
  1751 + }
  1752 + default:
  1753 + return Dso::ERROR_UNSUPPORTED;
  1754 + }
  1755 +
  1756 + this->settings.trigger.position = position;
  1757 + return (double)positionSamples / this->settings.samplerate.current;
1809 1758 }
1810 1759  
1811 1760 #ifdef DEBUG
... ... @@ -1821,334 +1770,333 @@ double Control::setPretriggerPosition(double position) {
1821 1770 /// \param command The command as string (Has to be parsed).
1822 1771 /// \return See ::Dso::ErrorCode.
1823 1772 int Control::stringCommand(QString command) {
1824   - if (!this->device->isConnected())
1825   - return Dso::ERROR_CONNECTION;
1826   -
1827   - QStringList commandParts = command.split(' ', QString::SkipEmptyParts);
1828   -
1829   - if (commandParts.count() >= 1) {
1830   - if (commandParts[0] == "send") {
1831   - if (commandParts.count() >= 2) {
1832   - if (commandParts[1] == "bulk") {
1833   - QString data = command.section(' ', 2, -1, QString::SectionSkipEmpty);
1834   - unsigned char commandCode = 0;
1835   -
1836   - // Read command code (First byte)
1837   - Helper::hexParse(commandParts[2], &commandCode, 1);
1838   - if (commandCode > BULK_COUNT)
1839   - return Dso::ERROR_UNSUPPORTED;
1840   -
1841   - // Update bulk command and mark as pending
1842   - Helper::hexParse(data, this->command[commandCode]->data(),
1843   - this->command[commandCode]->getSize());
1844   - this->commandPending[commandCode] = true;
1845   - return Dso::ERROR_NONE;
1846   - } else if (commandParts[1] == "control") {
1847   - unsigned char controlCode = 0;
1848   -
1849   - // Read command code (First byte)
1850   - Helper::hexParse(commandParts[2], &controlCode, 1);
1851   - int control;
1852   - for (control = 0; control < CONTROLINDEX_COUNT; ++control) {
1853   - if (this->controlCode[control] == controlCode)
1854   - break;
1855   - }
1856   - if (control >= CONTROLINDEX_COUNT)
1857   - return Dso::ERROR_UNSUPPORTED;
1858   -
1859   - QString data = command.section(' ', 3, -1, QString::SectionSkipEmpty);
1860   -
1861   - // Update control command and mark as pending
1862   - Helper::hexParse(data, this->control[control]->data(),
1863   - this->control[control]->getSize());
1864   - this->controlPending[control] = true;
1865   - return Dso::ERROR_NONE;
  1773 + if (!this->device->isConnected())
  1774 + return Dso::ERROR_CONNECTION;
  1775 +
  1776 + QStringList commandParts = command.split(' ', QString::SkipEmptyParts);
  1777 +
  1778 + if (commandParts.count() >= 1) {
  1779 + if (commandParts[0] == "send") {
  1780 + if (commandParts.count() >= 2) {
  1781 + if (commandParts[1] == "bulk") {
  1782 + QString data = command.section(' ', 2, -1, QString::SectionSkipEmpty);
  1783 + unsigned char commandCode = 0;
  1784 +
  1785 + // Read command code (First byte)
  1786 + hexParse(commandParts[2], &commandCode, 1);
  1787 + if (commandCode > BULK_COUNT)
  1788 + return Dso::ERROR_UNSUPPORTED;
  1789 +
  1790 + // Update bulk command and mark as pending
  1791 + hexParse(data, this->command[commandCode]->data(),
  1792 + this->command[commandCode]->getSize());
  1793 + this->commandPending[commandCode] = true;
  1794 + return Dso::ERROR_NONE;
  1795 + } else if (commandParts[1] == "control") {
  1796 + unsigned char controlCode = 0;
  1797 +
  1798 + // Read command code (First byte)
  1799 + hexParse(commandParts[2], &controlCode, 1);
  1800 + int control;
  1801 + for (control = 0; control < CONTROLINDEX_COUNT; ++control) {
  1802 + if (this->controlCode[control] == controlCode)
  1803 + break;
  1804 + }
  1805 + if (control >= CONTROLINDEX_COUNT)
  1806 + return Dso::ERROR_UNSUPPORTED;
  1807 +
  1808 + QString data = command.section(' ', 3, -1, QString::SectionSkipEmpty);
  1809 +
  1810 + // Update control command and mark as pending
  1811 + hexParse(data, this->control[control]->data(),
  1812 + this->control[control]->getSize());
  1813 + this->controlPending[control] = true;
  1814 + return Dso::ERROR_NONE;
  1815 + }
  1816 + } else {
  1817 + return Dso::ERROR_PARAMETER;
  1818 + }
1866 1819 }
1867   - } else {
  1820 + } else {
1868 1821 return Dso::ERROR_PARAMETER;
1869   - }
1870 1822 }
1871   - } else {
1872   - return Dso::ERROR_PARAMETER;
1873   - }
1874 1823  
1875   - return Dso::ERROR_UNSUPPORTED;
  1824 + return Dso::ERROR_UNSUPPORTED;
1876 1825 }
1877 1826 #endif
1878 1827  
1879   -/// \brief Called periodically in the control thread by a timer.
1880   -void Control::handler() {
1881   - int errorCode = 0;
  1828 +/// \brief Called periodically in the control thread by a timer->
  1829 +void HantekDsoControl::run() {
  1830 + int errorCode = 0;
1882 1831  
1883   - // Send all pending bulk commands
1884   - for (int command = 0; command < BULK_COUNT; ++command) {
1885   - if (!this->commandPending[command])
1886   - continue;
  1832 + // Send all pending bulk commands
  1833 + for (int command = 0; command < BULK_COUNT; ++command) {
  1834 + if (!this->commandPending[command])
  1835 + continue;
1887 1836  
1888 1837 #ifdef DEBUG
1889   - Helper::timestampDebug(
1890   - QString("Sending bulk command:%1")
1891   - .arg(Helper::hexDump(this->command[command]->data(),
1892   - this->command[command]->getSize())));
  1838 + timestampDebug(
  1839 + QString("Sending bulk command:%1")
  1840 + .arg(hexDump(this->command[command]->data(),
  1841 + this->command[command]->getSize())));
1893 1842 #endif
1894 1843  
1895   - errorCode = this->device->bulkCommand(this->command[command]);
1896   - if (errorCode < 0) {
1897   - qWarning("Sending bulk command %02x failed: %s", command,
1898   - Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
  1844 + errorCode = this->device->bulkCommand(this->command[command]);
  1845 + if (errorCode < 0) {
  1846 + qWarning("Sending bulk command %02x failed: %s", command,
  1847 + libUsbErrorString(errorCode).toLocal8Bit().data());
1899 1848  
1900   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1901   - this->quit();
1902   - return;
1903   - }
1904   - } else
1905   - this->commandPending[command] = false;
1906   - }
  1849 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  1850 + emit communicationError();
  1851 + return;
  1852 + }
  1853 + } else
  1854 + this->commandPending[command] = false;
  1855 + }
1907 1856  
1908   - // Send all pending control commands
1909   - for (int control = 0; control < CONTROLINDEX_COUNT; ++control) {
1910   - if (!this->controlPending[control])
1911   - continue;
  1857 + // Send all pending control commands
  1858 + for (int control = 0; control < CONTROLINDEX_COUNT; ++control) {
  1859 + if (!this->controlPending[control])
  1860 + continue;
1912 1861  
1913 1862 #ifdef DEBUG
1914   - Helper::timestampDebug(
1915   - QString("Sending control command %1:%2")
1916   - .arg(QString::number(this->controlCode[control], 16),
1917   - Helper::hexDump(this->control[control]->data(),
1918   - this->control[control]->getSize())));
  1863 + timestampDebug(
  1864 + QString("Sending control command %1:%2")
  1865 + .arg(QString::number(this->controlCode[control], 16),
  1866 + hexDump(this->control[control]->data(),
  1867 + this->control[control]->getSize())));
1919 1868 #endif
1920 1869  
1921   - errorCode = this->device->controlWrite(this->controlCode[control],
1922   - this->control[control]->data(),
1923   - this->control[control]->getSize());
1924   - if (errorCode < 0) {
1925   - qWarning("Sending control command %2x failed: %s",
1926   - this->controlCode[control],
1927   - Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
1928   -
1929   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1930   - this->quit();
1931   - return;
1932   - }
1933   - } else
1934   - this->controlPending[control] = false;
1935   - }
  1870 + errorCode = this->device->controlWrite(this->controlCode[control],
  1871 + this->control[control]->data(),
  1872 + this->control[control]->getSize());
  1873 + if (errorCode < 0) {
  1874 + qWarning("Sending control command %2x failed: %s",
  1875 + this->controlCode[control],
  1876 + libUsbErrorString(errorCode).toLocal8Bit().data());
1936 1877  
1937   - // State machine for the device communication
1938   - if (this->settings.samplerate.limits
1939   - ->recordLengths[this->settings.recordLengthId] == UINT_MAX) {
1940   - // Roll mode
1941   - this->captureState = CAPTURE_WAITING;
1942   - bool toNextState = true;
  1878 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  1879 + emit communicationError();
  1880 + return;
  1881 + }
  1882 + } else
  1883 + this->controlPending[control] = false;
  1884 + }
1943 1885  
1944   - switch (this->rollState) {
1945   - case ROLL_STARTSAMPLING:
1946   - // Don't iterate through roll mode steps when stopped
1947   - if (!this->sampling) {
1948   - toNextState = false;
1949   - break;
1950   - }
  1886 + // State machine for the device communication
  1887 + if (this->settings.samplerate.limits
  1888 + ->recordLengths[this->settings.recordLengthId] == UINT_MAX) {
  1889 + // Roll mode
  1890 + this->captureState = CAPTURE_WAITING;
  1891 + bool toNextState = true;
  1892 +
  1893 + switch (this->rollState) {
  1894 + case ROLL_STARTSAMPLING:
  1895 + // Don't iterate through roll mode steps when stopped
  1896 + if (!this->sampling) {
  1897 + toNextState = false;
  1898 + break;
  1899 + }
1951 1900  
1952   - // Sampling hasn't started, update the expected sample count
1953   - this->previousSampleCount = this->getSampleCount();
  1901 + // Sampling hasn't started, update the expected sample count
  1902 + this->previousSampleCount = this->getSampleCount();
1954 1903  
1955   - errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
1956   - if (errorCode < 0) {
1957   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1958   - this->quit();
1959   - return;
1960   - }
1961   - break;
1962   - }
  1904 + errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
  1905 + if (errorCode < 0) {
  1906 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  1907 + emit communicationError();
  1908 + return;
  1909 + }
  1910 + break;
  1911 + }
1963 1912 #ifdef DEBUG
1964   - Helper::timestampDebug("Starting to capture");
  1913 + timestampDebug("Starting to capture");
1965 1914 #endif
1966 1915  
1967   - this->samplingStarted = true;
  1916 + this->_samplingStarted = true;
1968 1917  
1969   - break;
  1918 + break;
1970 1919  
1971   - case ROLL_ENABLETRIGGER:
1972   - errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
1973   - if (errorCode < 0) {
1974   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1975   - this->quit();
1976   - return;
1977   - }
1978   - break;
1979   - }
  1920 + case ROLL_ENABLETRIGGER:
  1921 + errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
  1922 + if (errorCode < 0) {
  1923 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  1924 + emit communicationError();
  1925 + return;
  1926 + }
  1927 + break;
  1928 + }
1980 1929 #ifdef DEBUG
1981   - Helper::timestampDebug("Enabling trigger");
  1930 + timestampDebug("Enabling trigger");
1982 1931 #endif
1983 1932  
1984   - break;
  1933 + break;
1985 1934  
1986   - case ROLL_FORCETRIGGER:
1987   - errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
1988   - if (errorCode < 0) {
1989   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
1990   - this->quit();
1991   - return;
1992   - }
1993   - break;
1994   - }
  1935 + case ROLL_FORCETRIGGER:
  1936 + errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
  1937 + if (errorCode < 0) {
  1938 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  1939 + emit communicationError();
  1940 + return;
  1941 + }
  1942 + break;
  1943 + }
1995 1944 #ifdef DEBUG
1996   - Helper::timestampDebug("Forcing trigger");
  1945 + timestampDebug("Forcing trigger");
1997 1946 #endif
1998 1947  
1999   - break;
  1948 + break;
2000 1949  
2001   - case ROLL_GETDATA:
2002   - // Get data and process it, if we're still sampling
2003   - errorCode = this->getSamples(this->samplingStarted);
2004   - if (errorCode < 0)
2005   - qWarning("Getting sample data failed: %s",
2006   - Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
  1950 + case ROLL_GETDATA:
  1951 + // Get data and process it, if we're still sampling
  1952 + errorCode = this->getSamples(this->_samplingStarted);
  1953 + if (errorCode < 0)
  1954 + qWarning("Getting sample data failed: %s",
  1955 + libUsbErrorString(errorCode).toLocal8Bit().data());
2007 1956 #ifdef DEBUG
2008   - else
2009   - Helper::timestampDebug(
2010   - QString("Received %1 B of sampling data").arg(errorCode));
  1957 + else
  1958 + timestampDebug(
  1959 + QString("Received %1 B of sampling data").arg(errorCode));
2011 1960 #endif
2012 1961  
2013   - // Check if we're in single trigger mode
2014   - if (this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE &&
2015   - this->samplingStarted)
2016   - this->stopSampling();
  1962 + // Check if we're in single trigger mode
  1963 + if (this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE &&
  1964 + this->_samplingStarted)
  1965 + this->stopSampling();
2017 1966  
2018   - // Sampling completed, restart it when necessary
2019   - this->samplingStarted = false;
  1967 + // Sampling completed, restart it when necessary
  1968 + this->_samplingStarted = false;
2020 1969  
2021   - break;
  1970 + break;
2022 1971  
2023   - default:
  1972 + default:
2024 1973 #ifdef DEBUG
2025   - Helper::timestampDebug("Roll mode state unknown");
  1974 + timestampDebug("Roll mode state unknown");
2026 1975 #endif
2027   - break;
2028   - }
  1976 + break;
  1977 + }
2029 1978  
2030   - // Go to next state, or restart if last state was reached
2031   - if (toNextState)
2032   - this->rollState = (this->rollState + 1) % ROLL_COUNT;
2033   - } else {
2034   - // Standard mode
2035   - this->rollState = ROLL_STARTSAMPLING;
  1979 + // Go to next state, or restart if last state was reached
  1980 + if (toNextState)
  1981 + this->rollState = (this->rollState + 1) % ROLL_COUNT;
  1982 + } else {
  1983 + // Standard mode
  1984 + this->rollState = ROLL_STARTSAMPLING;
2036 1985  
2037 1986 #ifdef DEBUG
2038   - int lastCaptureState = this->captureState;
  1987 + int lastCaptureState = this->captureState;
2039 1988 #endif
2040   - this->captureState = this->getCaptureState();
2041   - if (this->captureState < 0)
2042   - qWarning(
2043   - "Getting capture state failed: %s",
2044   - Helper::libUsbErrorString(this->captureState).toLocal8Bit().data());
  1989 + this->captureState = this->getCaptureState();
  1990 + if (this->captureState < 0)
  1991 + qWarning(
  1992 + "Getting capture state failed: %s",
  1993 + libUsbErrorString(this->captureState).toLocal8Bit().data());
2045 1994 #ifdef DEBUG
2046   - else if (this->captureState != lastCaptureState)
2047   - Helper::timestampDebug(
2048   - QString("Capture state changed to %1").arg(this->captureState));
  1995 + else if (this->captureState != lastCaptureState)
  1996 + timestampDebug(
  1997 + QString("Capture state changed to %1").arg(this->captureState));
2049 1998 #endif
2050   - switch (this->captureState) {
2051   - case CAPTURE_READY:
2052   - case CAPTURE_READY2250:
2053   - case CAPTURE_READY5200:
2054   - // Get data and process it, if we're still sampling
2055   - errorCode = this->getSamples(this->samplingStarted);
2056   - if (errorCode < 0)
2057   - qWarning("Getting sample data failed: %s",
2058   - Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
  1999 + switch (this->captureState) {
  2000 + case CAPTURE_READY:
  2001 + case CAPTURE_READY2250:
  2002 + case CAPTURE_READY5200:
  2003 + // Get data and process it, if we're still sampling
  2004 + errorCode = this->getSamples(this->_samplingStarted);
  2005 + if (errorCode < 0)
  2006 + qWarning("Getting sample data failed: %s",
  2007 + libUsbErrorString(errorCode).toLocal8Bit().data());
2059 2008 #ifdef DEBUG
2060   - else
2061   - Helper::timestampDebug(
2062   - QString("Received %1 B of sampling data").arg(errorCode));
  2009 + else
  2010 + timestampDebug(
  2011 + QString("Received %1 B of sampling data").arg(errorCode));
2063 2012 #endif
2064 2013  
2065   - // Check if we're in single trigger mode
2066   - if (this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE &&
2067   - this->samplingStarted)
2068   - this->stopSampling();
2069   -
2070   - // Sampling completed, restart it when necessary
2071   - this->samplingStarted = false;
2072   -
2073   - // Start next capture if necessary by leaving out the break statement
2074   - if (!this->sampling)
2075   - break;
2076   -
2077   - case CAPTURE_WAITING:
2078   - // Sampling hasn't started, update the expected sample count
2079   - this->previousSampleCount = this->getSampleCount();
2080   -
2081   - if (this->samplingStarted &&
2082   - this->lastTriggerMode == this->settings.trigger.mode) {
2083   - ++this->cycleCounter;
2084   -
2085   - if (this->cycleCounter == this->startCycle &&
2086   - this->settings.samplerate.limits
2087   - ->recordLengths[this->settings.recordLengthId] !=
2088   - UINT_MAX) {
2089   - // Buffer refilled completely since start of sampling, enable the
2090   - // trigger now
2091   - errorCode =
2092   - this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
2093   - if (errorCode < 0) {
2094   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
2095   - this->quit();
2096   - return;
2097   - }
2098   - break;
2099   - }
  2014 + // Check if we're in single trigger mode
  2015 + if (this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE &&
  2016 + this->_samplingStarted)
  2017 + this->stopSampling();
  2018 +
  2019 + // Sampling completed, restart it when necessary
  2020 + this->_samplingStarted = false;
  2021 +
  2022 + // Start next capture if necessary by leaving out the break statement
  2023 + if (!this->sampling)
  2024 + break;
  2025 +
  2026 + case CAPTURE_WAITING:
  2027 + // Sampling hasn't started, update the expected sample count
  2028 + this->previousSampleCount = this->getSampleCount();
  2029 +
  2030 + if (this->_samplingStarted &&
  2031 + this->lastTriggerMode == this->settings.trigger.mode) {
  2032 + ++this->cycleCounter;
  2033 +
  2034 + if (this->cycleCounter == this->startCycle &&
  2035 + this->settings.samplerate.limits
  2036 + ->recordLengths[this->settings.recordLengthId] !=
  2037 + UINT_MAX) {
  2038 + // Buffer refilled completely since start of sampling, enable the
  2039 + // trigger now
  2040 + errorCode =
  2041 + this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
  2042 + if (errorCode < 0) {
  2043 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  2044 + emit communicationError();
  2045 + return;
  2046 + }
  2047 + break;
  2048 + }
2100 2049 #ifdef DEBUG
2101   - Helper::timestampDebug("Enabling trigger");
  2050 + timestampDebug("Enabling trigger");
2102 2051 #endif
2103   - } else if (this->cycleCounter >= 8 + this->startCycle &&
2104   - this->settings.trigger.mode == Dso::TRIGGERMODE_AUTO) {
2105   - // Force triggering
2106   - errorCode =
2107   - this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
2108   - if (errorCode < 0) {
2109   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
2110   - this->quit();
2111   - return;
2112   - }
2113   - break;
2114   - }
  2052 + } else if (this->cycleCounter >= 8 + this->startCycle &&
  2053 + this->settings.trigger.mode == Dso::TRIGGERMODE_AUTO) {
  2054 + // Force triggering
  2055 + errorCode =
  2056 + this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
  2057 + if (errorCode < 0) {
  2058 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  2059 + emit communicationError();
  2060 + return;
  2061 + }
  2062 + break;
  2063 + }
2115 2064 #ifdef DEBUG
2116   - Helper::timestampDebug("Forcing trigger");
  2065 + timestampDebug("Forcing trigger");
2117 2066 #endif
2118   - }
  2067 + }
2119 2068  
2120   - if (this->cycleCounter < 20 ||
2121   - this->cycleCounter < 4000 / this->timer->interval())
2122   - break;
2123   - }
2124   -
2125   - // Start capturing
2126   - errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
2127   - if (errorCode < 0) {
2128   - if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
2129   - this->quit();
2130   - return;
2131   - }
2132   - break;
2133   - }
  2069 + if (this->cycleCounter < 20 ||
  2070 + this->cycleCounter < 4000 / cycleTime)
  2071 + break;
  2072 + }
  2073 +
  2074 + // Start capturing
  2075 + errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
  2076 + if (errorCode < 0) {
  2077 + if (errorCode == LIBUSB_ERROR_NO_DEVICE) {
  2078 + emit communicationError();
  2079 + return;
  2080 + }
  2081 + break;
  2082 + }
2134 2083 #ifdef DEBUG
2135   - Helper::timestampDebug("Starting to capture");
  2084 + timestampDebug("Starting to capture");
2136 2085 #endif
2137 2086  
2138   - this->samplingStarted = true;
2139   - this->cycleCounter = 0;
2140   - this->startCycle =
2141   - this->settings.trigger.position * 1000 / this->timer->interval() + 1;
2142   - this->lastTriggerMode = this->settings.trigger.mode;
2143   - break;
  2087 + this->_samplingStarted = true;
  2088 + this->cycleCounter = 0;
  2089 + this->startCycle = this->settings.trigger.position * 1000 / cycleTime + 1;
  2090 + this->lastTriggerMode = this->settings.trigger.mode;
  2091 + break;
2144 2092  
2145   - case CAPTURE_SAMPLING:
2146   - break;
2147   - default:
2148   - break;
  2093 + case CAPTURE_SAMPLING:
  2094 + break;
  2095 + default:
  2096 + break;
  2097 + }
2149 2098 }
2150   - }
2151 2099  
2152   - this->updateInterval();
2153   -}
  2100 + this->updateInterval();
  2101 + QTimer::singleShot(cycleTime, this, &HantekDsoControl::run);
2154 2102 }
... ...
openhantek/src/hantek/hantekdsocontrol.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +
  5 +#include "utils/dataarray.h"
  6 +#include "controlStructs.h"
  7 +#include "bulkStructs.h"
  8 +#include "stateStructs.h"
  9 +#include "utils/printutils.h"
  10 +
  11 +#include <vector>
  12 +
  13 +#include <QStringList>
  14 +#include <QThread>
  15 +#include <QMutex>
  16 +#include <QTimer>
  17 +
  18 +class USBDevice;
  19 +
  20 +//////////////////////////////////////////////////////////////////////////////
  21 +/// \class Control hantek/control.h
  22 +/// \brief The DsoControl abstraction layer for %Hantek USB DSOs.
  23 +class HantekDsoControl : public QObject {
  24 + Q_OBJECT
  25 +
  26 +public:
  27 + /**
  28 + * Creates a dsoControl object. The actual event loop / timer is not started.
  29 + * You can optionally create a thread and move the created object to the thread.
  30 + * You need to call updateInterval() to start the timer.
  31 + * @param device
  32 + */
  33 + HantekDsoControl(USBDevice* device);
  34 + ~HantekDsoControl();
  35 + void run();
  36 +
  37 + unsigned int getChannelCount();
  38 + QList<unsigned int> *getAvailableRecordLengths();
  39 + double getMinSamplerate();
  40 + double getMaxSamplerate();
  41 +
  42 + const QStringList *getSpecialTriggerSources();
  43 +
  44 +signals:
  45 + void samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger
  46 + void samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger
  47 + void statusMessage(const QString &message,
  48 + int timeout); ///< Status message about the oscilloscope
  49 + void samplesAvailable(const std::vector<std::vector<double>> *data,
  50 + double samplerate, bool append,
  51 + QMutex *mutex); ///< New sample data is available
  52 +
  53 + void availableRecordLengthsChanged(const QList<unsigned int> &recordLengths); ///< The available record lengths, empty list for continuous
  54 + void samplerateLimitsChanged(double minimum, double maximum); ///< The minimum or maximum samplerate has changed
  55 + void recordLengthChanged(unsigned long duration); ///< The record length has changed
  56 + void recordTimeChanged(double duration); ///< The record time duration has changed
  57 + void samplerateChanged(double samplerate); ///< The samplerate has changed
  58 + void samplerateSet(int mode, QList<double> sampleSteps); ///< The samplerate has changed
  59 +
  60 + void communicationError();
  61 +
  62 +protected:
  63 + void updateInterval();
  64 + unsigned int calculateTriggerPoint(unsigned int value);
  65 + int getCaptureState();
  66 + int getSamples(bool process);
  67 + double getBestSamplerate(double samplerate, bool fastRate = false,
  68 + bool maximum = false, unsigned int *downsampler = 0);
  69 + unsigned int getSampleCount(bool *fastRate = 0);
  70 + unsigned int updateRecordLength(unsigned int size);
  71 + unsigned int updateSamplerate(unsigned int downsampler, bool fastRate);
  72 + void restoreTargets();
  73 + void updateSamplerateLimits();
  74 +
  75 + // Communication with device
  76 + USBDevice *device; ///< The USB device for the oscilloscope
  77 + bool sampling; ///< true, if the oscilloscope is taking samples
  78 +
  79 + QStringList specialTriggerSources; ///< Names of the special trigger sources
  80 +
  81 + DataArray<unsigned char> *command[Hantek::BULK_COUNT]; ///< Pointers to bulk commands, ready to be transmitted
  82 + bool commandPending[Hantek::BULK_COUNT]; ///< true, when the command should be executed
  83 + DataArray<unsigned char> *control[Hantek::CONTROLINDEX_COUNT]; ///< Pointers to control commands
  84 + unsigned char controlCode[Hantek::CONTROLINDEX_COUNT]; ///< Request codes for control commands
  85 + bool controlPending[Hantek::CONTROLINDEX_COUNT]; ///< true, when the control command should be executed
  86 +
  87 + // Device setup
  88 + Hantek::ControlSpecification specification; ///< The specifications of the device
  89 + Hantek::ControlSettings settings; ///< The current settings of the device
  90 +
  91 + // Results
  92 + std::vector<std::vector<double>> samples; ///< Sample data vectors sent to the data analyzer
  93 + unsigned int previousSampleCount; ///< The expected total number of samples at
  94 + ///the last check before sampling started
  95 + QMutex samplesMutex; ///< Mutex for the sample data
  96 +
  97 + // State of the communication thread
  98 + int captureState = Hantek::CAPTURE_WAITING;
  99 + int rollState = 0;
  100 + bool _samplingStarted = false;
  101 + Dso::TriggerMode lastTriggerMode = (Dso::TriggerMode)-1;
  102 + int cycleCounter=0;
  103 + int startCycle=0;
  104 + int cycleTime=0;
  105 +public slots:
  106 + void startSampling();
  107 + void stopSampling();
  108 +
  109 + unsigned int setRecordLength(unsigned int size);
  110 + double setSamplerate(double samplerate = 0.0);
  111 + double setRecordTime(double duration = 0.0);
  112 +
  113 + int setChannelUsed(unsigned int channel, bool used);
  114 + int setCoupling(unsigned int channel, Dso::Coupling coupling);
  115 + double setGain(unsigned int channel, double gain);
  116 + double setOffset(unsigned int channel, double offset);
  117 +
  118 + int setTriggerMode(Dso::TriggerMode mode);
  119 + int setTriggerSource(bool special, unsigned int id);
  120 + double setTriggerLevel(unsigned int channel, double level);
  121 + int setTriggerSlope(Dso::Slope slope);
  122 + double setPretriggerPosition(double position);
  123 + int forceTrigger();
  124 +
  125 +#ifdef DEBUG
  126 + int stringCommand(QString command);
  127 +#endif
  128 +};
... ...
openhantek/src/hantek/models.h 0 โ†’ 100644
  1 +
  2 +// SPDX-License-Identifier: GPL-2.0+
  3 +
  4 +#pragma once
  5 +
  6 +#include <string>
  7 +#include <list>
  8 +
  9 +/// \brief All supported Hantek DSO models.
  10 +enum Model {
  11 + MODEL_UNKNOWN = -1, ///< Unknown model
  12 + MODEL_DSO2090, ///< %Hantek DSO-2090 USB
  13 + MODEL_DSO2150, ///< %Hantek DSO-2150 USB
  14 + MODEL_DSO2250, ///< %Hantek DSO-2250 USB
  15 + MODEL_DSO5200, ///< %Hantek DSO-5200 USB
  16 + MODEL_DSO5200A, ///< %Hantek DSO-5200A USB
  17 + MODEL_DSO6022BE, ///< %Hantek6022BE USB
  18 + MODEL_COUNT
  19 +};
  20 +
  21 +class DSOModel {
  22 +public:
  23 + Model uniqueModelID;
  24 + long vendorID;
  25 + long productID;
  26 + long vendorIDnoFirmware;
  27 + long productIDnoFirmware;
  28 + std::string firmwareToken;
  29 + std::string name;
  30 + DSOModel(Model model, long vendorID, long productID,
  31 + long vendorIDnoFirmware,long productIDnoFirmware,
  32 + std::string firmwareToken,const std::string name)
  33 + : uniqueModelID(model), vendorID(vendorID),productID(productID),
  34 + vendorIDnoFirmware(vendorIDnoFirmware),productIDnoFirmware(productIDnoFirmware),
  35 + firmwareToken(firmwareToken),name(name) { }
  36 +};
  37 +
  38 +static std::list<DSOModel> supportedModels = \
  39 + std::list<DSOModel>({DSOModel(MODEL_DSO2090, 0x04b5, 0x2090, 0x04b4, 0x2090, "dso2090x86", "DSO-2090"),
  40 + DSOModel(MODEL_DSO2090, 0x04b5, 0x2090, 0x04b4, 0x8613, "dso2090x86", "DSO-2090"),
  41 + DSOModel(MODEL_DSO2150, 0x04b5, 0x2150, 0x04b4, 0x2150, "dso2150x86", "DSO-2150"),
  42 + DSOModel(MODEL_DSO2250, 0x04b5, 0x2250, 0x04b4, 0x2250, "dso2250x86", "DSO-2250"),
  43 + DSOModel(MODEL_DSO5200, 0x04b5, 0x5200, 0x04b4, 0x5200, "dso5200x86", "DSO-5200"),
  44 + DSOModel(MODEL_DSO5200A, 0x04b5, 0x520a, 0x04b4, 0x520a, "dso5200ax86","DSO-5200A"),
  45 + DSOModel(MODEL_DSO6022BE,0x04b5, 0x6022, 0x04b4, 0x6022, "dso6022be", "DSO-6022BE"),
  46 + DSOModel(MODEL_DSO6022BE,0x04b5, 0x602a, 0x04b4, 0x602a, "dso6022be", "DSO-6022LE")});
  47 +
... ...
openhantek/src/hantek/control.h renamed to openhantek/src/hantek/stateStructs.h
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file hantek/control.h
5   -/// \brief Declares the Hantek::Control class.
6   -//
7   -// Copyright (C) 2008, 2009 Oleg Khudyakov
8   -// prcoder@potrebitel.ru
9   -// Copyright (C) 2010 - 2012 Oliver Haag
10   -// oliver.haag@gmail.com
11   -//
12   -// This program is free software: you can redistribute it and/or modify it
13   -// under the terms of the GNU General Public License as published by the Free
14   -// Software Foundation, either version 3 of the License, or (at your option)
15   -// any later version.
16   -//
17   -// This program is distributed in the hope that it will be useful, but WITHOUT
18   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20   -// more details.
21   -//
22   -// You should have received a copy of the GNU General Public License along with
23   -// this program. If not, see <http://www.gnu.org/licenses/>.
24   -//
25   -////////////////////////////////////////////////////////////////////////////////
  1 +// SPDX-License-Identifier: GPL-2.0+
26 2  
27   -#ifndef HANTEK_CONTROL_H
28   -#define HANTEK_CONTROL_H
  3 +#pragma once
29 4  
30   -#include <QMutex>
31   -
32   -#include "dsocontrol.h"
33   -#include "hantek/types.h"
34   -#include "helper.h"
35   -
36   -class QTimer;
  5 +#include "definitions.h"
  6 +#include <QList>
37 7  
38 8 namespace Hantek {
39   -class Device;
40 9  
41 10 //////////////////////////////////////////////////////////////////////////////
42 11 /// \enum ControlIndex hantek/control.h
... ... @@ -204,97 +173,4 @@ struct ControlSettings {
204 173 unsigned short int usedChannels; ///< Number of activated channels
205 174 };
206 175  
207   -//////////////////////////////////////////////////////////////////////////////
208   -/// \class Control hantek/control.h
209   -/// \brief The DsoControl abstraction layer for %Hantek USB DSOs.
210   -class Control : public DsoControl {
211   - Q_OBJECT
212   -
213   -public:
214   - Control(QTimer *mainTimer, QObject *parent = 0);
215   - ~Control();
216   -
217   - unsigned int getChannelCount();
218   - QList<unsigned int> *getAvailableRecordLengths();
219   - double getMinSamplerate();
220   - double getMaxSamplerate();
221   -
222   -protected:
223   - void run();
224   - void updateInterval();
225   -
226   - unsigned int calculateTriggerPoint(unsigned int value);
227   - int getCaptureState();
228   - int getSamples(bool process);
229   - double getBestSamplerate(double samplerate, bool fastRate = false,
230   - bool maximum = false, unsigned int *downsampler = 0);
231   - unsigned int getSampleCount(bool *fastRate = 0);
232   - unsigned int updateRecordLength(unsigned int size);
233   - unsigned int updateSamplerate(unsigned int downsampler, bool fastRate);
234   - void restoreTargets();
235   - void updateSamplerateLimits();
236   -
237   - // Communication with device
238   - Device *device; ///< The USB device for the oscilloscope
239   - QTimer *timer; ///< Timer for periodic communication thread
240   -
241   - Helper::DataArray<unsigned char> *command[BULK_COUNT]; ///< Pointers to bulk
242   - ///commands, ready to
243   - ///be transmitted
244   - bool
245   - commandPending[BULK_COUNT]; ///< true, when the command should be executed
246   - Helper::DataArray<unsigned char>
247   - *control[CONTROLINDEX_COUNT]; ///< Pointers to control commands
248   - unsigned char
249   - controlCode[CONTROLINDEX_COUNT]; ///< Request codes for control commands
250   - bool controlPending[CONTROLINDEX_COUNT]; ///< true, when the control command
251   - ///should be executed
252   -
253   - // Device setup
254   - ControlSpecification specification; ///< The specifications of the device
255   - ControlSettings settings; ///< The current settings of the device
256   -
257   - // Results
258   - std::vector<std::vector<double>>
259   - samples; ///< Sample data vectors sent to the data analyzer
260   - unsigned int previousSampleCount; ///< The expected total number of samples at
261   - ///the last check before sampling started
262   - QMutex samplesMutex; ///< Mutex for the sample data
263   -
264   - // State of the communication thread
265   - int captureState;
266   - int rollState;
267   - bool samplingStarted;
268   - Dso::TriggerMode lastTriggerMode;
269   - int cycleCounter;
270   - int startCycle;
271   -
272   -public slots:
273   - virtual void connectDevice();
274   -
275   - unsigned int setRecordLength(unsigned int size);
276   - double setSamplerate(double samplerate = 0.0);
277   - double setRecordTime(double duration = 0.0);
278   -
279   - int setChannelUsed(unsigned int channel, bool used);
280   - int setCoupling(unsigned int channel, Dso::Coupling coupling);
281   - double setGain(unsigned int channel, double gain);
282   - double setOffset(unsigned int channel, double offset);
283   -
284   - int setTriggerMode(Dso::TriggerMode mode);
285   - int setTriggerSource(bool special, unsigned int id);
286   - double setTriggerLevel(unsigned int channel, double level);
287   - int setTriggerSlope(Dso::Slope slope);
288   - double setPretriggerPosition(double position);
289   - int forceTrigger();
290   -
291   -#ifdef DEBUG
292   - int stringCommand(QString command);
293   -#endif
294   -
295   -protected slots:
296   - void handler();
297   -};
298 176 }
299   -
300   -#endif
... ...
openhantek/src/hantek/usb/ezusb.cpp 0 โ†’ 100644
  1 +/*
  2 + * Copyright ยฉ 2001 Stephen Williams (steve@icarus.com)
  3 + * Copyright ยฉ 2001-2002 David Brownell (dbrownell@users.sourceforge.net)
  4 + * Copyright ยฉ 2008 Roger Williams (rawqux@users.sourceforge.net)
  5 + * Copyright ยฉ 2012 Pete Batard (pete@akeo.ie)
  6 + * Copyright ยฉ 2013 Federico Manzan (f.manzan@gmail.com)
  7 + *
  8 + * This source code is free software; you can redistribute it
  9 + * and/or modify it in source code form under the terms of the GNU
  10 + * General Public License as published by the Free Software
  11 + * Foundation; either version 2 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,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  22 + */
  23 +#include <stdio.h>
  24 +#include <errno.h>
  25 +#include <stdlib.h>
  26 +#include <string.h>
  27 +#include <stdint.h>
  28 +
  29 +#include <libusb-1.0/libusb.h>
  30 +
  31 +#include "ezusb.h"
  32 +
  33 +#define logerror(...) fprintf(stderr, __VA_ARGS__)
  34 +
  35 +/*
  36 + * This file contains functions for uploading firmware into Cypress
  37 + * EZ-USB microcontrollers. These chips use control endpoint 0 and vendor
  38 + * specific commands to support writing into the on-chip SRAM. They also
  39 + * support writing into the CPUCS register, which is how we reset the
  40 + * processor after loading firmware (including the reset vector).
  41 + *
  42 + * These Cypress devices are 8-bit 8051 based microcontrollers with
  43 + * special support for USB I/O. They come in several packages, and
  44 + * some can be set up with external memory when device costs allow.
  45 + * Note that the design was originally by AnchorChips, so you may find
  46 + * references to that vendor (which was later merged into Cypress).
  47 + * The Cypress FX parts are largely compatible with the Anchorhip ones.
  48 + */
  49 +
  50 +int verbose = 1;
  51 +
  52 +/*
  53 + * return true if [addr,addr+len] includes external RAM
  54 + * for Anchorchips EZ-USB or Cypress EZ-USB FX
  55 + */
  56 +static bool fx_is_external(uint32_t addr, size_t len)
  57 +{
  58 + /* with 8KB RAM, 0x0000-0x1b3f can be written
  59 + * we can't tell if it's a 4KB device here
  60 + */
  61 + if (addr <= 0x1b3f)
  62 + return ((addr + len) > 0x1b40);
  63 +
  64 + /* there may be more RAM; unclear if we can write it.
  65 + * some bulk buffers may be unused, 0x1b3f-0x1f3f
  66 + * firmware can set ISODISAB for 2KB at 0x2000-0x27ff
  67 + */
  68 + return true;
  69 +}
  70 +
  71 +/*
  72 + * return true if [addr,addr+len] includes external RAM
  73 + * for Cypress EZ-USB FX2
  74 + */
  75 +static bool fx2_is_external(uint32_t addr, size_t len)
  76 +{
  77 + /* 1st 8KB for data/code, 0x0000-0x1fff */
  78 + if (addr <= 0x1fff)
  79 + return ((addr + len) > 0x2000);
  80 +
  81 + /* and 512 for data, 0xe000-0xe1ff */
  82 + else if (addr >= 0xe000 && addr <= 0xe1ff)
  83 + return ((addr + len) > 0xe200);
  84 +
  85 + /* otherwise, it's certainly external */
  86 + else
  87 + return true;
  88 +}
  89 +
  90 +/*
  91 + * return true if [addr,addr+len] includes external RAM
  92 + * for Cypress EZ-USB FX2LP
  93 + */
  94 +static bool fx2lp_is_external(uint32_t addr, size_t len)
  95 +{
  96 + /* 1st 16KB for data/code, 0x0000-0x3fff */
  97 + if (addr <= 0x3fff)
  98 + return ((addr + len) > 0x4000);
  99 +
  100 + /* and 512 for data, 0xe000-0xe1ff */
  101 + else if (addr >= 0xe000 && addr <= 0xe1ff)
  102 + return ((addr + len) > 0xe200);
  103 +
  104 + /* otherwise, it's certainly external */
  105 + else
  106 + return true;
  107 +}
  108 +
  109 +
  110 +/*****************************************************************************/
  111 +
  112 +/*
  113 + * These are the requests (bRequest) that the bootstrap loader is expected
  114 + * to recognize. The codes are reserved by Cypress, and these values match
  115 + * what EZ-USB hardware, or "Vend_Ax" firmware (2nd stage loader) uses.
  116 + * Cypress' "a3load" is nice because it supports both FX and FX2, although
  117 + * it doesn't have the EEPROM support (subset of "Vend_Ax").
  118 + */
  119 +#define RW_INTERNAL 0xA0 /* hardware implements this one */
  120 +#define RW_MEMORY 0xA3
  121 +
  122 +/*
  123 + * Issues the specified vendor-specific write request.
  124 + */
  125 +static int ezusb_write(libusb_device_handle *device, const char *label,
  126 + uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
  127 +{
  128 + int status;
  129 +
  130 + if (verbose > 1)
  131 + logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
  132 + status = libusb_control_transfer(device,
  133 + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
  134 + opcode, addr & 0xFFFF, addr >> 16,
  135 + (unsigned char*)data, (uint16_t)len, 1000);
  136 + if (status != (signed)len) {
  137 + if (status < 0)
  138 + logerror("%s: %s\n", label, libusb_error_name(status));
  139 + else
  140 + logerror("%s ==> %d\n", label, status);
  141 + }
  142 + return (status < 0) ? -EIO : 0;
  143 +}
  144 +
  145 +/*
  146 + * Issues the specified vendor-specific read request.
  147 + */
  148 +static int ezusb_read(libusb_device_handle *device, const char *label,
  149 + uint8_t opcode, uint32_t addr, const unsigned char *data, size_t len)
  150 +{
  151 + int status;
  152 +
  153 + if (verbose > 1)
  154 + logerror("%s, addr 0x%08x len %4u (0x%04x)\n", label, addr, (unsigned)len, (unsigned)len);
  155 + status = libusb_control_transfer(device,
  156 + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
  157 + opcode, addr & 0xFFFF, addr >> 16,
  158 + (unsigned char*)data, (uint16_t)len, 1000);
  159 + if (status != (signed)len) {
  160 + if (status < 0)
  161 + logerror("%s: %s\n", label, libusb_error_name(status));
  162 + else
  163 + logerror("%s ==> %d\n", label, status);
  164 + }
  165 + return (status < 0) ? -EIO : 0;
  166 +}
  167 +
  168 +/*
  169 + * Modifies the CPUCS register to stop or reset the CPU.
  170 + * Returns false on error.
  171 + */
  172 +static bool ezusb_cpucs(libusb_device_handle *device, uint32_t addr, bool doRun)
  173 +{
  174 + int status;
  175 + uint8_t data = doRun ? 0x00 : 0x01;
  176 +
  177 + if (verbose)
  178 + logerror("%s\n", data ? "stop CPU" : "reset CPU");
  179 + status = libusb_control_transfer(device,
  180 + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
  181 + RW_INTERNAL, addr & 0xFFFF, addr >> 16,
  182 + &data, 1, 1000);
  183 + if ((status != 1) &&
  184 + /* We may get an I/O error from libusb as the device disappears */
  185 + ((!doRun) || (status != LIBUSB_ERROR_IO)))
  186 + {
  187 + const char *mesg = "can't modify CPUCS";
  188 + if (status < 0)
  189 + logerror("%s: %s\n", mesg, libusb_error_name(status));
  190 + else
  191 + logerror("%s\n", mesg);
  192 + return false;
  193 + } else
  194 + return true;
  195 +}
  196 +
  197 +/*
  198 + * Send an FX3 jumpt to address command
  199 + * Returns false on error.
  200 + */
  201 +static bool ezusb_fx3_jump(libusb_device_handle *device, uint32_t addr)
  202 +{
  203 + int status;
  204 +
  205 + if (verbose)
  206 + logerror("transfer execution to Program Entry at 0x%08x\n", addr);
  207 + status = libusb_control_transfer(device,
  208 + LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE,
  209 + RW_INTERNAL, addr & 0xFFFF, addr >> 16,
  210 + NULL, 0, 1000);
  211 + /* We may get an I/O error from libusb as the device disappears */
  212 + if ((status != 0) && (status != LIBUSB_ERROR_IO))
  213 + {
  214 + const char *mesg = "failed to send jump command";
  215 + if (status < 0)
  216 + logerror("%s: %s\n", mesg, libusb_error_name(status));
  217 + else
  218 + logerror("%s\n", mesg);
  219 + return false;
  220 + } else
  221 + return true;
  222 +}
  223 +
  224 +/*****************************************************************************/
  225 +
  226 +/*
  227 + * Parse an Intel HEX image file and invoke the poke() function on the
  228 + * various segments to implement policies such as writing to RAM (with
  229 + * a one or two stage loader setup, depending on the firmware) or to
  230 + * EEPROM (two stages required).
  231 + *
  232 + * image - the hex image file
  233 + * context - for use by poke()
  234 + * is_external - if non-null, used to check which segments go into
  235 + * external memory (writable only by software loader)
  236 + * poke - called with each memory segment; errors indicated
  237 + * by returning negative values.
  238 + *
  239 + * Caller is responsible for halting CPU as needed, such as when
  240 + * overwriting a second stage loader.
  241 + */
  242 +static int parse_ihex(FILE *image, void *context,
  243 + bool (*is_external)(uint32_t addr, size_t len),
  244 + int (*poke) (void *context, uint32_t addr, bool external,
  245 + const unsigned char *data, size_t len))
  246 +{
  247 + unsigned char data[1023];
  248 + uint32_t data_addr = 0;
  249 + size_t data_len = 0;
  250 + int rc;
  251 + int first_line = 1;
  252 + bool external = false;
  253 +
  254 + /* Read the input file as an IHEX file, and report the memory segments
  255 + * as we go. Each line holds a max of 16 bytes, but uploading is
  256 + * faster (and EEPROM space smaller) if we merge those lines into larger
  257 + * chunks. Most hex files keep memory segments together, which makes
  258 + * such merging all but free. (But it may still be worth sorting the
  259 + * hex files to make up for undesirable behavior from tools.)
  260 + *
  261 + * Note that EEPROM segments max out at 1023 bytes; the upload protocol
  262 + * allows segments of up to 64 KBytes (more than a loader could handle).
  263 + */
  264 + for (;;) {
  265 + char buf[512], *cp;
  266 + char tmp, type;
  267 + size_t len;
  268 + unsigned idx, off;
  269 +
  270 + cp = fgets(buf, sizeof(buf), image);
  271 + if (cp == NULL) {
  272 + logerror("EOF without EOF record!\n");
  273 + break;
  274 + }
  275 +
  276 + /* EXTENSION: "# comment-till-end-of-line", for copyrights etc */
  277 + if (buf[0] == '#')
  278 + continue;
  279 +
  280 + if (buf[0] != ':') {
  281 + logerror("not an ihex record: %s", buf);
  282 + return -2;
  283 + }
  284 +
  285 + /* ignore any newline */
  286 + cp = strchr(buf, '\n');
  287 + if (cp)
  288 + *cp = 0;
  289 +
  290 + if (verbose >= 3)
  291 + logerror("** LINE: %s\n", buf);
  292 +
  293 + /* Read the length field (up to 16 bytes) */
  294 + tmp = buf[3];
  295 + buf[3] = 0;
  296 + len = strtoul(buf+1, NULL, 16);
  297 + buf[3] = tmp;
  298 +
  299 + /* Read the target offset (address up to 64KB) */
  300 + tmp = buf[7];
  301 + buf[7] = 0;
  302 + off = (int)strtoul(buf+3, NULL, 16);
  303 + buf[7] = tmp;
  304 +
  305 + /* Initialize data_addr */
  306 + if (first_line) {
  307 + data_addr = off;
  308 + first_line = 0;
  309 + }
  310 +
  311 + /* Read the record type */
  312 + tmp = buf[9];
  313 + buf[9] = 0;
  314 + type = (char)strtoul(buf+7, NULL, 16);
  315 + buf[9] = tmp;
  316 +
  317 + /* If this is an EOF record, then make it so. */
  318 + if (type == 1) {
  319 + if (verbose >= 2)
  320 + logerror("EOF on hexfile\n");
  321 + break;
  322 + }
  323 +
  324 + if (type != 0) {
  325 + logerror("unsupported record type: %u\n", type);
  326 + return -3;
  327 + }
  328 +
  329 + if ((len * 2) + 11 > strlen(buf)) {
  330 + logerror("record too short?\n");
  331 + return -4;
  332 + }
  333 +
  334 + /* FIXME check for _physically_ contiguous not just virtually
  335 + * e.g. on FX2 0x1f00-0x2100 includes both on-chip and external
  336 + * memory so it's not really contiguous */
  337 +
  338 + /* flush the saved data if it's not contiguous,
  339 + * or when we've buffered as much as we can.
  340 + */
  341 + if (data_len != 0
  342 + && (off != (data_addr + data_len)
  343 + /* || !merge */
  344 + || (data_len + len) > sizeof(data))) {
  345 + if (is_external)
  346 + external = is_external(data_addr, data_len);
  347 + rc = poke(context, data_addr, external, data, data_len);
  348 + if (rc < 0)
  349 + return -1;
  350 + data_addr = off;
  351 + data_len = 0;
  352 + }
  353 +
  354 + /* append to saved data, flush later */
  355 + for (idx = 0, cp = buf+9 ; idx < len ; idx += 1, cp += 2) {
  356 + tmp = cp[2];
  357 + cp[2] = 0;
  358 + data[data_len + idx] = (uint8_t)strtoul(cp, NULL, 16);
  359 + cp[2] = tmp;
  360 + }
  361 + data_len += len;
  362 + }
  363 +
  364 +
  365 + /* flush any data remaining */
  366 + if (data_len != 0) {
  367 + if (is_external)
  368 + external = is_external(data_addr, data_len);
  369 + rc = poke(context, data_addr, external, data, data_len);
  370 + if (rc < 0)
  371 + return -1;
  372 + }
  373 + return 0;
  374 +}
  375 +
  376 +/*
  377 + * Parse a binary image file and write it as is to the target.
  378 + * Applies to Cypress BIX images for RAM or Cypress IIC images
  379 + * for EEPROM.
  380 + *
  381 + * image - the BIX image file
  382 + * context - for use by poke()
  383 + * is_external - if non-null, used to check which segments go into
  384 + * external memory (writable only by software loader)
  385 + * poke - called with each memory segment; errors indicated
  386 + * by returning negative values.
  387 + *
  388 + * Caller is responsible for halting CPU as needed, such as when
  389 + * overwriting a second stage loader.
  390 + */
  391 +static int parse_bin(FILE *image, void *context,
  392 + bool (*is_external)(uint32_t addr, size_t len), int (*poke)(void *context,
  393 + uint32_t addr, bool external, const unsigned char *data, size_t len))
  394 +{
  395 + unsigned char data[4096];
  396 + uint32_t data_addr = 0;
  397 + size_t data_len = 0;
  398 + int rc;
  399 + bool external = false;
  400 +
  401 + for (;;) {
  402 + data_len = fread(data, 1, 4096, image);
  403 + if (data_len == 0)
  404 + break;
  405 + if (is_external)
  406 + external = is_external(data_addr, data_len);
  407 + rc = poke(context, data_addr, external, data, data_len);
  408 + if (rc < 0)
  409 + return -1;
  410 + data_addr += (uint32_t)data_len;
  411 + }
  412 + return feof(image)?0:-1;
  413 +}
  414 +
  415 +/*
  416 + * Parse a Cypress IIC image file and invoke the poke() function on the
  417 + * various segments for writing to RAM
  418 + *
  419 + * image - the IIC image file
  420 + * context - for use by poke()
  421 + * is_external - if non-null, used to check which segments go into
  422 + * external memory (writable only by software loader)
  423 + * poke - called with each memory segment; errors indicated
  424 + * by returning negative values.
  425 + *
  426 + * Caller is responsible for halting CPU as needed, such as when
  427 + * overwriting a second stage loader.
  428 + */
  429 +static int parse_iic(FILE *image, void *context,
  430 + bool (*is_external)(uint32_t addr, size_t len),
  431 + int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
  432 +{
  433 + unsigned char data[4096];
  434 + uint32_t data_addr = 0;
  435 + size_t data_len = 0, read_len;
  436 + uint8_t block_header[4];
  437 + int rc;
  438 + bool external = false;
  439 + long file_size, initial_pos;
  440 +
  441 + initial_pos = ftell(image);
  442 + if (initial_pos < 0)
  443 + return -1;
  444 +
  445 + if (fseek(image, 0L, SEEK_END) != 0)
  446 + return -1;
  447 + file_size = ftell(image);
  448 + if (fseek(image, initial_pos, SEEK_SET) != 0)
  449 + return -1;
  450 + for (;;) {
  451 + /* Ignore the trailing reset IIC data (5 bytes) */
  452 + if (ftell(image) >= (file_size - 5))
  453 + break;
  454 + if (fread(&block_header, 1, sizeof(block_header), image) != 4) {
  455 + logerror("unable to read IIC block header\n");
  456 + return -1;
  457 + }
  458 + data_len = (block_header[0] << 8) + block_header[1];
  459 + data_addr = (block_header[2] << 8) + block_header[3];
  460 + if (data_len > sizeof(data)) {
  461 + /* If this is ever reported as an error, switch to using malloc/realloc */
  462 + logerror("IIC data block too small - please report this error to libusb.info\n");
  463 + return -1;
  464 + }
  465 + read_len = fread(data, 1, data_len, image);
  466 + if (read_len != data_len) {
  467 + logerror("read error\n");
  468 + return -1;
  469 + }
  470 + if (is_external)
  471 + external = is_external(data_addr, data_len);
  472 + rc = poke(context, data_addr, external, data, data_len);
  473 + if (rc < 0)
  474 + return -1;
  475 + }
  476 + return 0;
  477 +}
  478 +
  479 +/* the parse call will be selected according to the image type */
  480 +static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len),
  481 + int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len))
  482 + = { parse_ihex, parse_iic, parse_bin };
  483 +
  484 +/*****************************************************************************/
  485 +
  486 +/*
  487 + * For writing to RAM using a first (hardware) or second (software)
  488 + * stage loader and 0xA0 or 0xA3 vendor requests
  489 + */
  490 +typedef enum {
  491 + _undef = 0,
  492 + internal_only, /* hardware first-stage loader */
  493 + skip_internal, /* first phase, second-stage loader */
  494 + skip_external /* second phase, second-stage loader */
  495 +} ram_mode;
  496 +
  497 +struct ram_poke_context {
  498 + libusb_device_handle *device;
  499 + ram_mode mode;
  500 + size_t total, count;
  501 +};
  502 +
  503 +#define RETRY_LIMIT 5
  504 +
  505 +static int ram_poke(void *context, uint32_t addr, bool external,
  506 + const unsigned char *data, size_t len)
  507 +{
  508 + struct ram_poke_context *ctx = (struct ram_poke_context*)context;
  509 + int rc;
  510 + unsigned retry = 0;
  511 +
  512 + switch (ctx->mode) {
  513 + case internal_only: /* CPU should be stopped */
  514 + if (external) {
  515 + logerror("can't write %u bytes external memory at 0x%08x\n",
  516 + (unsigned)len, addr);
  517 + return -EINVAL;
  518 + }
  519 + break;
  520 + case skip_internal: /* CPU must be running */
  521 + if (!external) {
  522 + if (verbose >= 2) {
  523 + logerror("SKIP on-chip RAM, %u bytes at 0x%08x\n",
  524 + (unsigned)len, addr);
  525 + }
  526 + return 0;
  527 + }
  528 + break;
  529 + case skip_external: /* CPU should be stopped */
  530 + if (external) {
  531 + if (verbose >= 2) {
  532 + logerror("SKIP external RAM, %u bytes at 0x%08x\n",
  533 + (unsigned)len, addr);
  534 + }
  535 + return 0;
  536 + }
  537 + break;
  538 + case _undef:
  539 + default:
  540 + logerror("bug\n");
  541 + return -EDOM;
  542 + }
  543 +
  544 + ctx->total += len;
  545 + ctx->count++;
  546 +
  547 + /* Retry this till we get a real error. Control messages are not
  548 + * NAKed (just dropped) so time out means is a real problem.
  549 + */
  550 + while ((rc = ezusb_write(ctx->device,
  551 + external ? "write external" : "write on-chip",
  552 + external ? RW_MEMORY : RW_INTERNAL,
  553 + addr, data, len)) < 0
  554 + && retry < RETRY_LIMIT) {
  555 + if (rc != LIBUSB_ERROR_TIMEOUT)
  556 + break;
  557 + retry += 1;
  558 + }
  559 + return rc;
  560 +}
  561 +
  562 +/*
  563 + * Load a Cypress Image file into target RAM.
  564 + * See http://www.cypress.com/?docID=41351 (AN76405 PDF) for more info.
  565 + */
  566 +static int fx3_load_ram(libusb_device_handle *device, const char *path)
  567 +{
  568 + uint32_t dCheckSum, dExpectedCheckSum, dAddress, i, dLen, dLength;
  569 + uint32_t* dImageBuf;
  570 + unsigned char *bBuf, hBuf[4], blBuf[4], rBuf[4096];
  571 + FILE *image;
  572 + int ret = 0;
  573 +
  574 + image = fopen(path, "rb");
  575 + if (image == NULL) {
  576 + logerror("unable to open '%s' for input\n", path);
  577 + return -2;
  578 + } else if (verbose)
  579 + logerror("open firmware image %s for RAM upload\n", path);
  580 +
  581 + // Read header
  582 + if (fread(hBuf, sizeof(char), sizeof(hBuf), image) != sizeof(hBuf)) {
  583 + logerror("could not read image header");
  584 + ret = -3;
  585 + goto exit;
  586 + }
  587 +
  588 + // check "CY" signature byte and format
  589 + if ((hBuf[0] != 'C') || (hBuf[1] != 'Y')) {
  590 + logerror("image doesn't have a CYpress signature\n");
  591 + ret = -3;
  592 + goto exit;
  593 + }
  594 +
  595 + // Check bImageType
  596 + switch(hBuf[3]) {
  597 + case 0xB0:
  598 + if (verbose)
  599 + logerror("normal FW binary %s image with checksum\n", (hBuf[2]&0x01)?"data":"executable");
  600 + break;
  601 + case 0xB1:
  602 + logerror("security binary image is not currently supported\n");
  603 + ret = -3;
  604 + goto exit;
  605 + case 0xB2:
  606 + logerror("VID:PID image is not currently supported\n");
  607 + ret = -3;
  608 + goto exit;
  609 + default:
  610 + logerror("invalid image type 0x%02X\n", hBuf[3]);
  611 + ret = -3;
  612 + goto exit;
  613 + }
  614 +
  615 + // Read the bootloader version
  616 + if (verbose) {
  617 + if ((ezusb_read(device, "read bootloader version", RW_INTERNAL, 0xFFFF0020, blBuf, 4) < 0)) {
  618 + logerror("Could not read bootloader version\n");
  619 + ret = -8;
  620 + goto exit;
  621 + }
  622 + logerror("FX3 bootloader version: 0x%02X%02X%02X%02X\n", blBuf[3], blBuf[2], blBuf[1], blBuf[0]);
  623 + }
  624 +
  625 + dCheckSum = 0;
  626 + if (verbose)
  627 + logerror("writing image...\n");
  628 + while (1) {
  629 + if ((fread(&dLength, sizeof(uint32_t), 1, image) != 1) || // read dLength
  630 + (fread(&dAddress, sizeof(uint32_t), 1, image) != 1)) { // read dAddress
  631 + logerror("could not read image");
  632 + ret = -3;
  633 + goto exit;
  634 + }
  635 + if (dLength == 0)
  636 + break; // done
  637 +
  638 + // coverity[tainted_data]
  639 + dImageBuf = (uint32_t*)calloc(dLength, sizeof(uint32_t));
  640 + if (dImageBuf == NULL) {
  641 + logerror("could not allocate buffer for image chunk\n");
  642 + ret = -4;
  643 + goto exit;
  644 + }
  645 +
  646 + // read sections
  647 + if (fread(dImageBuf, sizeof(uint32_t), dLength, image) != dLength) {
  648 + logerror("could not read image");
  649 + free(dImageBuf);
  650 + ret = -3;
  651 + goto exit;
  652 + }
  653 + for (i = 0; i < dLength; i++)
  654 + dCheckSum += dImageBuf[i];
  655 + dLength <<= 2; // convert to Byte length
  656 + bBuf = (unsigned char*) dImageBuf;
  657 +
  658 + while (dLength > 0) {
  659 + dLen = 4096; // 4K max
  660 + if (dLen > dLength)
  661 + dLen = dLength;
  662 + if ((ezusb_write(device, "write firmware", RW_INTERNAL, dAddress, bBuf, dLen) < 0) ||
  663 + (ezusb_read(device, "read firmware", RW_INTERNAL, dAddress, rBuf, dLen) < 0)) {
  664 + logerror("R/W error\n");
  665 + free(dImageBuf);
  666 + ret = -5;
  667 + goto exit;
  668 + }
  669 + // Verify data: rBuf with bBuf
  670 + for (i = 0; i < dLen; i++) {
  671 + if (rBuf[i] != bBuf[i]) {
  672 + logerror("verify error");
  673 + free(dImageBuf);
  674 + ret = -6;
  675 + goto exit;
  676 + }
  677 + }
  678 +
  679 + dLength -= dLen;
  680 + bBuf += dLen;
  681 + dAddress += dLen;
  682 + }
  683 + free(dImageBuf);
  684 + }
  685 +
  686 + // read pre-computed checksum data
  687 + if ((fread(&dExpectedCheckSum, sizeof(uint32_t), 1, image) != 1) ||
  688 + (dCheckSum != dExpectedCheckSum)) {
  689 + logerror("checksum error\n");
  690 + ret = -7;
  691 + goto exit;
  692 + }
  693 +
  694 + // transfer execution to Program Entry
  695 + if (!ezusb_fx3_jump(device, dAddress)) {
  696 + ret = -6;
  697 + }
  698 +
  699 +exit:
  700 + fclose(image);
  701 + return ret;
  702 +}
  703 +
  704 +/*
  705 + * Load a firmware file into target RAM. device is the open libusb
  706 + * device, and the path is the name of the source file. Open the file,
  707 + * parse the bytes, and write them in one or two phases.
  708 + *
  709 + * If stage == 0, this uses the first stage loader, built into EZ-USB
  710 + * hardware but limited to writing on-chip memory or CPUCS. Everything
  711 + * is written during one stage, unless there's an error such as the image
  712 + * holding data that needs to be written to external memory.
  713 + *
  714 + * Otherwise, things are written in two stages. First the external
  715 + * memory is written, expecting a second stage loader to have already
  716 + * been loaded. Then file is re-parsed and on-chip memory is written.
  717 + */
  718 +int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage)
  719 +{
  720 + FILE *image;
  721 + uint32_t cpucs_addr;
  722 + bool (*is_external)(uint32_t off, size_t len);
  723 + struct ram_poke_context ctx;
  724 + int status;
  725 + uint8_t iic_header[8] = { 0 };
  726 + int ret = 0;
  727 +
  728 + if (fx_type == FX_TYPE_FX3)
  729 + return fx3_load_ram(device, path);
  730 +
  731 + image = fopen(path, "rb");
  732 + if (image == NULL) {
  733 + logerror("%s: unable to open for input.\n", path);
  734 + return -2;
  735 + } else if (verbose > 1)
  736 + logerror("open firmware image %s for RAM upload\n", path);
  737 +
  738 + if (img_type == IMG_TYPE_IIC) {
  739 + if ( (fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header))
  740 + || (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2))
  741 + || ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2))
  742 + || ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6)) ) {
  743 + logerror("IIC image does not contain executable code - cannot load to RAM.\n");
  744 + ret = -1;
  745 + goto exit;
  746 + }
  747 + }
  748 +
  749 + /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */
  750 + switch(fx_type) {
  751 + case FX_TYPE_FX2LP:
  752 + cpucs_addr = 0xe600;
  753 + is_external = fx2lp_is_external;
  754 + break;
  755 + case FX_TYPE_FX2:
  756 + cpucs_addr = 0xe600;
  757 + is_external = fx2_is_external;
  758 + break;
  759 + default:
  760 + cpucs_addr = 0x7f92;
  761 + is_external = fx_is_external;
  762 + break;
  763 + }
  764 +
  765 + /* use only first stage loader? */
  766 + if (stage == 0) {
  767 + ctx.mode = internal_only;
  768 +
  769 + /* if required, halt the CPU while we overwrite its code/data */
  770 + if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
  771 + {
  772 + ret = -1;
  773 + goto exit;
  774 + }
  775 +
  776 + /* 2nd stage, first part? loader was already uploaded */
  777 + } else {
  778 + ctx.mode = skip_internal;
  779 +
  780 + /* let CPU run; overwrite the 2nd stage loader later */
  781 + if (verbose)
  782 + logerror("2nd stage: write external memory\n");
  783 + }
  784 +
  785 + /* scan the image, first (maybe only) time */
  786 + ctx.device = device;
  787 + ctx.total = ctx.count = 0;
  788 + status = parse[img_type](image, &ctx, is_external, ram_poke);
  789 + if (status < 0) {
  790 + logerror("unable to upload %s\n", path);
  791 + ret = status;
  792 + goto exit;
  793 + }
  794 +
  795 + /* second part of 2nd stage: rescan */
  796 + // TODO: what should we do for non HEX images there?
  797 + if (stage) {
  798 + ctx.mode = skip_external;
  799 +
  800 + /* if needed, halt the CPU while we overwrite the 1st stage loader */
  801 + if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, false))
  802 + {
  803 + ret = -1;
  804 + goto exit;
  805 + }
  806 +
  807 + /* at least write the interrupt vectors (at 0x0000) for reset! */
  808 + rewind(image);
  809 + if (verbose)
  810 + logerror("2nd stage: write on-chip memory\n");
  811 + status = parse_ihex(image, &ctx, is_external, ram_poke);
  812 + if (status < 0) {
  813 + logerror("unable to completely upload %s\n", path);
  814 + ret = status;
  815 + goto exit;
  816 + }
  817 + }
  818 +
  819 + if (verbose && (ctx.count != 0)) {
  820 + logerror("... WROTE: %d bytes, %d segments, avg %d\n",
  821 + (int)ctx.total, (int)ctx.count, (int)(ctx.total/ctx.count));
  822 + }
  823 +
  824 + /* if required, reset the CPU so it runs what we just uploaded */
  825 + if (cpucs_addr && !ezusb_cpucs(device, cpucs_addr, true))
  826 + ret = -1;
  827 +
  828 +exit:
  829 + fclose(image);
  830 + return ret;
  831 +}
... ...
openhantek/src/hantek/usb/ezusb.h 0 โ†’ 100644
  1 +#ifndef __ezusb_H
  2 +#define __ezusb_H
  3 +/*
  4 + * Copyright ยฉ 2001 Stephen Williams (steve@icarus.com)
  5 + * Copyright ยฉ 2002 David Brownell (dbrownell@users.sourceforge.net)
  6 + * Copyright ยฉ 2013 Federico Manzan (f.manzan@gmail.com)
  7 + *
  8 + * This source code is free software; you can redistribute it
  9 + * and/or modify it in source code form under the terms of the GNU
  10 + * General Public License as published by the Free Software
  11 + * Foundation; either version 2 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,
  15 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17 + * GNU General Public License for more details.
  18 + *
  19 + * You should have received a copy of the GNU General Public License
  20 + * along with this program; if not, write to the Free Software
  21 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
  22 + */
  23 +#if !defined(_MSC_VER)
  24 +#include <stdbool.h>
  25 +#else
  26 +#define __attribute__(x)
  27 +#if !defined(bool)
  28 +#define bool int
  29 +#endif
  30 +#if !defined(true)
  31 +#define true (1 == 1)
  32 +#endif
  33 +#if !defined(false)
  34 +#define false (!true)
  35 +#endif
  36 +#if defined(_PREFAST_)
  37 +#pragma warning(disable:28193)
  38 +#endif
  39 +#endif
  40 +
  41 +#define FX_TYPE_UNDEFINED -1
  42 +#define FX_TYPE_AN21 0 /* Original AnchorChips parts */
  43 +#define FX_TYPE_FX1 1 /* Updated Cypress versions */
  44 +#define FX_TYPE_FX2 2 /* USB 2.0 versions */
  45 +#define FX_TYPE_FX2LP 3 /* Updated FX2 */
  46 +#define FX_TYPE_FX3 4 /* USB 3.0 versions */
  47 +#define FX_TYPE_MAX 5
  48 +#define FX_TYPE_NAMES { "an21", "fx", "fx2", "fx2lp", "fx3" }
  49 +
  50 +#define IMG_TYPE_UNDEFINED -1
  51 +#define IMG_TYPE_HEX 0 /* Intel HEX */
  52 +#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */
  53 +#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */
  54 +#define IMG_TYPE_IMG 3 /* Cypress IMG format */
  55 +#define IMG_TYPE_MAX 4
  56 +#define IMG_TYPE_NAMES { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" }
  57 +
  58 +
  59 +/*
  60 + * Automatically identified devices (VID, PID, type, designation).
  61 + * TODO: Could use some validation. Also where's the FX2?
  62 + */
  63 +typedef struct {
  64 + uint16_t vid;
  65 + uint16_t pid;
  66 + int type;
  67 + const char* designation;
  68 +} fx_known_device;
  69 +
  70 +#define FX_KNOWN_DEVICES { \
  71 + { 0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)" },\
  72 + { 0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)" },\
  73 + { 0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)" },\
  74 + { 0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)" },\
  75 + { 0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)" },\
  76 + { 0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)" },\
  77 + { 0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)" },\
  78 + { 0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)" },\
  79 + { 0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)" },\
  80 + { 0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1" },\
  81 + { 0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)" }, \
  82 + { 0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3" },\
  83 +}
  84 +
  85 +/*
  86 + * This function uploads the firmware from the given file into RAM.
  87 + * Stage == 0 means this is a single stage load (or the first of
  88 + * two stages). Otherwise it's the second of two stages; the
  89 + * caller having preloaded the second stage loader.
  90 + *
  91 + * The target processor is reset at the end of this upload.
  92 + */
  93 +extern int ezusb_load_ram(libusb_device_handle *device,
  94 + const char *path, int fx_type, int img_type, int stage);
  95 +
  96 +/*
  97 + * This function uploads the firmware from the given file into EEPROM.
  98 + * This uses the right CPUCS address to terminate the EEPROM load with
  99 + * a reset command where FX parts behave differently than FX2 ones.
  100 + * The configuration byte is as provided here (zero for an21xx parts)
  101 + * and the EEPROM type is set so that the microcontroller will boot
  102 + * from it.
  103 + *
  104 + * The caller must have preloaded a second stage loader that knows
  105 + * how to respond to the EEPROM write request.
  106 + */
  107 +extern int ezusb_load_eeprom(libusb_device_handle *device,
  108 + const char *path, int fx_type, int img_type, int config);
  109 +
  110 +/* Verbosity level (default 1). Can be increased or decreased with options v/q */
  111 +extern int verbose;
  112 +
  113 +#endif
... ...
openhantek/src/hantek/usb/finddevices.cpp 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#include <QList>
  4 +#include <QCoreApplication>
  5 +#include <QDebug>
  6 +#include <QTemporaryFile>
  7 +
  8 +#include "finddevices.h"
  9 +#include "utils/printutils.h"
  10 +#include "ezusb.h"
  11 +
  12 +FindDevices::FindDevices(libusb_context *context) : context(context) { }
  13 +
  14 +// Iterate through all usb devices
  15 +std::list<std::unique_ptr<USBDevice>> FindDevices::findDevices() {
  16 + std::list<std::unique_ptr<USBDevice>> devices;
  17 +
  18 + libusb_device **deviceList;
  19 + ssize_t deviceCount = libusb_get_device_list(context, &deviceList);
  20 + if (deviceCount < 0){
  21 + errorMessage = QCoreApplication::translate("","Failed to get device list");
  22 + return devices;
  23 + }
  24 +
  25 + noAccessDevices = false;
  26 + int noAccessDeviceCount = 0;
  27 +
  28 + for (ssize_t deviceIterator = 0; deviceIterator < deviceCount; ++deviceIterator) {
  29 + libusb_device* device = deviceList[deviceIterator];
  30 + // Get device descriptor
  31 + struct libusb_device_descriptor descriptor;
  32 + if (libusb_get_device_descriptor(device, &descriptor) < 0)
  33 + continue;
  34 +
  35 + for (DSOModel& model: supportedModels){
  36 + // Check VID and PID for firmware flashed devices
  37 + if (descriptor.idVendor == model.vendorID && descriptor.idProduct == model.productID) {
  38 + devices.push_back(std::unique_ptr<USBDevice>(new USBDevice(model, device)));
  39 + break;
  40 + }
  41 + // Devices without firmware have different VID/PIDs
  42 + if (descriptor.idVendor == model.vendorIDnoFirmware && descriptor.idProduct == model.productIDnoFirmware) {
  43 + devices.push_back(std::unique_ptr<USBDevice>(new USBDevice(model, device)));
  44 + break;
  45 + }
  46 + }
  47 + }
  48 +
  49 + if (noAccessDeviceCount == deviceCount) {
  50 + noAccessDevices = true;
  51 + errorMessage = QCoreApplication::translate("","Please make sure to have read/write access to your usb device. On linux you need to install the correct udev file for example.");
  52 + }
  53 +
  54 + libusb_free_device_list(deviceList, true);
  55 + return devices;
  56 +}
  57 +
  58 +const QString &FindDevices::getErrorMessage() const
  59 +{
  60 + return errorMessage;
  61 +}
  62 +
  63 +bool FindDevices::allDevicesNoAccessError() const
  64 +{
  65 + return noAccessDevices;
  66 +}
... ...
openhantek/src/hantek/usb/finddevices.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +
  5 +#include <libusb-1.0/libusb.h>
  6 +#include <memory>
  7 +#include <QString>
  8 +
  9 +#include "definitions.h"
  10 +#include "usbdevice.h"
  11 +
  12 +/**
  13 + * @brief Search for Hantek devices and connect to the selected one.
  14 + *
  15 + * At the moment this class connects to the first found devic automatically.
  16 + */
  17 +class FindDevices {
  18 +public:
  19 + FindDevices(libusb_context *context=nullptr);
  20 + std::list<std::unique_ptr<USBDevice>> findDevices();
  21 + const QString& getErrorMessage() const;
  22 + bool allDevicesNoAccessError() const;
  23 +private:
  24 + libusb_context *context; ///< The usb context used for this device
  25 + QString errorMessage;
  26 + bool noAccessDevices=false;
  27 +};
... ...
openhantek/src/hantek/usb/uploadFirmware.cpp 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#include <libusb-1.0/libusb.h>
  4 +#include <memory>
  5 +#include <QString>
  6 +#include <QDebug>
  7 +#include <QCoreApplication>
  8 +#include <QTemporaryFile>
  9 +
  10 +#include "ezusb.h"
  11 +#include "uploadFirmware.h"
  12 +#include "usbdevice.h"
  13 +#include "utils/printutils.h"
  14 +
  15 +bool UploadFirmware::startUpload(USBDevice* device) {
  16 + if (device->isConnected() || !device->needsFirmware()) return false;
  17 +
  18 + // Open device
  19 + libusb_device_handle *handle;
  20 + int errorCode = libusb_open(device->getRawDevice(), &handle);
  21 + if (errorCode != LIBUSB_SUCCESS) {
  22 + handle = nullptr;
  23 + errorMessage = QCoreApplication::translate("","Couldn't open device: %1").arg(libUsbErrorString(errorCode));
  24 + return false;
  25 + }
  26 +
  27 + // Write firmware from resources to temp files
  28 + QFile firmwareRes(QString(":/firmware/%1-firmware.hex").arg(QString::fromStdString(device->getModel().firmwareToken)));
  29 + auto temp_firmware_path = std::unique_ptr<QTemporaryFile>(QTemporaryFile::createNativeFile(firmwareRes));
  30 + if (!temp_firmware_path) return false;
  31 + temp_firmware_path->open();
  32 + QFile loaderRes(QString(":/firmware/%1-loader.hex").arg(QString::fromStdString(device->getModel().firmwareToken)));
  33 + auto temp_loader_path = std::unique_ptr<QTemporaryFile>(QTemporaryFile::createNativeFile(loaderRes));
  34 + if (!temp_loader_path) return false;
  35 + temp_loader_path->open();
  36 +
  37 + /* We need to claim the first interface */
  38 + libusb_set_auto_detach_kernel_driver(handle, 1);
  39 + int status = libusb_claim_interface(handle, 0);
  40 + if (status != LIBUSB_SUCCESS) {
  41 + errorMessage = QString("libusb_claim_interface() failed: %1").arg(libusb_error_name(status));
  42 + libusb_close(handle);
  43 + return false;
  44 + }
  45 +
  46 + // Write loader
  47 + status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 0);
  48 +
  49 + if (status != LIBUSB_SUCCESS) {
  50 + errorMessage = QString("ezusb_load_ram(loader_path) failed: %1").arg(libusb_error_name(status));
  51 + libusb_release_interface(handle, 0);
  52 + libusb_close(handle);
  53 + return false;
  54 + }
  55 +
  56 + // Write firmware
  57 + status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 1);
  58 +
  59 + if (status != LIBUSB_SUCCESS) {
  60 + errorMessage = QString("ezusb_load_ram(firmware_path) failed: %1").arg(libusb_error_name(status));
  61 + libusb_release_interface(handle, 0);
  62 + libusb_close(handle);
  63 + return false;
  64 + }
  65 + libusb_release_interface(handle, 0);
  66 + libusb_close(handle);
  67 +
  68 + return status == LIBUSB_SUCCESS;
  69 +}
  70 +
  71 +const QString &UploadFirmware::getErrorMessage() const
  72 +{
  73 + return errorMessage;
  74 +}
... ...
openhantek/src/hantek/usb/uploadFirmware.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +
  5 +#include <QString>
  6 +
  7 +class USBDevice;
  8 +
  9 +/**
  10 + * Extracts the firmware from the applications resources, and uploads the firmware to the given device.
  11 + */
  12 +class UploadFirmware {
  13 +public:
  14 + bool startUpload(USBDevice* device);
  15 + const QString& getErrorMessage() const;
  16 +private:
  17 + QString errorMessage;
  18 +};
  19 +
... ...
openhantek/src/hantek/usb/usbdevice.cpp 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#include <QList>
  4 +#include <QCoreApplication>
  5 +
  6 +#include "usbdevice.h"
  7 +
  8 +#include "models.h"
  9 +#include "controlStructs.h"
  10 +#include "utils/printutils.h"
  11 +
  12 +using namespace Hantek;
  13 +
  14 +USBDevice::USBDevice(DSOModel model, libusb_device* device) : model(model), device(device) {
  15 + libusb_ref_device(device);
  16 + libusb_get_device_descriptor(device, &descriptor);
  17 +}
  18 +
  19 +bool USBDevice::connectDevice(QString &errorMessage)
  20 +{
  21 + if (needsFirmware()) return false;
  22 +
  23 + // Open device
  24 + int errorCode = libusb_open(device, &(handle));
  25 + if (errorCode != LIBUSB_SUCCESS) {
  26 + handle = nullptr;
  27 + errorMessage = QCoreApplication::translate("","Couldn't open device: %1").arg(libUsbErrorString(errorCode));
  28 + return false;
  29 + }
  30 +
  31 + // Find and claim interface
  32 + errorCode = LIBUSB_ERROR_NOT_FOUND;
  33 + libusb_config_descriptor *configDescriptor;
  34 + libusb_get_config_descriptor(device, 0, &configDescriptor);
  35 + for (int interfaceIndex = 0; interfaceIndex < (int)configDescriptor->bNumInterfaces; ++interfaceIndex) {
  36 + const libusb_interface *interface = &configDescriptor->interface[interfaceIndex];
  37 + if (interface->num_altsetting < 1)
  38 + continue;
  39 +
  40 + const libusb_interface_descriptor *interfaceDescriptor = &interface->altsetting[0];
  41 + if (interfaceDescriptor->bInterfaceClass == LIBUSB_CLASS_VENDOR_SPEC &&
  42 + interfaceDescriptor->bInterfaceSubClass == 0 &&
  43 + interfaceDescriptor->bInterfaceProtocol == 0 &&
  44 + interfaceDescriptor->bNumEndpoints == 2) {
  45 + errorCode = claimInterface(interfaceDescriptor, HANTEK_EP_OUT, HANTEK_EP_IN);
  46 + break;
  47 + }
  48 + }
  49 +
  50 + libusb_free_config_descriptor(configDescriptor);
  51 +
  52 + if (errorCode != LIBUSB_SUCCESS) {
  53 + errorMessage = QString("%1 (%2:%3)").arg(libUsbErrorString(errorCode))
  54 + .arg(libusb_get_bus_number(device), 3, 10, QLatin1Char('0'))
  55 + .arg(libusb_get_device_address(device), 3, 10, QLatin1Char('0'));
  56 + return false;
  57 + }
  58 +
  59 + return true;
  60 +}
  61 +
  62 +USBDevice::~USBDevice() {
  63 + connectionLost();
  64 +}
  65 +
  66 +int USBDevice::claimInterface(const libusb_interface_descriptor *interfaceDescriptor, int endpointOut, int endPointIn)
  67 +{
  68 + int errorCode = libusb_claim_interface(this->handle, interfaceDescriptor->bInterfaceNumber);
  69 + if (errorCode < 0) {
  70 + return errorCode;
  71 + }
  72 +
  73 + interface = interfaceDescriptor->bInterfaceNumber;
  74 +
  75 + // Check the maximum endpoint packet size
  76 + const libusb_endpoint_descriptor *endpointDescriptor;
  77 + this->outPacketLength = 0;
  78 + this->inPacketLength = 0;
  79 + for (int endpoint = 0; endpoint < interfaceDescriptor->bNumEndpoints; ++endpoint) {
  80 + endpointDescriptor = &(interfaceDescriptor->endpoint[endpoint]);
  81 + if (endpointDescriptor->bEndpointAddress == endpointOut){
  82 + this->outPacketLength = endpointDescriptor->wMaxPacketSize;
  83 + } else if (endpointDescriptor->bEndpointAddress == endPointIn){
  84 + this->inPacketLength = (model.uniqueModelID == MODEL_DSO6022BE) ? 16384 : endpointDescriptor->wMaxPacketSize;
  85 + }
  86 + }
  87 + return LIBUSB_SUCCESS;
  88 +}
  89 +
  90 +void USBDevice::connectionLost() {
  91 + libusb_unref_device(device);
  92 +
  93 + if (!this->handle)
  94 + return;
  95 +
  96 + // Release claimed interface
  97 + libusb_release_interface(this->handle, this->interface);
  98 + this->interface = -1;
  99 +
  100 + // Close device handle
  101 + libusb_close(this->handle);
  102 + this->handle = 0;
  103 +
  104 + emit deviceDisconnected();
  105 +}
  106 +
  107 +bool USBDevice::isConnected() { return this->handle != 0; }
  108 +
  109 +bool USBDevice::needsFirmware() { return this->descriptor.idProduct != model.productID || this->descriptor.idVendor != model.vendorID; }
  110 +
  111 +int USBDevice::bulkTransfer(unsigned char endpoint, unsigned char *data,
  112 + unsigned int length, int attempts,
  113 + unsigned int timeout) {
  114 + if (!this->handle)
  115 + return LIBUSB_ERROR_NO_DEVICE;
  116 +
  117 + int errorCode = LIBUSB_ERROR_TIMEOUT;
  118 + int transferred;
  119 + for (int attempt = 0; (attempt < attempts || attempts == -1) &&
  120 + errorCode == LIBUSB_ERROR_TIMEOUT;
  121 + ++attempt)
  122 + errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length,
  123 + &transferred, timeout);
  124 +
  125 + if (errorCode == LIBUSB_ERROR_NO_DEVICE)
  126 + connectionLost();
  127 + if (errorCode < 0)
  128 + return errorCode;
  129 + else
  130 + return transferred;
  131 +}
  132 +
  133 +/// \brief Bulk write to the oscilloscope.
  134 +/// \param data Buffer for the sent/recieved data.
  135 +/// \param length The length of the packet.
  136 +/// \param attempts The number of attempts, that are done on timeouts.
  137 +/// \return Number of sent bytes on success, libusb error code on error.
  138 +int USBDevice::bulkWrite(unsigned char *data, unsigned int length, int attempts) {
  139 + if (!this->handle)
  140 + return LIBUSB_ERROR_NO_DEVICE;
  141 +
  142 + int errorCode = this->getConnectionSpeed();
  143 + if (errorCode < 0)
  144 + return errorCode;
  145 +
  146 + return this->bulkTransfer(HANTEK_EP_OUT, data, length, attempts);
  147 +}
  148 +
  149 +/// \brief Bulk read from the oscilloscope.
  150 +/// \param data Buffer for the sent/recieved data.
  151 +/// \param length The length of the packet.
  152 +/// \param attempts The number of attempts, that are done on timeouts.
  153 +/// \return Number of received bytes on success, libusb error code on error.
  154 +int USBDevice::bulkRead(unsigned char *data, unsigned int length, int attempts) {
  155 + if (!this->handle)
  156 + return LIBUSB_ERROR_NO_DEVICE;
  157 +
  158 + int errorCode = this->getConnectionSpeed();
  159 + if (errorCode < 0)
  160 + return errorCode;
  161 +
  162 + return this->bulkTransfer(HANTEK_EP_IN, data, length, attempts);
  163 +}
  164 +
  165 +/// \brief Send a bulk command to the oscilloscope.
  166 +/// \param command The command, that should be sent.
  167 +/// \param attempts The number of attempts, that are done on timeouts.
  168 +/// \return Number of sent bytes on success, libusb error code on error.
  169 +int USBDevice::bulkCommand(DataArray<unsigned char> *command,
  170 + int attempts) {
  171 + if (!this->handle)
  172 + return LIBUSB_ERROR_NO_DEVICE;
  173 +
  174 + // don't send bulk command if dso6022be
  175 + if (this->getUniqueModelID() == MODEL_DSO6022BE)
  176 + return 0;
  177 +
  178 + // Send BeginCommand control command
  179 + int errorCode = this->controlWrite(CONTROL_BEGINCOMMAND,
  180 + this->beginCommandControl->data(),
  181 + this->beginCommandControl->getSize());
  182 + if (errorCode < 0)
  183 + return errorCode;
  184 +
  185 + // Send bulk command
  186 + return this->bulkWrite(command->data(), command->getSize(), attempts);
  187 +}
  188 +
  189 +/// \brief Multi packet bulk read from the oscilloscope.
  190 +/// \param data Buffer for the sent/recieved data.
  191 +/// \param length The length of data contained in the packets.
  192 +/// \param attempts The number of attempts, that are done on timeouts.
  193 +/// \return Number of received bytes on success, libusb error code on error.
  194 +int USBDevice::bulkReadMulti(unsigned char *data, unsigned int length,
  195 + int attempts) {
  196 + if (!this->handle)
  197 + return LIBUSB_ERROR_NO_DEVICE;
  198 +
  199 + int errorCode = 0;
  200 +
  201 + errorCode = this->getConnectionSpeed();
  202 + if (errorCode < 0)
  203 + return errorCode;
  204 +
  205 + errorCode = this->inPacketLength;
  206 + unsigned int packet, received = 0;
  207 + for (packet = 0; received < length && errorCode == this->inPacketLength;
  208 + ++packet) {
  209 + errorCode = this->bulkTransfer(
  210 + HANTEK_EP_IN, data + packet * this->inPacketLength,
  211 + qMin(length - received, (unsigned int)this->inPacketLength), attempts,
  212 + HANTEK_TIMEOUT_MULTI);
  213 + if (errorCode > 0)
  214 + received += errorCode;
  215 + }
  216 +
  217 + if (received > 0)
  218 + return received;
  219 + else
  220 + return errorCode;
  221 +}
  222 +
  223 +/// \brief Control transfer to the oscilloscope.
  224 +/// \param type The request type, also sets the direction of the transfer.
  225 +/// \param request The request field of the packet.
  226 +/// \param data Buffer for the sent/recieved data.
  227 +/// \param length The length field of the packet.
  228 +/// \param value The value field of the packet.
  229 +/// \param index The index field of the packet.
  230 +/// \param attempts The number of attempts, that are done on timeouts.
  231 +/// \return Number of transferred bytes on success, libusb error code on error.
  232 +int USBDevice::controlTransfer(unsigned char type, unsigned char request,
  233 + unsigned char *data, unsigned int length, int value,
  234 + int index, int attempts) {
  235 + if (!this->handle)
  236 + return LIBUSB_ERROR_NO_DEVICE;
  237 +
  238 + int errorCode = LIBUSB_ERROR_TIMEOUT;
  239 + for (int attempt = 0; (attempt < attempts || attempts == -1) &&
  240 + errorCode == LIBUSB_ERROR_TIMEOUT;
  241 + ++attempt)
  242 + errorCode = libusb_control_transfer(this->handle, type, request, value,
  243 + index, data, length, HANTEK_TIMEOUT);
  244 +
  245 + if (errorCode == LIBUSB_ERROR_NO_DEVICE)
  246 + connectionLost();
  247 + return errorCode;
  248 +}
  249 +
  250 +/// \brief Control write to the oscilloscope.
  251 +/// \param request The request field of the packet.
  252 +/// \param data Buffer for the sent/recieved data.
  253 +/// \param length The length field of the packet.
  254 +/// \param value The value field of the packet.
  255 +/// \param index The index field of the packet.
  256 +/// \param attempts The number of attempts, that are done on timeouts.
  257 +/// \return Number of sent bytes on success, libusb error code on error.
  258 +int USBDevice::controlWrite(unsigned char request, unsigned char *data,
  259 + unsigned int length, int value, int index,
  260 + int attempts) {
  261 + if (!this->handle)
  262 + return LIBUSB_ERROR_NO_DEVICE;
  263 +
  264 + return this->controlTransfer(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
  265 + request, data, length, value, index, attempts);
  266 +}
  267 +
  268 +/// \brief Control read to the oscilloscope.
  269 +/// \param request The request field of the packet.
  270 +/// \param data Buffer for the sent/recieved data.
  271 +/// \param length The length field of the packet.
  272 +/// \param value The value field of the packet.
  273 +/// \param index The index field of the packet.
  274 +/// \param attempts The number of attempts, that are done on timeouts.
  275 +/// \return Number of received bytes on success, libusb error code on error.
  276 +int USBDevice::controlRead(unsigned char request, unsigned char *data,
  277 + unsigned int length, int value, int index,
  278 + int attempts) {
  279 + if (!this->handle)
  280 + return LIBUSB_ERROR_NO_DEVICE;
  281 +
  282 + return this->controlTransfer(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN,
  283 + request, data, length, value, index, attempts);
  284 +}
  285 +
  286 +/// \brief Gets the speed of the connection.
  287 +/// \return The ::ConnectionSpeed of the USB connection.
  288 +int USBDevice::getConnectionSpeed() {
  289 + int errorCode;
  290 + ControlGetSpeed response;
  291 +
  292 + errorCode =
  293 + this->controlRead(CONTROL_GETSPEED, response.data(), response.getSize());
  294 + if (errorCode < 0)
  295 + return errorCode;
  296 +
  297 + return response.getSpeed();
  298 +}
  299 +
  300 +/// \brief Gets the maximum size of one packet transmitted via bulk transfer.
  301 +/// \return The maximum packet size in bytes, -1 on error.
  302 +int USBDevice::getPacketSize() {
  303 + switch (this->getConnectionSpeed()) {
  304 + case CONNECTION_FULLSPEED:
  305 + return 64;
  306 + break;
  307 + case CONNECTION_HIGHSPEED:
  308 + return 512;
  309 + break;
  310 + default:
  311 + return -1;
  312 + break;
  313 + }
  314 +}
  315 +
  316 +/// \brief Get the oscilloscope model.
  317 +/// \return The ::Model of the connected Hantek DSO.
  318 +int USBDevice::getUniqueModelID() { return model.uniqueModelID; }
  319 +
  320 +libusb_device *USBDevice::getRawDevice() const
  321 +{
  322 + return device;
  323 +}
  324 +
  325 +const DSOModel &USBDevice::getModel() const
  326 +{
  327 + return model;
  328 +}
... ...
openhantek/src/hantek/usb/usbdevice.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +
  5 +#include <QObject>
  6 +#include <QStringList>
  7 +#include <libusb-1.0/libusb.h>
  8 +#include <memory>
  9 +
  10 +#include "controlbegin.h"
  11 +#include "definitions.h"
  12 +#include "utils/dataarray.h"
  13 +#include "models.h"
  14 +
  15 +#define HANTEK_TIMEOUT 500 ///< Timeout for USB transfers in ms
  16 +#define HANTEK_TIMEOUT_MULTI \
  17 + 100 ///< Timeout for multi packet USB transfers in ms
  18 +#define HANTEK_ATTEMPTS 3 ///< The number of transfer attempts
  19 +#define HANTEK_ATTEMPTS_MULTI \
  20 + 1 ///< The number of multi packet transfer attempts
  21 +
  22 +/// \brief This class handles the USB communication with an usb device that has one in and one out endpoint.
  23 +class USBDevice : public QObject {
  24 + Q_OBJECT
  25 +
  26 +public:
  27 + USBDevice(DSOModel model, libusb_device *device);
  28 + ~USBDevice();
  29 + bool connectDevice(QString &errorMessage);
  30 +
  31 + /// \brief Check if the oscilloscope is connected.
  32 + /// \return true, if a connection is up.
  33 + bool isConnected();
  34 + bool needsFirmware();
  35 +
  36 + // Various methods to handle USB transfers
  37 +
  38 + /// \brief Bulk transfer to/from the oscilloscope.
  39 + /// \param endpoint Endpoint number, also sets the direction of the transfer.
  40 + /// \param data Buffer for the sent/recieved data.
  41 + /// \param length The length of the packet.
  42 + /// \param attempts The number of attempts, that are done on timeouts.
  43 + /// \param timeout The timeout in ms.
  44 + /// \return Number of transferred bytes on success, libusb error code on error.
  45 + int bulkTransfer(unsigned char endpoint, unsigned char *data,
  46 + unsigned int length, int attempts = HANTEK_ATTEMPTS,
  47 + unsigned int timeout = HANTEK_TIMEOUT);
  48 + int bulkWrite(unsigned char *data, unsigned int length,
  49 + int attempts = HANTEK_ATTEMPTS);
  50 + int bulkRead(unsigned char *data, unsigned int length,
  51 + int attempts = HANTEK_ATTEMPTS);
  52 +
  53 + int bulkCommand(DataArray<unsigned char> *command,
  54 + int attempts = HANTEK_ATTEMPTS);
  55 + int bulkReadMulti(unsigned char *data, unsigned int length,
  56 + int attempts = HANTEK_ATTEMPTS_MULTI);
  57 +
  58 + int controlTransfer(unsigned char type, unsigned char request,
  59 + unsigned char *data, unsigned int length, int value,
  60 + int index, int attempts = HANTEK_ATTEMPTS);
  61 + int controlWrite(unsigned char request, unsigned char *data,
  62 + unsigned int length, int value = 0, int index = 0,
  63 + int attempts = HANTEK_ATTEMPTS);
  64 + int controlRead(unsigned char request, unsigned char *data,
  65 + unsigned int length, int value = 0, int index = 0,
  66 + int attempts = HANTEK_ATTEMPTS);
  67 +
  68 + int getConnectionSpeed();
  69 + int getPacketSize();
  70 + int getUniqueModelID();
  71 +
  72 + libusb_device* getRawDevice() const;
  73 + const DSOModel& getModel() const;
  74 +protected:
  75 + int claimInterface(const libusb_interface_descriptor *interfaceDescriptor, int endpointOut, int endPointIn);
  76 + void connectionLost();
  77 +
  78 + // Command buffers
  79 + ControlBeginCommand *beginCommandControl = new ControlBeginCommand();
  80 + DSOModel model;
  81 +
  82 + // Libusb specific variables
  83 + struct libusb_device_descriptor descriptor;
  84 + libusb_device *device; ///< The USB handle for the oscilloscope
  85 + libusb_device_handle *handle = nullptr;
  86 + int interface;
  87 + int outPacketLength; ///< Packet length for the OUT endpoint
  88 + int inPacketLength; ///< Packet length for the IN endpoint
  89 +
  90 +signals:
  91 + void deviceDisconnected(); ///< The device has been disconnected
  92 +};
... ...
openhantek/src/main.cpp
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// main.cpp
5   -//
6   -// Copyright (C) 2010 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 <QLibraryInfo>
26 5 #include <QLocale>
  6 +#include <QDebug>
  7 +#include <QMessageBox>
27 8 #include <QTranslator>
  9 +#include <QTimer>
28 10 #include <iostream>
  11 +#include <memory>
29 12  
30   -#include "openhantek.h"
  13 +#include <libusb-1.0/libusb.h>
  14 +
  15 +#include "hantekdsocontrol.h"
  16 +#include "dataanalyzer.h"
  17 +#include "mainwindow.h"
  18 +#include "usb/finddevices.h"
  19 +#include "usb/usbdevice.h"
  20 +#include "usb/uploadFirmware.h"
  21 +
  22 +using namespace Hantek;
  23 +
  24 +void showMessage(const QString& message) {
  25 + QMessageBox::information(nullptr,QCoreApplication::translate("","No connection established!"), message);
  26 +}
31 27  
32 28 /// \brief Initialize resources and translations and show the main window.
33 29 int main(int argc, char *argv[]) {
34   - std::cout << "Version " << VERSION << std::endl;
35   - Q_INIT_RESOURCE(application);
  30 + // Set application information
  31 + QCoreApplication::setOrganizationName("OpenHantek");
  32 + QCoreApplication::setOrganizationDomain("www.openhantek.org");
  33 + QCoreApplication::setApplicationName("OpenHantek");
  34 + QCoreApplication::setApplicationVersion(VERSION);
36 35  
37 36 QApplication openHantekApplication(argc, argv);
38 37  
39 38 QTranslator qtTranslator;
40   - if (qtTranslator.load("qt_" + QLocale::system().name(),
41   - QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
  39 + if (qtTranslator.load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
42 40 openHantekApplication.installTranslator(&qtTranslator);
43 41  
44 42 QTranslator openHantekTranslator;
45 43 if (openHantekTranslator.load(QLocale(), QLatin1String("openhantek"),
46 44 QLatin1String("_"),
47   - QLatin1String(":/translations")))
48   - openHantekApplication.installTranslator(&openHantekTranslator);
  45 + QLatin1String(":/translations"))) {
  46 + openHantekApplication.installTranslator(&openHantekTranslator);
  47 + }
  48 +
  49 + libusb_context* context;
  50 + int error = libusb_init(&context);
  51 +
  52 + if (error){
  53 + showMessage(QCoreApplication::translate("","Can't initalize USB: %1").arg(libUsbErrorString(error)));
  54 + return -1;
  55 + }
  56 +
  57 + FindDevices findDevices;
  58 + std::list<std::unique_ptr<USBDevice>> devices = findDevices.findDevices();
  59 +
  60 + if (devices.empty()) {
  61 + showMessage(QCoreApplication::translate("","No Hantek oscilloscope found. Please check if your device is supported by this software, is connected, in the right mode (oscilloscope mode) and if the driver is correctly installed. Refer to the <a href='https://github.com/OpenHantek/openhantek/'>website</a> for help: %1").arg(findDevices.getErrorMessage()));
  62 + return -1;
  63 + }
  64 +
  65 + // Upload firmwares for all connected devices
  66 + for (auto i = devices.begin(); i != devices.end(); ++i) {
  67 + if (i->get()->needsFirmware()) {
  68 + UploadFirmware uf;
  69 + if (!uf.startUpload(i->get())) {
  70 + showMessage(QCoreApplication::translate("","Uploading firmware to %1: failed").arg(uf.getErrorMessage()));
  71 + } else {
  72 + showMessage(QCoreApplication::translate("","Uploading firmware to %1: done").arg(QString::fromStdString(i->get()->getModel().name)));
  73 + }
  74 + }
  75 + }
49 76  
50   - OpenHantekMainWindow *openHantekMainWindow = new OpenHantekMainWindow();
  77 + devices.clear();
  78 +
  79 + // Find first ready device
  80 + devices = findDevices.findDevices();
  81 + std::unique_ptr<USBDevice> device;
  82 + for (auto i = devices.begin(); i != devices.end(); ++i) {
  83 + if (i->get()->needsFirmware()) continue;
  84 + QString errorMessage;
  85 + if (i->get()->connectDevice(errorMessage)) {
  86 + device = std::move(*i);
  87 + break;
  88 + } else {
  89 + showMessage(QCoreApplication::translate("","A device was found, but the connection could not be established: %1").arg(findDevices.getErrorMessage()));
  90 + }
  91 + }
  92 +
  93 + if (device == nullptr) {
  94 + showMessage(QCoreApplication::translate("","A device was found, but the firmware upload seem to have failed or the connection could not be established: %1").arg(findDevices.getErrorMessage()));
  95 + return -1;
  96 + }
  97 +
  98 + // USB device
  99 + QObject::connect(device.get(), &USBDevice::deviceDisconnected, QCoreApplication::instance(), &QCoreApplication::quit);
  100 +
  101 + QThread dsoControlThread;
  102 + std::shared_ptr<HantekDsoControl> dsoControl(new HantekDsoControl(device.get()));
  103 + dsoControl->moveToThread(&dsoControlThread);
  104 + QObject::connect(&dsoControlThread,&QThread::started,dsoControl.get(),&HantekDsoControl::run);
  105 + QObject::connect(dsoControl.get(), &HantekDsoControl::communicationError, QCoreApplication::instance(), &QCoreApplication::quit);
  106 +
  107 + std::shared_ptr<DataAnalyzer> dataAnalyser(new DataAnalyzer());
  108 +
  109 + OpenHantekMainWindow *openHantekMainWindow = new OpenHantekMainWindow(dsoControl, dataAnalyser);
51 110 openHantekMainWindow->show();
52 111  
53   - return openHantekApplication.exec();
  112 + dsoControlThread.start();
  113 +
  114 + int res = openHantekApplication.exec();
  115 +
  116 + dsoControlThread.quit();
  117 + dsoControlThread.wait(10000);
  118 + return res;
54 119 }
... ...
openhantek/src/mainwindow.cpp 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#include <QAction>
  4 +#include <QActionGroup>
  5 +#include <QApplication>
  6 +#include <QDir>
  7 +#include <QFileDialog>
  8 +#include <QMainWindow>
  9 +#include <QMenu>
  10 +#include <QMenuBar>
  11 +#include <QMessageBox>
  12 +#include <QStatusBar>
  13 +#include <QToolBar>
  14 +
  15 +#include "mainwindow.h"
  16 +
  17 +#include "configdialog.h"
  18 +#include "dataanalyzer.h"
  19 +#include "dockwindows.h"
  20 +#include "hantekdsocontrol.h"
  21 +#include "dsowidget.h"
  22 +#include "hantek/hantekdsocontrol.h"
  23 +#include "settings.h"
  24 +
  25 +////////////////////////////////////////////////////////////////////////////////
  26 +// class OpenHantekMainWindow
  27 +/// \brief Initializes the gui elements of the main window.
  28 +/// \param parent The parent widget.
  29 +/// \param flags Flags for the window manager.
  30 +OpenHantekMainWindow::OpenHantekMainWindow(std::shared_ptr<HantekDsoControl> dsoControl, std::shared_ptr<DataAnalyzer> dataAnalyzer)
  31 + :dsoControl(dsoControl),dataAnalyzer(dataAnalyzer) {
  32 +
  33 + // Window title
  34 + setWindowIcon(QIcon(":openhantek.png"));
  35 + setWindowTitle(tr("OpenHantek"));
  36 +
  37 + // Application settings
  38 + settings = new DsoSettings();
  39 + settings->setChannelCount(dsoControl->getChannelCount());
  40 + readSettings();
  41 +
  42 + // Create dock windows before the dso widget, they fix messed up settings
  43 + createDockWindows();
  44 +
  45 + // Central oszilloscope widget
  46 + dsoWidget = new DsoWidget(settings, dataAnalyzer.get());
  47 + setCentralWidget(dsoWidget);
  48 +
  49 + // Subroutines for window elements
  50 + createActions();
  51 + createToolBars();
  52 + createMenus();
  53 + createStatusBar();
  54 +
  55 + // Apply the settings after the gui is initialized
  56 + applySettings();
  57 +
  58 + // Connect all signals
  59 + connectSignals();
  60 +
  61 + // Set up the oscilloscope
  62 + applySettingsToDevice();
  63 + dsoControl->startSampling();
  64 +}
  65 +
  66 +/// \brief Save the settings before exiting.
  67 +/// \param event The close event that should be handled.
  68 +void OpenHantekMainWindow::closeEvent(QCloseEvent *event) {
  69 + if (settings->options.alwaysSave)
  70 + writeSettings();
  71 +
  72 + QMainWindow::closeEvent(event);
  73 +}
  74 +
  75 +/// \brief Create the used actions.
  76 +void OpenHantekMainWindow::createActions() {
  77 + openAction =
  78 + new QAction(QIcon(":actions/open.png"), tr("&Open..."), this);
  79 + openAction->setShortcut(tr("Ctrl+O"));
  80 + openAction->setStatusTip(tr("Open saved settings"));
  81 + connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
  82 +
  83 + saveAction = new QAction(QIcon(":actions/save.png"), tr("&Save"), this);
  84 + saveAction->setShortcut(tr("Ctrl+S"));
  85 + saveAction->setStatusTip(tr("Save the current settings"));
  86 + connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
  87 +
  88 + saveAsAction =
  89 + new QAction(QIcon(":actions/save-as.png"), tr("Save &as..."), this);
  90 + saveAsAction->setStatusTip(
  91 + tr("Save the current settings to another file"));
  92 + connect(saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));
  93 +
  94 + printAction =
  95 + new QAction(QIcon(":actions/print.png"), tr("&Print..."), this);
  96 + printAction->setShortcut(tr("Ctrl+P"));
  97 + printAction->setStatusTip(tr("Print the oscilloscope screen"));
  98 + connect(printAction, SIGNAL(triggered()), dsoWidget,
  99 + SLOT(print()));
  100 +
  101 + exportAsAction =
  102 + new QAction(QIcon(":actions/export-as.png"), tr("&Export as..."), this);
  103 + exportAsAction->setShortcut(tr("Ctrl+E"));
  104 + exportAsAction->setStatusTip(
  105 + tr("Export the oscilloscope data to a file"));
  106 + connect(exportAsAction, SIGNAL(triggered()), dsoWidget,
  107 + SLOT(exportAs()));
  108 +
  109 + exitAction = new QAction(tr("E&xit"), this);
  110 + exitAction->setShortcut(tr("Ctrl+Q"));
  111 + exitAction->setStatusTip(tr("Exit the application"));
  112 + connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
  113 +
  114 + configAction = new QAction(tr("&Settings"), this);
  115 + configAction->setShortcut(tr("Ctrl+S"));
  116 + configAction->setStatusTip(tr("Configure the oscilloscope"));
  117 + connect(configAction, SIGNAL(triggered()), this, SLOT(config()));
  118 +
  119 + startStopAction = new QAction(this);
  120 + startStopAction->setShortcut(tr("Space"));
  121 + stopped();
  122 +
  123 + digitalPhosphorAction = new QAction(
  124 + QIcon(":actions/digitalphosphor.png"), tr("Digital &phosphor"), this);
  125 + digitalPhosphorAction->setCheckable(true);
  126 + digitalPhosphorAction->setChecked(settings->view.digitalPhosphor);
  127 + digitalPhosphor(settings->view.digitalPhosphor);
  128 + connect(digitalPhosphorAction, SIGNAL(toggled(bool)), this,
  129 + SLOT(digitalPhosphor(bool)));
  130 +
  131 + zoomAction = new QAction(QIcon(":actions/zoom.png"), tr("&Zoom"), this);
  132 + zoomAction->setCheckable(true);
  133 + zoomAction->setChecked(settings->view.zoom);
  134 + zoom(settings->view.zoom);
  135 + connect(zoomAction, SIGNAL(toggled(bool)), this, SLOT(zoom(bool)));
  136 + connect(zoomAction, SIGNAL(toggled(bool)), dsoWidget,
  137 + SLOT(updateZoom(bool)));
  138 +
  139 + aboutAction = new QAction(tr("&About"), this);
  140 + aboutAction->setStatusTip(tr("Show information about this program"));
  141 + connect(aboutAction, SIGNAL(triggered()), this, SLOT(about()));
  142 +
  143 + aboutQtAction = new QAction(tr("About &Qt"), this);
  144 + aboutQtAction->setStatusTip(tr("Show the Qt library's About box"));
  145 + connect(aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
  146 +
  147 +#ifdef DEBUG
  148 + commandAction = new QAction(tr("Send command"), this);
  149 + commandAction->setShortcut(tr("Shift+C"));
  150 +#endif
  151 +}
  152 +
  153 +/// \brief Create the menus and menuitems.
  154 +void OpenHantekMainWindow::createMenus() {
  155 + fileMenu = menuBar()->addMenu(tr("&File"));
  156 + fileMenu->addAction(openAction);
  157 + fileMenu->addAction(saveAction);
  158 + fileMenu->addAction(saveAsAction);
  159 + fileMenu->addSeparator();
  160 + fileMenu->addAction(printAction);
  161 + fileMenu->addAction(exportAsAction);
  162 + fileMenu->addSeparator();
  163 + fileMenu->addAction(exitAction);
  164 +
  165 + viewMenu = menuBar()->addMenu(tr("&View"));
  166 + viewMenu->addAction(digitalPhosphorAction);
  167 + viewMenu->addAction(zoomAction);
  168 + viewMenu->addSeparator();
  169 + dockMenu = viewMenu->addMenu(tr("&Docking windows"));
  170 + dockMenu->addAction(horizontalDock->toggleViewAction());
  171 + dockMenu->addAction(spectrumDock->toggleViewAction());
  172 + dockMenu->addAction(triggerDock->toggleViewAction());
  173 + dockMenu->addAction(voltageDock->toggleViewAction());
  174 + toolbarMenu = viewMenu->addMenu(tr("&Toolbars"));
  175 + toolbarMenu->addAction(fileToolBar->toggleViewAction());
  176 + toolbarMenu->addAction(oscilloscopeToolBar->toggleViewAction());
  177 + toolbarMenu->addAction(viewToolBar->toggleViewAction());
  178 +
  179 + oscilloscopeMenu = menuBar()->addMenu(tr("&Oscilloscope"));
  180 + oscilloscopeMenu->addAction(configAction);
  181 + oscilloscopeMenu->addSeparator();
  182 + oscilloscopeMenu->addAction(startStopAction);
  183 +#ifdef DEBUG
  184 + oscilloscopeMenu->addSeparator();
  185 + oscilloscopeMenu->addAction(commandAction);
  186 +#endif
  187 +
  188 + menuBar()->addSeparator();
  189 +
  190 + helpMenu = menuBar()->addMenu(tr("&Help"));
  191 + helpMenu->addAction(aboutAction);
  192 + helpMenu->addAction(aboutQtAction);
  193 +}
  194 +
  195 +namespace {
  196 +
  197 +QToolBar* CreateToolBar(const QString& title) {
  198 + QToolBar* newObj = new QToolBar(title);
  199 + newObj->setObjectName(title);
  200 + newObj->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea);
  201 + return newObj;
  202 +}
  203 +
  204 +}
  205 +
  206 +/// \brief Create the toolbars and their buttons.
  207 +void OpenHantekMainWindow::createToolBars() {
  208 +
  209 + // File
  210 + fileToolBar = CreateToolBar(tr("File"));
  211 + fileToolBar->addAction(openAction);
  212 + fileToolBar->addAction(saveAction);
  213 + fileToolBar->addAction(saveAsAction);
  214 + fileToolBar->addSeparator();
  215 + fileToolBar->addAction(printAction);
  216 + fileToolBar->addAction(exportAsAction);
  217 +
  218 + // Oscilloscope
  219 + oscilloscopeToolBar = CreateToolBar(tr("Oscilloscope"));
  220 + oscilloscopeToolBar->addAction(startStopAction);
  221 +
  222 + // View
  223 + viewToolBar = CreateToolBar(tr("View"));
  224 + viewToolBar->addAction(digitalPhosphorAction);
  225 + viewToolBar->addAction(zoomAction);
  226 +}
  227 +
  228 +/// \brief Create the status bar.
  229 +void OpenHantekMainWindow::createStatusBar() {
  230 +#ifdef DEBUG
  231 + // Command field inside the status bar
  232 + commandEdit = new QLineEdit();
  233 + commandEdit->hide();
  234 +
  235 + statusBar()->addPermanentWidget(commandEdit, 1);
  236 +#endif
  237 +
  238 + statusBar()->showMessage(tr("Ready"));
  239 +
  240 +#ifdef DEBUG
  241 + connect(commandAction, SIGNAL(triggered()), commandEdit,
  242 + SLOT(show()));
  243 + connect(commandAction, SIGNAL(triggered()), commandEdit,
  244 + SLOT(setFocus()));
  245 + connect(commandEdit, SIGNAL(returnPressed()), this,
  246 + SLOT(sendCommand()));
  247 +#endif
  248 +}
  249 +
  250 +/// \brief Create all docking windows.
  251 +void OpenHantekMainWindow::createDockWindows() {
  252 + horizontalDock = new HorizontalDock(settings);
  253 + triggerDock = new TriggerDock(settings, dsoControl->getSpecialTriggerSources());
  254 + spectrumDock = new SpectrumDock(settings);
  255 + voltageDock = new VoltageDock(settings);
  256 +}
  257 +
  258 +/// \brief Connect general signals and device management signals.
  259 +void OpenHantekMainWindow::connectSignals() {
  260 + // Connect general signals
  261 + connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
  262 + // connect(dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
  263 + connect(dsoControl.get(), SIGNAL(statusMessage(QString, int)),
  264 + statusBar(), SLOT(showMessage(QString, int)));
  265 + connect(dsoControl.get(),
  266 + SIGNAL(samplesAvailable(const std::vector<std::vector<double>> *,
  267 + double, bool, QMutex *)),
  268 + dataAnalyzer.get(),
  269 + SLOT(analyze(const std::vector<std::vector<double>> *, double, bool,
  270 + QMutex *)));
  271 +
  272 + // Connect signals to DSO controller and widget
  273 + connect(horizontalDock, SIGNAL(samplerateChanged(double)), this,
  274 + SLOT(samplerateSelected()));
  275 + connect(horizontalDock, SIGNAL(timebaseChanged(double)), this,
  276 + SLOT(timebaseSelected()));
  277 + connect(horizontalDock, SIGNAL(frequencybaseChanged(double)),
  278 + dsoWidget, SLOT(updateFrequencybase(double)));
  279 + connect(horizontalDock, SIGNAL(recordLengthChanged(unsigned long)),
  280 + this, SLOT(recordLengthSelected(unsigned long)));
  281 + // connect(horizontalDock, SIGNAL(formatChanged(HorizontalFormat)),
  282 + // dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
  283 +
  284 + connect(triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)),
  285 + dsoControl.get(), SLOT(setTriggerMode(Dso::TriggerMode)));
  286 + connect(triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)),
  287 + dsoWidget, SLOT(updateTriggerMode()));
  288 + connect(triggerDock, SIGNAL(sourceChanged(bool, unsigned int)),
  289 + dsoControl.get(), SLOT(setTriggerSource(bool, unsigned int)));
  290 + connect(triggerDock, SIGNAL(sourceChanged(bool, unsigned int)),
  291 + dsoWidget, SLOT(updateTriggerSource()));
  292 + connect(triggerDock, SIGNAL(slopeChanged(Dso::Slope)), dsoControl.get(),
  293 + SLOT(setTriggerSlope(Dso::Slope)));
  294 + connect(triggerDock, SIGNAL(slopeChanged(Dso::Slope)), dsoWidget,
  295 + SLOT(updateTriggerSlope()));
  296 + connect(dsoWidget, SIGNAL(triggerPositionChanged(double)),
  297 + dsoControl.get(), SLOT(setPretriggerPosition(double)));
  298 + connect(dsoWidget, SIGNAL(triggerLevelChanged(unsigned int, double)),
  299 + dsoControl.get(), SLOT(setTriggerLevel(unsigned int, double)));
  300 +
  301 + connect(voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this,
  302 + SLOT(updateUsed(unsigned int)));
  303 + connect(voltageDock, SIGNAL(usedChanged(unsigned int, bool)),
  304 + dsoWidget, SLOT(updateVoltageUsed(unsigned int, bool)));
  305 + connect(voltageDock,
  306 + SIGNAL(couplingChanged(unsigned int, Dso::Coupling)),
  307 + dsoControl.get(), SLOT(setCoupling(unsigned int, Dso::Coupling)));
  308 + connect(voltageDock,
  309 + SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), dsoWidget,
  310 + SLOT(updateVoltageCoupling(unsigned int)));
  311 + connect(voltageDock, SIGNAL(modeChanged(Dso::MathMode)),
  312 + dsoWidget, SLOT(updateMathMode()));
  313 + connect(voltageDock, SIGNAL(gainChanged(unsigned int, double)), this,
  314 + SLOT(updateVoltageGain(unsigned int)));
  315 + connect(voltageDock, SIGNAL(gainChanged(unsigned int, double)),
  316 + dsoWidget, SLOT(updateVoltageGain(unsigned int)));
  317 + connect(dsoWidget, SIGNAL(offsetChanged(unsigned int, double)), this,
  318 + SLOT(updateOffset(unsigned int)));
  319 +
  320 + connect(spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this,
  321 + SLOT(updateUsed(unsigned int)));
  322 + connect(spectrumDock, SIGNAL(usedChanged(unsigned int, bool)),
  323 + dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool)));
  324 + connect(spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)),
  325 + dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int)));
  326 +
  327 + // Started/stopped signals from oscilloscope
  328 + connect(dsoControl.get(), SIGNAL(samplingStarted()), this, SLOT(started()));
  329 + connect(dsoControl.get(), SIGNAL(samplingStopped()), this, SLOT(stopped()));
  330 +
  331 + // connect(dsoControl, SIGNAL(recordLengthChanged(unsigned long)), this,
  332 + // SLOT(recordLengthChanged()));
  333 + connect(dsoControl.get(), SIGNAL(recordTimeChanged(double)), this,
  334 + SLOT(recordTimeChanged(double)));
  335 + connect(dsoControl.get(), SIGNAL(samplerateChanged(double)), this,
  336 + SLOT(samplerateChanged(double)));
  337 +
  338 + connect(dsoControl.get(),
  339 + SIGNAL(availableRecordLengthsChanged(QList<unsigned int>)),
  340 + horizontalDock,
  341 + SLOT(availableRecordLengthsChanged(QList<unsigned int>)));
  342 + connect(dsoControl.get(), SIGNAL(samplerateLimitsChanged(double, double)),
  343 + horizontalDock, SLOT(samplerateLimitsChanged(double, double)));
  344 + connect(dsoControl.get(), SIGNAL(samplerateSet(int, QList<double>)),
  345 + horizontalDock, SLOT(samplerateSet(int, QList<double>)));
  346 +}
  347 +
  348 +/// \brief Initialize the device with the current settings.
  349 +void OpenHantekMainWindow::applySettingsToDevice() {
  350 + for (unsigned int channel = 0;
  351 + channel < settings->scope.physicalChannels; ++channel) {
  352 + dsoControl->setCoupling(
  353 + channel, (Dso::Coupling)settings->scope.voltage[channel].misc);
  354 + updateVoltageGain(channel);
  355 + updateOffset(channel);
  356 + dsoControl->setTriggerLevel(
  357 + channel, settings->scope.voltage[channel].trigger);
  358 + }
  359 + updateUsed(settings->scope.physicalChannels);
  360 + if (settings->scope.horizontal.samplerateSet)
  361 + samplerateSelected();
  362 + else
  363 + timebaseSelected();
  364 + if (dsoControl->getAvailableRecordLengths()->isEmpty())
  365 + dsoControl->setRecordLength(
  366 + settings->scope.horizontal.recordLength);
  367 + else {
  368 + int index = dsoControl->getAvailableRecordLengths()->indexOf(
  369 + settings->scope.horizontal.recordLength);
  370 + dsoControl->setRecordLength(index < 0 ? 1 : index);
  371 + }
  372 + dsoControl->setTriggerMode(settings->scope.trigger.mode);
  373 + dsoControl->setPretriggerPosition(
  374 + settings->scope.trigger.position *
  375 + settings->scope.horizontal.timebase * DIVS_TIME);
  376 + dsoControl->setTriggerSlope(settings->scope.trigger.slope);
  377 + dsoControl->setTriggerSource(settings->scope.trigger.special,
  378 + settings->scope.trigger.source);
  379 +}
  380 +
  381 +/// \brief Read the settings from an ini file.
  382 +/// \param fileName Optional filename to export the settings to a specific file.
  383 +/// \return 0 on success, negative on error.
  384 +int OpenHantekMainWindow::readSettings(const QString &fileName) {
  385 + int status = settings->load(fileName);
  386 +
  387 + if (status == 0)
  388 + emit(settingsChanged());
  389 +
  390 + return status;
  391 +}
  392 +
  393 +/// \brief Save the settings to the harddisk.
  394 +/// \param fileName Optional filename to read the settings from an ini file.
  395 +/// \return 0 on success, negative on error.
  396 +int OpenHantekMainWindow::writeSettings(const QString &fileName) {
  397 + updateSettings();
  398 +
  399 + return settings->save(fileName);
  400 +}
  401 +
  402 +/// \brief Open a configuration file.
  403 +/// \return 0 on success, 1 on user abort, negative on error.
  404 +int OpenHantekMainWindow::open() {
  405 + QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), "",
  406 + tr("Settings (*.ini)"));
  407 +
  408 + if (!fileName.isEmpty())
  409 + return readSettings(fileName);
  410 + else
  411 + return 1;
  412 +}
  413 +
  414 +/// \brief Save the current configuration to a file.
  415 +/// \return 0 on success, negative on error.
  416 +int OpenHantekMainWindow::save() {
  417 + if (currentFile.isEmpty())
  418 + return saveAs();
  419 + else
  420 + return writeSettings(currentFile);
  421 +}
  422 +
  423 +/// \brief Save the configuration to another filename.
  424 +/// \return 0 on success, 1 on user abort, negative on error.
  425 +int OpenHantekMainWindow::saveAs() {
  426 + QString fileName = QFileDialog::getSaveFileName(this, tr("Save settings"), "",
  427 + tr("Settings (*.ini)"));
  428 + if (fileName.isEmpty())
  429 + return 1;
  430 +
  431 + int status = writeSettings(fileName);
  432 +
  433 + if (status == 0)
  434 + currentFile = fileName;
  435 +
  436 + return status;
  437 +}
  438 +
  439 +/// \brief The oscilloscope started sampling.
  440 +void OpenHantekMainWindow::started() {
  441 + startStopAction->setText(tr("&Stop"));
  442 + startStopAction->setIcon(QIcon(":actions/stop.png"));
  443 + startStopAction->setStatusTip(tr("Stop the oscilloscope"));
  444 +
  445 + disconnect(startStopAction, SIGNAL(triggered()), dsoControl.get(),
  446 + SLOT(startSampling()));
  447 + connect(startStopAction, SIGNAL(triggered()), dsoControl.get(),
  448 + SLOT(stopSampling()));
  449 +}
  450 +
  451 +/// \brief The oscilloscope stopped sampling.
  452 +void OpenHantekMainWindow::stopped() {
  453 + startStopAction->setText(tr("&Start"));
  454 + startStopAction->setIcon(QIcon(":actions/start.png"));
  455 + startStopAction->setStatusTip(tr("Start the oscilloscope"));
  456 +
  457 + disconnect(startStopAction, SIGNAL(triggered()), dsoControl.get(),
  458 + SLOT(stopSampling()));
  459 + connect(startStopAction, SIGNAL(triggered()), dsoControl.get(),
  460 + SLOT(startSampling()));
  461 +}
  462 +
  463 +/// \brief Configure the oscilloscope.
  464 +void OpenHantekMainWindow::config() {
  465 + updateSettings();
  466 +
  467 + DsoConfigDialog configDialog(settings, this);
  468 + if (configDialog.exec() == QDialog::Accepted)
  469 + settingsChanged();
  470 +}
  471 +
  472 +/// \brief Enable/disable digital phosphor.
  473 +void OpenHantekMainWindow::digitalPhosphor(bool enabled) {
  474 + settings->view.digitalPhosphor = enabled;
  475 +
  476 + if (settings->view.digitalPhosphor)
  477 + digitalPhosphorAction->setStatusTip(
  478 + tr("Disable fading of previous graphs"));
  479 + else
  480 + digitalPhosphorAction->setStatusTip(
  481 + tr("Enable fading of previous graphs"));
  482 +}
  483 +
  484 +/// \brief Show/hide the magnified scope.
  485 +void OpenHantekMainWindow::zoom(bool enabled) {
  486 + settings->view.zoom = enabled;
  487 +
  488 + if (settings->view.zoom)
  489 + zoomAction->setStatusTip(tr("Hide magnified scope"));
  490 + else
  491 + zoomAction->setStatusTip(tr("Show magnified scope"));
  492 +}
  493 +
  494 +/// \brief Show the about dialog.
  495 +void OpenHantekMainWindow::about() {
  496 + QMessageBox::about(
  497 + this, tr("About OpenHantek %1").arg(VERSION),
  498 + tr("<p>This is a open source software for Hantek USB oscilloscopes.</p>"
  499 + "<p>Copyright &copy; 2010, 2011 Oliver Haag "
  500 + "&lt;oliver.haag@gmail.com&gt;</p>"));
  501 +}
  502 +
  503 +/// \brief The settings have changed.
  504 +void OpenHantekMainWindow::applySettings() {
  505 + addDockWidget(Qt::RightDockWidgetArea, horizontalDock);
  506 + addDockWidget(Qt::RightDockWidgetArea, triggerDock);
  507 + addDockWidget(Qt::RightDockWidgetArea, voltageDock);
  508 + addDockWidget(Qt::RightDockWidgetArea, spectrumDock);
  509 +
  510 + addToolBar(fileToolBar);
  511 + addToolBar(oscilloscopeToolBar);
  512 + addToolBar(viewToolBar);
  513 +
  514 + restoreGeometry(settings->mainWindowGeometry);
  515 + restoreState(settings->mainWindowState);
  516 +}
  517 +
  518 +/// \brief Update the window layout in the settings.
  519 +void OpenHantekMainWindow::updateSettings() {
  520 + // Main window
  521 + settings->mainWindowGeometry = saveGeometry();
  522 + settings->mainWindowState = saveState();
  523 +}
  524 +
  525 +/// \brief The oscilloscope changed the record time.
  526 +/// \param duration The new record time duration in seconds.
  527 +void OpenHantekMainWindow::recordTimeChanged(double duration) {
  528 + if (settings->scope.horizontal.samplerateSet &&
  529 + settings->scope.horizontal.recordLength != UINT_MAX) {
  530 + // The samplerate was set, let's adapt the timebase accordingly
  531 + settings->scope.horizontal.timebase =
  532 + horizontalDock->setTimebase(duration / DIVS_TIME);
  533 + }
  534 +
  535 + // The trigger position should be kept at the same place but the timebase has
  536 + // changed
  537 + dsoControl->setPretriggerPosition(
  538 + settings->scope.trigger.position *
  539 + settings->scope.horizontal.timebase * DIVS_TIME);
  540 +
  541 + dsoWidget->updateTimebase(settings->scope.horizontal.timebase);
  542 +}
  543 +
  544 +/// \brief The oscilloscope changed the samplerate.
  545 +/// \param samplerate The new samplerate in samples per second.
  546 +void OpenHantekMainWindow::samplerateChanged(double samplerate) {
  547 + if (!settings->scope.horizontal.samplerateSet &&
  548 + settings->scope.horizontal.recordLength != UINT_MAX) {
  549 + // The timebase was set, let's adapt the samplerate accordingly
  550 + settings->scope.horizontal.samplerate = samplerate;
  551 + horizontalDock->setSamplerate(samplerate);
  552 + }
  553 +
  554 + dsoWidget->updateSamplerate(samplerate);
  555 +}
  556 +
  557 +/// \brief Apply new record length to settings.
  558 +/// \param recordLength The selected record length in samples.
  559 +void OpenHantekMainWindow::recordLengthSelected(unsigned long recordLength) {
  560 + dsoControl->setRecordLength(recordLength);
  561 +}
  562 +
  563 +/// \brief Sets the samplerate of the oscilloscope.
  564 +void OpenHantekMainWindow::samplerateSelected() {
  565 + dsoControl->setSamplerate(settings->scope.horizontal.samplerate);
  566 +}
  567 +
  568 +/// \brief Sets the record time of the oscilloscope.
  569 +void OpenHantekMainWindow::timebaseSelected() {
  570 + dsoControl->setRecordTime(settings->scope.horizontal.timebase *
  571 + DIVS_TIME);
  572 + dsoWidget->updateTimebase(settings->scope.horizontal.timebase);
  573 +}
  574 +
  575 +/// \brief Sets the offset of the oscilloscope for the given channel.
  576 +/// \param channel The channel that got a new offset.
  577 +void OpenHantekMainWindow::updateOffset(unsigned int channel) {
  578 + if (channel >= settings->scope.physicalChannels)
  579 + return;
  580 +
  581 + dsoControl->setOffset(
  582 + channel,
  583 + (settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
  584 +}
  585 +
  586 +/// \brief Sets the state of the given oscilloscope channel.
  587 +/// \param channel The channel whose state has changed.
  588 +void OpenHantekMainWindow::updateUsed(unsigned int channel) {
  589 + if (channel >= (unsigned int)settings->scope.voltage.count())
  590 + return;
  591 +
  592 + bool mathUsed =
  593 + settings->scope.voltage[settings->scope.physicalChannels]
  594 + .used |
  595 + settings->scope.spectrum[settings->scope.physicalChannels]
  596 + .used;
  597 +
  598 + // Normal channel, check if voltage/spectrum or math channel is used
  599 + if (channel < settings->scope.physicalChannels)
  600 + dsoControl->setChannelUsed(
  601 + channel, mathUsed | settings->scope.voltage[channel].used |
  602 + settings->scope.spectrum[channel].used);
  603 + // Math channel, update all channels
  604 + else if (channel == settings->scope.physicalChannels) {
  605 + for (unsigned int channelCounter = 0;
  606 + channelCounter < settings->scope.physicalChannels;
  607 + ++channelCounter)
  608 + dsoControl->setChannelUsed(
  609 + channelCounter,
  610 + mathUsed | settings->scope.voltage[channelCounter].used |
  611 + settings->scope.spectrum[channelCounter].used);
  612 + }
  613 +}
  614 +
  615 +/// \brief Sets the gain of the oscilloscope for the given channel.
  616 +/// \param channel The channel that got a new gain value.
  617 +void OpenHantekMainWindow::updateVoltageGain(unsigned int channel) {
  618 + if (channel >= settings->scope.physicalChannels)
  619 + return;
  620 +
  621 + dsoControl->setGain(
  622 + channel, settings->scope.voltage[channel].gain * DIVS_VOLTAGE);
  623 +}
  624 +
  625 +#ifdef DEBUG
  626 +/// \brief Send the command in the commandEdit to the oscilloscope.
  627 +void OpenHantekMainWindow::sendCommand() {
  628 + int errorCode = dsoControl->stringCommand(commandEdit->text());
  629 +
  630 + commandEdit->hide();
  631 + commandEdit->clear();
  632 +
  633 + if (errorCode < 0)
  634 + statusBar()->showMessage(tr("Invalid command"), 3000);
  635 +}
  636 +#endif
... ...
openhantek/src/openhantek.h renamed to openhantek/src/mainwindow.h
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file openhantek.h
5   -/// \brief Declares the HantekDsoMainWindow class.
6   -//
7   -// Copyright (C) 2010, 2011 Oliver Haag
8   -// oliver.haag@gmail.com
9   -//
10   -// This program is free software: you can redistribute it and/or modify it
11   -// under the terms of the GNU General Public License as published by the Free
12   -// Software Foundation, either version 3 of the License, or (at your option)
13   -// any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful, but WITHOUT
16   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18   -// more details.
19   -//
20   -// You should have received a copy of the GNU General Public License along with
21   -// this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -////////////////////////////////////////////////////////////////////////////////
  1 +// SPDX-License-Identifier: GPL-2.0+
24 2  
25   -#ifndef HANTEKDSO_H
26   -#define HANTEKDSO_H
  3 +#pragma once
27 4  
28 5 #include <QMainWindow>
29 6 #include <QTimer>
  7 +#include <memory>
30 8  
31 9 class QActionGroup;
32 10 class QLineEdit;
33 11  
34 12 class DataAnalyzer;
35   -class DsoControl;
  13 +class HantekDsoControl;
36 14 class DsoSettings;
37 15 class DsoWidget;
38 16 class HorizontalDock;
... ... @@ -49,8 +27,7 @@ class OpenHantekMainWindow : public QMainWindow {
49 27 Q_OBJECT
50 28  
51 29 public:
52   - OpenHantekMainWindow(QWidget *parent = 0, Qt::WindowFlags flags = 0);
53   - ~OpenHantekMainWindow();
  30 + OpenHantekMainWindow(std::shared_ptr<HantekDsoControl> dsoControl, std::shared_ptr<DataAnalyzer> dataAnalyser);
54 31  
55 32 protected:
56 33 void closeEvent(QCloseEvent *event);
... ... @@ -65,7 +42,7 @@ private:
65 42  
66 43 // Device management
67 44 void connectSignals();
68   - void initializeDevice();
  45 + void applySettingsToDevice();
69 46  
70 47 // Settings
71 48 int readSettings(const QString &fileName = QString());
... ... @@ -109,12 +86,9 @@ private:
109 86 QLineEdit *commandEdit;
110 87 #endif
111 88  
112   - // Timer for DsoControl thread
113   - QTimer *timer = new QTimer();
114   -
115 89 // Data handling classes
116   - DataAnalyzer *dataAnalyzer;
117   - DsoControl *dsoControl;
  90 + std::shared_ptr<HantekDsoControl> dsoControl;
  91 + std::shared_ptr<DataAnalyzer> dataAnalyzer;
118 92  
119 93 // Other variables
120 94 QString currentFile;
... ... @@ -158,5 +132,3 @@ signals:
158 132 void
159 133 settingsChanged(); ///< The settings have changed (Option dialog, loading...)
160 134 };
161   -
162   -#endif
... ...
openhantek/src/openhantek.cpp deleted
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// openhantek.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   -////////////////////////////////////////////////////////////////////////////////
23   -
24   -#include <QAction>
25   -#include <QActionGroup>
26   -#include <QApplication>
27   -#include <QDir>
28   -#include <QFileDialog>
29   -#include <QMainWindow>
30   -#include <QMenu>
31   -#include <QMenuBar>
32   -#include <QMessageBox>
33   -#include <QStatusBar>
34   -#include <QToolBar>
35   -
36   -#include "openhantek.h"
37   -
38   -#include "configdialog.h"
39   -#include "dataanalyzer.h"
40   -#include "dockwindows.h"
41   -#include "dsocontrol.h"
42   -#include "dsowidget.h"
43   -#include "hantek/control.h"
44   -#include "settings.h"
45   -
46   -////////////////////////////////////////////////////////////////////////////////
47   -// class OpenHantekMainWindow
48   -/// \brief Initializes the gui elements of the main window.
49   -/// \param parent The parent widget.
50   -/// \param flags Flags for the window manager.
51   -OpenHantekMainWindow::OpenHantekMainWindow(QWidget *parent,
52   - Qt::WindowFlags flags)
53   - : QMainWindow(parent, flags) {
54   - // Set application information
55   - QCoreApplication::setOrganizationName("paranoiacs.net");
56   - QCoreApplication::setOrganizationDomain("paranoiacs.net");
57   - QCoreApplication::setApplicationName("OpenHantek");
58   -
59   - // Window title
60   - this->setWindowIcon(QIcon(":openhantek.png"));
61   - this->setWindowTitle(tr("OpenHantek"));
62   -
63   - // Create the controller for the oscilloscope, provides channel count for
64   - // settings
65   - this->dsoControl = new Hantek::Control(timer);
66   - connect(timer, SIGNAL(timeout()), dsoControl, SLOT(handler()),
67   - Qt::DirectConnection);
68   - timer->moveToThread(dsoControl);
69   -
70   - // Application settings
71   - this->settings = new DsoSettings();
72   - this->settings->setChannelCount(this->dsoControl->getChannelCount());
73   - this->readSettings();
74   -
75   - // Create dock windows before the dso widget, they fix messed up settings
76   - this->createDockWindows();
77   -
78   - // The data analyzer
79   - this->dataAnalyzer = new DataAnalyzer(this->settings);
80   -
81   - // Central oszilloscope widget
82   - this->dsoWidget = new DsoWidget(this->settings, this->dataAnalyzer);
83   - this->setCentralWidget(this->dsoWidget);
84   -
85   - // Subroutines for window elements
86   - this->createActions();
87   - this->createToolBars();
88   - this->createMenus();
89   - this->createStatusBar();
90   -
91   - // Apply the settings after the gui is initialized
92   - this->applySettings();
93   -
94   - // Connect all signals
95   - this->connectSignals();
96   -
97   - // Set up the oscilloscope
98   - this->dsoControl->connectDevice();
99   - this->initializeDevice();
100   - this->dsoControl->startSampling();
101   -}
102   -
103   -/// \brief Cleans up the main window.
104   -OpenHantekMainWindow::~OpenHantekMainWindow() {}
105   -
106   -/// \brief Save the settings before exiting.
107   -/// \param event The close event that should be handled.
108   -void OpenHantekMainWindow::closeEvent(QCloseEvent *event) {
109   - if (this->settings->options.alwaysSave)
110   - this->writeSettings();
111   -
112   - QMainWindow::closeEvent(event);
113   -}
114   -
115   -/// \brief Create the used actions.
116   -void OpenHantekMainWindow::createActions() {
117   - this->openAction =
118   - new QAction(QIcon(":actions/open.png"), tr("&Open..."), this);
119   - this->openAction->setShortcut(tr("Ctrl+O"));
120   - this->openAction->setStatusTip(tr("Open saved settings"));
121   - connect(this->openAction, SIGNAL(triggered()), this, SLOT(open()));
122   -
123   - this->saveAction = new QAction(QIcon(":actions/save.png"), tr("&Save"), this);
124   - this->saveAction->setShortcut(tr("Ctrl+S"));
125   - this->saveAction->setStatusTip(tr("Save the current settings"));
126   - connect(this->saveAction, SIGNAL(triggered()), this, SLOT(save()));
127   -
128   - this->saveAsAction =
129   - new QAction(QIcon(":actions/save-as.png"), tr("Save &as..."), this);
130   - this->saveAsAction->setStatusTip(
131   - tr("Save the current settings to another file"));
132   - connect(this->saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));
133   -
134   - this->printAction =
135   - new QAction(QIcon(":actions/print.png"), tr("&Print..."), this);
136   - this->printAction->setShortcut(tr("Ctrl+P"));
137   - this->printAction->setStatusTip(tr("Print the oscilloscope screen"));
138   - connect(this->printAction, SIGNAL(triggered()), this->dsoWidget,
139   - SLOT(print()));
140   -
141   - this->exportAsAction =
142   - new QAction(QIcon(":actions/export-as.png"), tr("&Export as..."), this);
143   - this->exportAsAction->setShortcut(tr("Ctrl+E"));
144   - this->exportAsAction->setStatusTip(
145   - tr("Export the oscilloscope data to a file"));
146   - connect(this->exportAsAction, SIGNAL(triggered()), this->dsoWidget,
147   - SLOT(exportAs()));
148   -
149   - this->exitAction = new QAction(tr("E&xit"), this);
150   - this->exitAction->setShortcut(tr("Ctrl+Q"));
151   - this->exitAction->setStatusTip(tr("Exit the application"));
152   - connect(this->exitAction, SIGNAL(triggered()), this, SLOT(close()));
153   -
154   - this->configAction = new QAction(tr("&Settings"), this);
155   - this->configAction->setShortcut(tr("Ctrl+S"));
156   - this->configAction->setStatusTip(tr("Configure the oscilloscope"));
157   - connect(this->configAction, SIGNAL(triggered()), this, SLOT(config()));
158   -
159   - this->startStopAction = new QAction(this);
160   - this->startStopAction->setShortcut(tr("Space"));
161   - this->stopped();
162   -
163   - this->digitalPhosphorAction = new QAction(
164   - QIcon(":actions/digitalphosphor.png"), tr("Digital &phosphor"), this);
165   - this->digitalPhosphorAction->setCheckable(true);
166   - this->digitalPhosphorAction->setChecked(this->settings->view.digitalPhosphor);
167   - this->digitalPhosphor(this->settings->view.digitalPhosphor);
168   - connect(this->digitalPhosphorAction, SIGNAL(toggled(bool)), this,
169   - SLOT(digitalPhosphor(bool)));
170   -
171   - this->zoomAction = new QAction(QIcon(":actions/zoom.png"), tr("&Zoom"), this);
172   - this->zoomAction->setCheckable(true);
173   - this->zoomAction->setChecked(this->settings->view.zoom);
174   - this->zoom(this->settings->view.zoom);
175   - connect(this->zoomAction, SIGNAL(toggled(bool)), this, SLOT(zoom(bool)));
176   - connect(this->zoomAction, SIGNAL(toggled(bool)), this->dsoWidget,
177   - SLOT(updateZoom(bool)));
178   -
179   - this->aboutAction = new QAction(tr("&About"), this);
180   - this->aboutAction->setStatusTip(tr("Show information about this program"));
181   - connect(this->aboutAction, SIGNAL(triggered()), this, SLOT(about()));
182   -
183   - this->aboutQtAction = new QAction(tr("About &Qt"), this);
184   - this->aboutQtAction->setStatusTip(tr("Show the Qt library's About box"));
185   - connect(this->aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
186   -
187   -#ifdef DEBUG
188   - this->commandAction = new QAction(tr("Send command"), this);
189   - this->commandAction->setShortcut(tr("Shift+C"));
190   -#endif
191   -}
192   -
193   -/// \brief Create the menus and menuitems.
194   -void OpenHantekMainWindow::createMenus() {
195   - this->fileMenu = this->menuBar()->addMenu(tr("&File"));
196   - this->fileMenu->addAction(this->openAction);
197   - this->fileMenu->addAction(this->saveAction);
198   - this->fileMenu->addAction(this->saveAsAction);
199   - this->fileMenu->addSeparator();
200   - this->fileMenu->addAction(this->printAction);
201   - this->fileMenu->addAction(this->exportAsAction);
202   - this->fileMenu->addSeparator();
203   - this->fileMenu->addAction(this->exitAction);
204   -
205   - this->viewMenu = this->menuBar()->addMenu(tr("&View"));
206   - this->viewMenu->addAction(this->digitalPhosphorAction);
207   - this->viewMenu->addAction(this->zoomAction);
208   - this->viewMenu->addSeparator();
209   - this->dockMenu = this->viewMenu->addMenu(tr("&Docking windows"));
210   - this->dockMenu->addAction(this->horizontalDock->toggleViewAction());
211   - this->dockMenu->addAction(this->spectrumDock->toggleViewAction());
212   - this->dockMenu->addAction(this->triggerDock->toggleViewAction());
213   - this->dockMenu->addAction(this->voltageDock->toggleViewAction());
214   - this->toolbarMenu = this->viewMenu->addMenu(tr("&Toolbars"));
215   - this->toolbarMenu->addAction(this->fileToolBar->toggleViewAction());
216   - this->toolbarMenu->addAction(this->oscilloscopeToolBar->toggleViewAction());
217   - this->toolbarMenu->addAction(this->viewToolBar->toggleViewAction());
218   -
219   - this->oscilloscopeMenu = this->menuBar()->addMenu(tr("&Oscilloscope"));
220   - this->oscilloscopeMenu->addAction(this->configAction);
221   - this->oscilloscopeMenu->addSeparator();
222   - this->oscilloscopeMenu->addAction(this->startStopAction);
223   -#ifdef DEBUG
224   - this->oscilloscopeMenu->addSeparator();
225   - this->oscilloscopeMenu->addAction(this->commandAction);
226   -#endif
227   -
228   - this->menuBar()->addSeparator();
229   -
230   - this->helpMenu = this->menuBar()->addMenu(tr("&Help"));
231   - this->helpMenu->addAction(this->aboutAction);
232   - this->helpMenu->addAction(this->aboutQtAction);
233   -}
234   -
235   -namespace {
236   -
237   -QToolBar* CreateToolBar(const QString& title) {
238   - QToolBar* newObj = new QToolBar(title);
239   - newObj->setObjectName(title);
240   - newObj->setAllowedAreas(Qt::TopToolBarArea | Qt::LeftToolBarArea);
241   - return newObj;
242   -}
243   -
244   -}
245   -
246   -/// \brief Create the toolbars and their buttons.
247   -void OpenHantekMainWindow::createToolBars() {
248   -
249   - // File
250   - this->fileToolBar = CreateToolBar(tr("File"));
251   - this->fileToolBar->addAction(this->openAction);
252   - this->fileToolBar->addAction(this->saveAction);
253   - this->fileToolBar->addAction(this->saveAsAction);
254   - this->fileToolBar->addSeparator();
255   - this->fileToolBar->addAction(this->printAction);
256   - this->fileToolBar->addAction(this->exportAsAction);
257   -
258   - // Oscilloscope
259   - this->oscilloscopeToolBar = CreateToolBar(tr("Oscilloscope"));
260   - this->oscilloscopeToolBar->addAction(this->startStopAction);
261   -
262   - // View
263   - this->viewToolBar = CreateToolBar(tr("View"));
264   - this->viewToolBar->addAction(this->digitalPhosphorAction);
265   - this->viewToolBar->addAction(this->zoomAction);
266   -}
267   -
268   -/// \brief Create the status bar.
269   -void OpenHantekMainWindow::createStatusBar() {
270   -#ifdef DEBUG
271   - // Command field inside the status bar
272   - this->commandEdit = new QLineEdit();
273   - this->commandEdit->hide();
274   -
275   - this->statusBar()->addPermanentWidget(this->commandEdit, 1);
276   -#endif
277   -
278   - this->statusBar()->showMessage(tr("Ready"));
279   -
280   -#ifdef DEBUG
281   - connect(this->commandAction, SIGNAL(triggered()), this->commandEdit,
282   - SLOT(show()));
283   - connect(this->commandAction, SIGNAL(triggered()), this->commandEdit,
284   - SLOT(setFocus()));
285   - connect(this->commandEdit, SIGNAL(returnPressed()), this,
286   - SLOT(sendCommand()));
287   -#endif
288   -}
289   -
290   -/// \brief Create all docking windows.
291   -void OpenHantekMainWindow::createDockWindows() {
292   - this->horizontalDock = new HorizontalDock(this->settings);
293   - this->triggerDock = new TriggerDock(
294   - this->settings, this->dsoControl->getSpecialTriggerSources());
295   - this->spectrumDock = new SpectrumDock(this->settings);
296   - this->voltageDock = new VoltageDock(this->settings);
297   -}
298   -
299   -/// \brief Connect general signals and device management signals.
300   -void OpenHantekMainWindow::connectSignals() {
301   - // Connect general signals
302   - connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
303   - // connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
304   - connect(this->dsoControl, SIGNAL(statusMessage(QString, int)),
305   - this->statusBar(), SLOT(showMessage(QString, int)));
306   - connect(this->dsoControl,
307   - SIGNAL(samplesAvailable(const std::vector<std::vector<double>> *,
308   - double, bool, QMutex *)),
309   - this->dataAnalyzer,
310   - SLOT(analyze(const std::vector<std::vector<double>> *, double, bool,
311   - QMutex *)));
312   -
313   - // Connect signals to DSO controller and widget
314   - connect(this->horizontalDock, SIGNAL(samplerateChanged(double)), this,
315   - SLOT(samplerateSelected()));
316   - connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this,
317   - SLOT(timebaseSelected()));
318   - connect(this->horizontalDock, SIGNAL(frequencybaseChanged(double)),
319   - this->dsoWidget, SLOT(updateFrequencybase(double)));
320   - connect(this->horizontalDock, SIGNAL(recordLengthChanged(unsigned long)),
321   - this, SLOT(recordLengthSelected(unsigned long)));
322   - // connect(this->horizontalDock, SIGNAL(formatChanged(HorizontalFormat)),
323   - // this->dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
324   -
325   - connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)),
326   - this->dsoControl, SLOT(setTriggerMode(Dso::TriggerMode)));
327   - connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)),
328   - this->dsoWidget, SLOT(updateTriggerMode()));
329   - connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)),
330   - this->dsoControl, SLOT(setTriggerSource(bool, unsigned int)));
331   - connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)),
332   - this->dsoWidget, SLOT(updateTriggerSource()));
333   - connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoControl,
334   - SLOT(setTriggerSlope(Dso::Slope)));
335   - connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoWidget,
336   - SLOT(updateTriggerSlope()));
337   - connect(this->dsoWidget, SIGNAL(triggerPositionChanged(double)),
338   - this->dsoControl, SLOT(setPretriggerPosition(double)));
339   - connect(this->dsoWidget, SIGNAL(triggerLevelChanged(unsigned int, double)),
340   - this->dsoControl, SLOT(setTriggerLevel(unsigned int, double)));
341   -
342   - connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this,
343   - SLOT(updateUsed(unsigned int)));
344   - connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)),
345   - this->dsoWidget, SLOT(updateVoltageUsed(unsigned int, bool)));
346   - connect(this->voltageDock,
347   - SIGNAL(couplingChanged(unsigned int, Dso::Coupling)),
348   - this->dsoControl, SLOT(setCoupling(unsigned int, Dso::Coupling)));
349   - connect(this->voltageDock,
350   - SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoWidget,
351   - SLOT(updateVoltageCoupling(unsigned int)));
352   - connect(this->voltageDock, SIGNAL(modeChanged(Dso::MathMode)),
353   - this->dsoWidget, SLOT(updateMathMode()));
354   - connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this,
355   - SLOT(updateVoltageGain(unsigned int)));
356   - connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)),
357   - this->dsoWidget, SLOT(updateVoltageGain(unsigned int)));
358   - connect(this->dsoWidget, SIGNAL(offsetChanged(unsigned int, double)), this,
359   - SLOT(updateOffset(unsigned int)));
360   -
361   - connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this,
362   - SLOT(updateUsed(unsigned int)));
363   - connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)),
364   - this->dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool)));
365   - connect(this->spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)),
366   - this->dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int)));
367   -
368   - // Started/stopped signals from oscilloscope
369   - connect(this->dsoControl, SIGNAL(samplingStarted()), this, SLOT(started()));
370   - connect(this->dsoControl, SIGNAL(samplingStopped()), this, SLOT(stopped()));
371   -
372   - // connect(this->dsoControl, SIGNAL(recordLengthChanged(unsigned long)), this,
373   - // SLOT(recordLengthChanged()));
374   - connect(this->dsoControl, SIGNAL(recordTimeChanged(double)), this,
375   - SLOT(recordTimeChanged(double)));
376   - connect(this->dsoControl, SIGNAL(samplerateChanged(double)), this,
377   - SLOT(samplerateChanged(double)));
378   -
379   - connect(this->dsoControl,
380   - SIGNAL(availableRecordLengthsChanged(QList<unsigned int>)),
381   - this->horizontalDock,
382   - SLOT(availableRecordLengthsChanged(QList<unsigned int>)));
383   - connect(this->dsoControl, SIGNAL(samplerateLimitsChanged(double, double)),
384   - this->horizontalDock, SLOT(samplerateLimitsChanged(double, double)));
385   - connect(this->dsoControl, SIGNAL(samplerateSet(int, QList<double>)),
386   - this->horizontalDock, SLOT(samplerateSet(int, QList<double>)));
387   -}
388   -
389   -/// \brief Initialize the device with the current settings.
390   -void OpenHantekMainWindow::initializeDevice() {
391   - for (unsigned int channel = 0;
392   - channel < this->settings->scope.physicalChannels; ++channel) {
393   - this->dsoControl->setCoupling(
394   - channel, (Dso::Coupling)this->settings->scope.voltage[channel].misc);
395   - this->updateVoltageGain(channel);
396   - this->updateOffset(channel);
397   - this->dsoControl->setTriggerLevel(
398   - channel, this->settings->scope.voltage[channel].trigger);
399   - }
400   - this->updateUsed(this->settings->scope.physicalChannels);
401   - if (this->settings->scope.horizontal.samplerateSet)
402   - this->samplerateSelected();
403   - else
404   - this->timebaseSelected();
405   - if (this->dsoControl->getAvailableRecordLengths()->isEmpty())
406   - this->dsoControl->setRecordLength(
407   - this->settings->scope.horizontal.recordLength);
408   - else {
409   - int index = this->dsoControl->getAvailableRecordLengths()->indexOf(
410   - this->settings->scope.horizontal.recordLength);
411   - this->dsoControl->setRecordLength(index < 0 ? 1 : index);
412   - }
413   - this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode);
414   - this->dsoControl->setPretriggerPosition(
415   - this->settings->scope.trigger.position *
416   - this->settings->scope.horizontal.timebase * DIVS_TIME);
417   - this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope);
418   - this->dsoControl->setTriggerSource(this->settings->scope.trigger.special,
419   - this->settings->scope.trigger.source);
420   -}
421   -
422   -/// \brief Read the settings from an ini file.
423   -/// \param fileName Optional filename to export the settings to a specific file.
424   -/// \return 0 on success, negative on error.
425   -int OpenHantekMainWindow::readSettings(const QString &fileName) {
426   - int status = this->settings->load(fileName);
427   -
428   - if (status == 0)
429   - emit(settingsChanged());
430   -
431   - return status;
432   -}
433   -
434   -/// \brief Save the settings to the harddisk.
435   -/// \param fileName Optional filename to read the settings from an ini file.
436   -/// \return 0 on success, negative on error.
437   -int OpenHantekMainWindow::writeSettings(const QString &fileName) {
438   - this->updateSettings();
439   -
440   - return this->settings->save(fileName);
441   -}
442   -
443   -/// \brief Open a configuration file.
444   -/// \return 0 on success, 1 on user abort, negative on error.
445   -int OpenHantekMainWindow::open() {
446   - QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"), "",
447   - tr("Settings (*.ini)"));
448   -
449   - if (!fileName.isEmpty())
450   - return this->readSettings(fileName);
451   - else
452   - return 1;
453   -}
454   -
455   -/// \brief Save the current configuration to a file.
456   -/// \return 0 on success, negative on error.
457   -int OpenHantekMainWindow::save() {
458   - if (this->currentFile.isEmpty())
459   - return saveAs();
460   - else
461   - return this->writeSettings(this->currentFile);
462   -}
463   -
464   -/// \brief Save the configuration to another filename.
465   -/// \return 0 on success, 1 on user abort, negative on error.
466   -int OpenHantekMainWindow::saveAs() {
467   - QString fileName = QFileDialog::getSaveFileName(this, tr("Save settings"), "",
468   - tr("Settings (*.ini)"));
469   - if (fileName.isEmpty())
470   - return 1;
471   -
472   - int status = this->writeSettings(fileName);
473   -
474   - if (status == 0)
475   - this->currentFile = fileName;
476   -
477   - return status;
478   -}
479   -
480   -/// \brief The oscilloscope started sampling.
481   -void OpenHantekMainWindow::started() {
482   - this->startStopAction->setText(tr("&Stop"));
483   - this->startStopAction->setIcon(QIcon(":actions/stop.png"));
484   - this->startStopAction->setStatusTip(tr("Stop the oscilloscope"));
485   -
486   - disconnect(this->startStopAction, SIGNAL(triggered()), this->dsoControl,
487   - SLOT(startSampling()));
488   - connect(this->startStopAction, SIGNAL(triggered()), this->dsoControl,
489   - SLOT(stopSampling()));
490   -}
491   -
492   -/// \brief The oscilloscope stopped sampling.
493   -void OpenHantekMainWindow::stopped() {
494   - this->startStopAction->setText(tr("&Start"));
495   - this->startStopAction->setIcon(QIcon(":actions/start.png"));
496   - this->startStopAction->setStatusTip(tr("Start the oscilloscope"));
497   -
498   - disconnect(this->startStopAction, SIGNAL(triggered()), this->dsoControl,
499   - SLOT(stopSampling()));
500   - connect(this->startStopAction, SIGNAL(triggered()), this->dsoControl,
501   - SLOT(startSampling()));
502   -}
503   -
504   -/// \brief Configure the oscilloscope.
505   -void OpenHantekMainWindow::config() {
506   - this->updateSettings();
507   -
508   - DsoConfigDialog configDialog(this->settings, this);
509   - if (configDialog.exec() == QDialog::Accepted)
510   - this->settingsChanged();
511   -}
512   -
513   -/// \brief Enable/disable digital phosphor.
514   -void OpenHantekMainWindow::digitalPhosphor(bool enabled) {
515   - this->settings->view.digitalPhosphor = enabled;
516   -
517   - if (this->settings->view.digitalPhosphor)
518   - this->digitalPhosphorAction->setStatusTip(
519   - tr("Disable fading of previous graphs"));
520   - else
521   - this->digitalPhosphorAction->setStatusTip(
522   - tr("Enable fading of previous graphs"));
523   -}
524   -
525   -/// \brief Show/hide the magnified scope.
526   -void OpenHantekMainWindow::zoom(bool enabled) {
527   - this->settings->view.zoom = enabled;
528   -
529   - if (this->settings->view.zoom)
530   - this->zoomAction->setStatusTip(tr("Hide magnified scope"));
531   - else
532   - this->zoomAction->setStatusTip(tr("Show magnified scope"));
533   -}
534   -
535   -/// \brief Show the about dialog.
536   -void OpenHantekMainWindow::about() {
537   - QMessageBox::about(
538   - this, tr("About OpenHantek %1").arg(VERSION),
539   - tr("<p>This is a open source software for Hantek USB oscilloscopes.</p>"
540   - "<p>Copyright &copy; 2010, 2011 Oliver Haag "
541   - "&lt;oliver.haag@gmail.com&gt;</p>"));
542   -}
543   -
544   -/// \brief The settings have changed.
545   -void OpenHantekMainWindow::applySettings() {
546   - addDockWidget(Qt::RightDockWidgetArea, horizontalDock);
547   - addDockWidget(Qt::RightDockWidgetArea, triggerDock);
548   - addDockWidget(Qt::RightDockWidgetArea, voltageDock);
549   - addDockWidget(Qt::RightDockWidgetArea, spectrumDock);
550   -
551   - addToolBar(fileToolBar);
552   - addToolBar(oscilloscopeToolBar);
553   - addToolBar(viewToolBar);
554   -
555   - restoreGeometry(settings->mainWindowGeometry);
556   - restoreState(settings->mainWindowState);
557   -}
558   -
559   -/// \brief Update the window layout in the settings.
560   -void OpenHantekMainWindow::updateSettings() {
561   - // Main window
562   - settings->mainWindowGeometry = saveGeometry();
563   - settings->mainWindowState = saveState();
564   -}
565   -
566   -/// \brief The oscilloscope changed the record time.
567   -/// \param duration The new record time duration in seconds.
568   -void OpenHantekMainWindow::recordTimeChanged(double duration) {
569   - if (this->settings->scope.horizontal.samplerateSet &&
570   - this->settings->scope.horizontal.recordLength != UINT_MAX) {
571   - // The samplerate was set, let's adapt the timebase accordingly
572   - this->settings->scope.horizontal.timebase =
573   - this->horizontalDock->setTimebase(duration / DIVS_TIME);
574   - }
575   -
576   - // The trigger position should be kept at the same place but the timebase has
577   - // changed
578   - this->dsoControl->setPretriggerPosition(
579   - this->settings->scope.trigger.position *
580   - this->settings->scope.horizontal.timebase * DIVS_TIME);
581   -
582   - this->dsoWidget->updateTimebase(this->settings->scope.horizontal.timebase);
583   -}
584   -
585   -/// \brief The oscilloscope changed the samplerate.
586   -/// \param samplerate The new samplerate in samples per second.
587   -void OpenHantekMainWindow::samplerateChanged(double samplerate) {
588   - if (!this->settings->scope.horizontal.samplerateSet &&
589   - this->settings->scope.horizontal.recordLength != UINT_MAX) {
590   - // The timebase was set, let's adapt the samplerate accordingly
591   - this->settings->scope.horizontal.samplerate = samplerate;
592   - this->horizontalDock->setSamplerate(samplerate);
593   - }
594   -
595   - this->dsoWidget->updateSamplerate(samplerate);
596   -}
597   -
598   -/// \brief Apply new record length to settings.
599   -/// \param recordLength The selected record length in samples.
600   -void OpenHantekMainWindow::recordLengthSelected(unsigned long recordLength) {
601   - this->dsoControl->setRecordLength(recordLength);
602   -}
603   -
604   -/// \brief Sets the samplerate of the oscilloscope.
605   -void OpenHantekMainWindow::samplerateSelected() {
606   - this->dsoControl->setSamplerate(this->settings->scope.horizontal.samplerate);
607   -}
608   -
609   -/// \brief Sets the record time of the oscilloscope.
610   -void OpenHantekMainWindow::timebaseSelected() {
611   - this->dsoControl->setRecordTime(this->settings->scope.horizontal.timebase *
612   - DIVS_TIME);
613   - this->dsoWidget->updateTimebase(settings->scope.horizontal.timebase);
614   -}
615   -
616   -/// \brief Sets the offset of the oscilloscope for the given channel.
617   -/// \param channel The channel that got a new offset.
618   -void OpenHantekMainWindow::updateOffset(unsigned int channel) {
619   - if (channel >= this->settings->scope.physicalChannels)
620   - return;
621   -
622   - this->dsoControl->setOffset(
623   - channel,
624   - (this->settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
625   -}
626   -
627   -/// \brief Sets the state of the given oscilloscope channel.
628   -/// \param channel The channel whose state has changed.
629   -void OpenHantekMainWindow::updateUsed(unsigned int channel) {
630   - if (channel >= (unsigned int)this->settings->scope.voltage.count())
631   - return;
632   -
633   - bool mathUsed =
634   - this->settings->scope.voltage[this->settings->scope.physicalChannels]
635   - .used |
636   - this->settings->scope.spectrum[this->settings->scope.physicalChannels]
637   - .used;
638   -
639   - // Normal channel, check if voltage/spectrum or math channel is used
640   - if (channel < this->settings->scope.physicalChannels)
641   - this->dsoControl->setChannelUsed(
642   - channel, mathUsed | this->settings->scope.voltage[channel].used |
643   - this->settings->scope.spectrum[channel].used);
644   - // Math channel, update all channels
645   - else if (channel == this->settings->scope.physicalChannels) {
646   - for (unsigned int channelCounter = 0;
647   - channelCounter < this->settings->scope.physicalChannels;
648   - ++channelCounter)
649   - this->dsoControl->setChannelUsed(
650   - channelCounter,
651   - mathUsed | this->settings->scope.voltage[channelCounter].used |
652   - this->settings->scope.spectrum[channelCounter].used);
653   - }
654   -}
655   -
656   -/// \brief Sets the gain of the oscilloscope for the given channel.
657   -/// \param channel The channel that got a new gain value.
658   -void OpenHantekMainWindow::updateVoltageGain(unsigned int channel) {
659   - if (channel >= this->settings->scope.physicalChannels)
660   - return;
661   -
662   - this->dsoControl->setGain(
663   - channel, this->settings->scope.voltage[channel].gain * DIVS_VOLTAGE);
664   -}
665   -
666   -#ifdef DEBUG
667   -/// \brief Send the command in the commandEdit to the oscilloscope.
668   -void OpenHantekMainWindow::sendCommand() {
669   - int errorCode = this->dsoControl->stringCommand(this->commandEdit->text());
670   -
671   - this->commandEdit->hide();
672   - this->commandEdit->clear();
673   -
674   - if (errorCode < 0)
675   - this->statusBar()->showMessage(tr("Invalid command"), 3000);
676   -}
677   -#endif
openhantek/src/settings.cpp
... ... @@ -27,7 +27,7 @@
27 27  
28 28 #include "settings.h"
29 29  
30   -#include "dso.h"
  30 +#include "definitions.h"
31 31 #include "dsowidget.h"
32 32  
33 33 ////////////////////////////////////////////////////////////////////////////////
... ...
openhantek/src/settings.h
... ... @@ -32,7 +32,7 @@
32 32 #include <QSize>
33 33 #include <QString>
34 34  
35   -#include "dso.h"
  35 +#include "definitions.h"
36 36  
37 37 ////////////////////////////////////////////////////////////////////////////////
38 38 /// \struct DsoSettingsOptions settings.h
... ...
openhantek/src/sispinbox.cpp
... ... @@ -26,7 +26,7 @@
26 26  
27 27 #include "sispinbox.h"
28 28  
29   -#include "helper.h"
  29 +#include "utils/printutils.h"
30 30  
31 31 ////////////////////////////////////////////////////////////////////////////////
32 32 // class OpenHantekMainWindow
... ... @@ -37,7 +37,7 @@ SiSpinBox::SiSpinBox(QWidget *parent) : QDoubleSpinBox(parent) { this-&gt;init(); }
37 37 /// \brief Initializes the SiSpinBox, allowing the user to choose the unit.
38 38 /// \param unit The unit shown for the value in the spin box.
39 39 /// \param parent The parent widget.
40   -SiSpinBox::SiSpinBox(Helper::Unit unit, QWidget *parent)
  40 +SiSpinBox::SiSpinBox(Unit unit, QWidget *parent)
41 41 : QDoubleSpinBox(parent) {
42 42 this->init();
43 43  
... ... @@ -55,7 +55,7 @@ QValidator::State SiSpinBox::validate(QString &amp;input, int &amp;pos) const {
55 55 Q_UNUSED(pos);
56 56  
57 57 bool ok;
58   - double value = Helper::stringToValue(input, this->unit, &ok);
  58 + double value = stringToValue(input, this->unit, &ok);
59 59  
60 60 if (!ok)
61 61 return QValidator::Invalid;
... ... @@ -69,21 +69,21 @@ QValidator::State SiSpinBox::validate(QString &amp;input, int &amp;pos) const {
69 69 /// \param text The content of the text box.
70 70 /// \return Value in base unit.
71 71 double SiSpinBox::valueFromText(const QString &text) const {
72   - return Helper::stringToValue(text, this->unit);
  72 + return stringToValue(text, this->unit);
73 73 }
74 74  
75 75 /// \brief Get string representation of value.
76 76 /// \param val Value in base unit.
77 77 /// \return String representation containing value and (prefix+)unit.
78 78 QString SiSpinBox::textFromValue(double val) const {
79   - return Helper::valueToString(val, this->unit, -1) + this->unitPostfix;
  79 + return valueToString(val, this->unit, -1) + this->unitPostfix;
80 80 }
81 81  
82 82 /// \brief Fixes the text after the user finished changing it.
83 83 /// \param input The content of the text box.
84 84 void SiSpinBox::fixup(QString &input) const {
85 85 bool ok;
86   - double value = Helper::stringToValue(input, this->unit, &ok);
  86 + double value = stringToValue(input, this->unit, &ok);
87 87  
88 88 if (!ok)
89 89 value = this->value();
... ... @@ -154,8 +154,8 @@ void SiSpinBox::stepBy(int steps) {
154 154 /// \brief Set the unit for this spin box.
155 155 /// \param unit The unit shown for the value in the spin box.
156 156 /// \return true on success, false on invalid unit.
157   -bool SiSpinBox::setUnit(Helper::Unit unit) {
158   - if ((unsigned int)unit >= Helper::UNIT_COUNT)
  157 +bool SiSpinBox::setUnit(Unit unit) {
  158 + if ((unsigned int)unit >= UNIT_COUNT)
159 159 return false;
160 160  
161 161 this->unit = unit;
... ...
openhantek/src/sispinbox.h
... ... @@ -28,7 +28,7 @@
28 28 #include <QDoubleSpinBox>
29 29 #include <QStringList>
30 30  
31   -#include "helper.h"
  31 +#include "utils/printutils.h"
32 32  
33 33 ////////////////////////////////////////////////////////////////////////////////
34 34 /// \class SiSpinBox sispinbox.h
... ... @@ -41,7 +41,7 @@ class SiSpinBox : public QDoubleSpinBox {
41 41  
42 42 public:
43 43 explicit SiSpinBox(QWidget *parent = 0);
44   - SiSpinBox(Helper::Unit unit, QWidget *parent = 0);
  44 + SiSpinBox(Unit unit, QWidget *parent = 0);
45 45 ~SiSpinBox();
46 46  
47 47 QValidator::State validate(QString &input, int &pos) const;
... ... @@ -49,7 +49,7 @@ public:
49 49 QString textFromValue(double val) const;
50 50 void fixup(QString &input) const;
51 51 void stepBy(int steps);
52   - bool setUnit(Helper::Unit unit);
  52 + bool setUnit(Unit unit);
53 53 void setUnitPostfix(const QString &postfix);
54 54 void setSteps(const QList<double> &steps);
55 55 void setMode(const int mode);
... ... @@ -57,7 +57,7 @@ public:
57 57 private:
58 58 void init();
59 59  
60   - Helper::Unit unit; ///< The SI unit used for this spin box
  60 + Unit unit; ///< The SI unit used for this spin box
61 61 QString unitPostfix; ///< Shown after the unit
62 62 QList<double> steps; ///< The steps, begins from start after last element
63 63 int mode; ///< The mode, fixed or constant
... ...
openhantek/src/utils/dataarray.cpp 0 โ†’ 100644
  1 +#include "dataarray.h"
... ...
openhantek/src/helper.h renamed to openhantek/src/utils/dataarray.h
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -/// \file helper.h
5   -/// \brief Provides miscellaneous helper functions.
6   -//
7   -// Copyright (C) 2010 Oliver Haag
8   -// oliver.haag@gmail.com
9   -//
10   -// This program is free software: you can redistribute it and/or modify it
11   -// under the terms of the GNU General Public License as published by the Free
12   -// Software Foundation, either version 3 of the License, or (at your option)
13   -// any later version.
14   -//
15   -// This program is distributed in the hope that it will be useful, but WITHOUT
16   -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17   -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18   -// more details.
19   -//
20   -// You should have received a copy of the GNU General Public License along with
21   -// this program. If not, see <http://www.gnu.org/licenses/>.
22   -//
23   -////////////////////////////////////////////////////////////////////////////////
  1 +// SPDX-License-Identifier: GPL-2.0+
24 2  
25   -#ifndef HELPER_H
26   -#define HELPER_H
  3 +#pragma once
27 4  
28   -#include <cerrno>
29   -
30   -#include <QString>
31   -#include <QTime>
32   -
33   -namespace Helper {
34   -//////////////////////////////////////////////////////////////////////////////
35   -/// \enum Unit helper.h
36   -/// \brief The various units supported by valueToString.
37   -enum Unit {
38   - UNIT_VOLTS,
39   - UNIT_DECIBEL,
40   - UNIT_SECONDS,
41   - UNIT_HERTZ,
42   - UNIT_SAMPLES,
43   - UNIT_COUNT
44   -};
45   -
46   -QString libUsbErrorString(int error);
47   -
48   -QString valueToString(double value, Unit unit, int precision = -1);
49   -double stringToValue(const QString &text, Unit unit, bool *ok = 0);
50   -
51   -#ifdef DEBUG
52   -QString hexDump(unsigned char *data, unsigned int length);
53   -unsigned int hexParse(const QString dump, unsigned char *data,
54   - unsigned int length);
55   -inline void timestampDebug(QString text);
56   -
57   -/// \brief Print debug information with timestamp.
58   -/// \param text Text that will be output via qDebug.
59   -inline void timestampDebug(QString text) {
60   - qDebug("%s: %s",
61   - QTime::currentTime().toString("hh:mm:ss.zzz").toLatin1().constData(),
62   - text.toLatin1().constData());
63   -}
64   -#endif
65   -
66   -//////////////////////////////////////////////////////////////////////////////
67   -/// \class DataArray helper.h
68 5 /// \brief A class template for a simple array with a fixed size.
69 6 template <class T> class DataArray {
70 7 public:
... ... @@ -108,7 +45,3 @@ template &lt;class T&gt; T DataArray&lt;T&gt;::operator[](unsigned int index) {
108 45 template <class T> unsigned int DataArray<T>::getSize() const {
109 46 return this->size;
110 47 }
111   -
112   -} // namespace Helper
113   -
114   -#endif
... ...
openhantek/src/dso.cpp renamed to openhantek/src/utils/dsoStrings.cpp
... ... @@ -23,7 +23,7 @@
23 23  
24 24 #include <QApplication>
25 25  
26   -#include "dso.h"
  26 +#include "definitions.h"
27 27  
28 28 namespace Dso {
29 29 /// \brief Return string representation of the given channel mode.
... ...
openhantek/src/utils/dsoStrings.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +#include <QString>
  5 +
  6 +#define MARKER_COUNT 2 ///< Number of markers
  7 +
  8 +/// \namespace Dso
  9 +/// \brief All DSO specific things for different modes and so on.
  10 +namespace Dso {
  11 +
  12 +QString channelModeString(ChannelMode mode);
  13 +QString graphFormatString(GraphFormat format);
  14 +QString couplingString(Coupling coupling);
  15 +QString mathModeString(MathMode mode);
  16 +QString triggerModeString(TriggerMode mode);
  17 +QString slopeString(Slope slope);
  18 +QString windowFunctionString(WindowFunction window);
  19 +QString interpolationModeString(InterpolationMode interpolation);
  20 +}
... ...
openhantek/src/helper.cpp renamed to openhantek/src/utils/printutils.cpp
1   -////////////////////////////////////////////////////////////////////////////////
2   -//
3   -// OpenHantek
4   -// helper.cpp
5   -//
6   -// Copyright (C) 2010 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 <cmath>
25 4  
... ... @@ -29,12 +8,9 @@
29 8  
30 9 #include <libusb-1.0/libusb.h>
31 10  
32   -#include "helper.h"
  11 +#include "utils/printutils.h"
  12 +
33 13  
34   -namespace Helper {
35   -/// \brief Returns string representation for libusb errors.
36   -/// \param error The error code.
37   -/// \return String explaining the error.
38 14 QString libUsbErrorString(int error) {
39 15 switch (error) {
40 16 case LIBUSB_SUCCESS:
... ... @@ -69,12 +45,6 @@ QString libUsbErrorString(int error) {
69 45 }
70 46 }
71 47  
72   -/// \brief Converts double to string containing value and (prefix+)unit
73   -/// (Counterpart to Helper::stringToValue).
74   -/// \param value The value in prefixless units.
75   -/// \param unit The unit for the value.
76   -/// \param precision Significant digits, 0 for integer, -1 for auto.
77   -/// \return String with the value and unit.
78 48 QString valueToString(double value, Unit unit, int precision) {
79 49 char format = (precision < 0) ? 'g' : 'f';
80 50  
... ... @@ -193,12 +163,6 @@ QString valueToString(double value, Unit unit, int precision) {
193 163 }
194 164 }
195 165  
196   -/// \brief Converts string containing value and (prefix+)unit to double
197   -/// (Counterpart to Helper::valueToString).
198   -/// \param text The text containing the value and its unit.
199   -/// \param unit The base unit of the value.
200   -/// \param ok Pointer to a success-flag, true on success, false on error.
201   -/// \return Decoded value.
202 166 double stringToValue(const QString &text, Unit unit, bool *ok) {
203 167 // Check if the text is empty
204 168 int totalSize = text.size();
... ... @@ -302,11 +266,6 @@ double stringToValue(const QString &amp;text, Unit unit, bool *ok) {
302 266 }
303 267 }
304 268  
305   -#ifdef DEBUG
306   -/// \brief Returns the hex dump for the given data.
307   -/// \param data Pointer to the data bytes that should be dumped.
308   -/// \param length The length of the data array in bytes.
309   -/// \return String with the hex dump of the data.
310 269 QString hexDump(unsigned char *data, unsigned int length) {
311 270 QString dumpString, byteString;
312 271  
... ... @@ -316,11 +275,6 @@ QString hexDump(unsigned char *data, unsigned int length) {
316 275 return dumpString;
317 276 }
318 277  
319   -/// \brief Returns the hex dump for the given data.
320   -/// \param dump The string with the hex dump of the data.
321   -/// \param data Pointer to the address where the data bytes should be saved.
322   -/// \param length The maximum length of the data array in bytes.
323   -/// \return The length of the saved data.
324 278 unsigned int hexParse(const QString dump, unsigned char *data,
325 279 unsigned int length) {
326 280 QString dumpString = dump;
... ... @@ -346,5 +300,3 @@ unsigned int hexParse(const QString dump, unsigned char *data,
346 300  
347 301 return index;
348 302 }
349   -#endif
350   -}
... ...
openhantek/src/utils/printutils.h 0 โ†’ 100644
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +
  3 +#pragma once
  4 +#include <cerrno>
  5 +
  6 +#include <QString>
  7 +#include <QTime>
  8 +
  9 +//////////////////////////////////////////////////////////////////////////////
  10 +/// \enum Unit utils/printutils.h
  11 +/// \brief The various units supported by valueToString.
  12 +enum Unit {
  13 + UNIT_VOLTS,
  14 + UNIT_DECIBEL,
  15 + UNIT_SECONDS,
  16 + UNIT_HERTZ,
  17 + UNIT_SAMPLES,
  18 + UNIT_COUNT
  19 +};
  20 +
  21 +/// \brief Returns string representation for libusb errors.
  22 +/// \param error The error code.
  23 +/// \return String explaining the error.
  24 +QString libUsbErrorString(int error);
  25 +
  26 +/// \brief Converts double to string containing value and (prefix+)unit
  27 +/// (Counterpart to stringToValue).
  28 +/// \param value The value in prefixless units.
  29 +/// \param unit The unit for the value.
  30 +/// \param precision Significant digits, 0 for integer, -1 for auto.
  31 +/// \return String with the value and unit.
  32 +QString valueToString(double value, Unit unit, int precision = -1);
  33 +
  34 +/// \brief Converts string containing value and (prefix+)unit to double
  35 +/// (Counterpart to valueToString).
  36 +/// \param text The text containing the value and its unit.
  37 +/// \param unit The base unit of the value.
  38 +/// \param ok Pointer to a success-flag, true on success, false on error.
  39 +/// \return Decoded value.
  40 +double stringToValue(const QString &text, Unit unit, bool *ok = 0);
  41 +
  42 +/// \brief Returns the hex dump for the given data.
  43 +/// \param data Pointer to the data bytes that should be dumped.
  44 +/// \param length The length of the data array in bytes.
  45 +/// \return String with the hex dump of the data.
  46 +QString hexDump(unsigned char *data, unsigned int length);
  47 +
  48 +/// \brief Returns the hex dump for the given data.
  49 +/// \param dump The string with the hex dump of the data.
  50 +/// \param data Pointer to the address where the data bytes should be saved.
  51 +/// \param length The maximum length of the data array in bytes.
  52 +/// \return The length of the saved data.
  53 +unsigned int hexParse(const QString dump, unsigned char *data, unsigned int length);
  54 +
  55 +/// \brief Print debug information with timestamp.
  56 +/// \param text Text that will be output via qDebug.
  57 +inline void timestampDebug(QString text) {
  58 + qDebug("%s: %s", QTime::currentTime().toString("hh:mm:ss.zzz").toLatin1().constData(), text.toLatin1().constData());
  59 +}
... ...
readme.md
... ... @@ -10,7 +10,7 @@ Supported operating systems:
10 10 <td> <img alt="Image of main window on linux" width="100%" src="doc/screenshot_mainwindow.png"> </td>
11 11 <td> <img alt="Image of main window on Windows" width="100%" src="doc/screenshot_mainwindow_win.png"> </td>
12 12 </tr></table>
13   -
  13 +
14 14 Supported hantek devices:
15 15 * DSO2xxx Series
16 16 * DSO52xx Series
... ... @@ -28,30 +28,31 @@ You need the following packages, to build OpenHantek from source:
28 28  
29 29 You need a OpenGL 3.x capable graphics card for OpenHantek.
30 30  
31   -### Install requirements on Linux
  31 +### Linux
32 32 For debian based systems (Ubuntu, Mint) install named requirements like this:
33 33 > apt install g++ cmake qttools5-dev qttools5-dev-tools libfftw3-dev binutils-dev libusb-1.0-0-dev libqt5opengl5-dev
34 34  
35 35 For rpm based distributions (Fedora) use this command:
36 36 > dnf install cmake gcc-c++ qt5-qtbase-gui qt5-qttools-devel qt5-qttranslations fftw-devel binutils-devel libusb-devel
37 37  
38   -### Install requirements on OSX
39   -For MacOSX use homebrew
40   -> brew update <br>
41   -> brew install libusb fftw qt5;
42   -
43   -### Build on Linux
44 38 After you've installed the requirements run the following commands inside the directory of this package:
45 39 > mkdir build <br>
46 40 > cd build <br>
47 41 > cmake ../ <br>
48 42 > make -j
49 43  
50   -Optionally install the program including a desktop icon:
  44 +Optionally install the program:
51 45  
52 46 > sudo make install
53 47  
54   -### Build on OSX
  48 +If you do not install the program, you need to copy the file `firmware/60-hantek.rules` to `/lib/udev/rules.d/`,
  49 +and reload the udev service, otherwise you will not have the correct permissions to access usb devices.
  50 +
  51 +### Apple MacOSX
  52 +We recommend homebrew to install the required libraries.
  53 +> brew update <br>
  54 +> brew install libusb fftw qt5;
  55 +
55 56 After you've installed the requirements run the following commands inside the directory of this package:
56 57 > mkdir build <br>
57 58 > cd build <br>
... ... @@ -61,13 +62,14 @@ After you&#39;ve installed the requirements run the following commands inside the di
61 62 Please adjust the path to Qt5. You can find the path with the command:
62 63 > brew info qt5
63 64  
64   -### Build on Windows
  65 +### Windows
65 66  
66   -Run the **CMake GUI** program and select the source directory, build directory and your compiler. If your compiler is for example Visual Studio, cmake will generate a Visual Studio Project and solution file (\*.sln). Open the project and build it. If you use an IDE that has inbuild support for cmake projects like QtCreator, you can just open and build this project.
  67 +Run the **CMake GUI** program and select the source directory, build directory and your compiler.
  68 +If your compiler is for example Visual Studio, cmake will generate a Visual Studio Project and solution file (\*.sln).
  69 +Open the project and build it. If you use an IDE that has inbuild support for cmake projects like QtCreator,
  70 +you can just open and build this project.
67 71  
68   -## Windows: Install driver
69   -
70   -While we don't need an installed driver on linux and MacOS X, we do need one on Windows systems.
  72 +Microsoft Windows needs an installed driver for every usb device:
71 73  
72 74 * Make sure your original Hantek driver is uninstalled.
73 75 * Extract `cmake/winusb driver.zip` and customize the `libusb_device.inf` file for your device. The Vendor ID and Device ID as well as a unique GUID need to be entered like in the following example for a Hantek 6022BE.
... ... @@ -90,28 +92,12 @@ Date = &quot;08/12/2017&quot;
90 92 ; =====================================================
91 93 ````
92 94  
93   -## Firmware (Linux and MacOS X)
94   -Your DSO does not store its firmware permanently -- the firmware has to be sent to the device each time it is connected. The `firmware` directory of this project contains the binary firmware extracted from Hantek's Windows drivers, and a udev rule to upload the firmware to the device automatically each time it is plugged in.
95   -
96   -* You need binutils-dev autoconf automake fxload
97   -* Install the `firmware/*.hex` files into `/usr/local/share/hantek/`.
98   -
99   -> mkdir -p /usr/local/share/hantek <br>
100   -> cp -r firmware/*.hex /usr/local/share/hantek/
101   -
102   -* Install the `firmware/90-hantek.rules` file into `/etc/udev/rules.d/`.
103   -
104   -> cp firmware/90-hantek.rules /etc/udev/rules.d/
105   -
106   -* install fxload (fxload is a program which downloads firmware to USB devices based on AnchorChips EZ-USB, Cypress EZ-USB FX, or Cypress EZ-USB FX2 microcontrollers.)
107   -
108   -> apt-get install fxload
109   -
110   -## 6022BE
  95 +## Special case: 6022BE
111 96 You can adjust samplerate and use software triggering for 6022BE.
112 97 - Support 48, 24, 16, 8, 4, 2, 1 M and 500, 200, 100 k Hz samplerates with modded firmware by [jhoenicke](https://github.com/rpcope1/Hantek6022API)
113   - - Support software trigger by detecting rising or falling edge of signal. Use software trigger item on the trigger menu. For trigger level, adjust left arrow on the right-side of the graph.
114   - - Note that the first few thousand samples are dropped due to unstable/unusual reading.
  98 + - Support software trigger by detecting rising or falling edge of signal.
  99 + Use software trigger item on the trigger menu. For trigger level, adjust left arrow on the right-side of the graph.
  100 + - Note that the first few samples are dropped due to unstable/unusual reading.
115 101  
116 102 ## Contribute
117 103 Please use Github Issues to report any problems or enhancements or send us pull requests. Some random notes:
... ...