Commit b7a65b8aa3c13848b49d366c07a5ec2e55d351de
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 "${CMAKE_CURRENT_LIST_DIR}/cmake/") |
| 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
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
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<std::vector<double>> *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<std::vector<double>> *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
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
openhantek/src/glscope.h
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<uint8_t>(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->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->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->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<uint8_t>(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<uint8_t>(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->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<uint8_t>(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<uint8_t>(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 © 2010, 2011 Oliver Haag " | |
| 500 | + "<oliver.haag@gmail.com></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 © 2010, 2011 Oliver Haag " | |
| 541 | - "<oliver.haag@gmail.com></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
openhantek/src/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->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 &input, int &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 &input, int &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 <class T> T DataArray<T>::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
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 &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'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 = "08/12/2017" |
| 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: | ... | ... |