diff --git a/CMakeLists.txt b/CMakeLists.txt index f119432..6a07ecf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,10 +18,11 @@ include(cmake/CPackInfos.cmake) # Qt Widgets based Gui with OpenGL canvas add_subdirectory(openhantek) -add_subdirectory(firmware EXCLUDE_FROM_ALL) if (WIN32) install(FILES COPYING readme.md DESTINATION ".") +else() + add_subdirectory(firmware EXCLUDE_FROM_ALL) endif() if("${CMAKE_SYSTEM}" MATCHES "Linux") diff --git a/openhantek/CMakeLists.txt b/openhantek/CMakeLists.txt index 2c39da3..3614a50 100644 --- a/openhantek/CMakeLists.txt +++ b/openhantek/CMakeLists.txt @@ -19,6 +19,7 @@ include_directories(src/ src/hantekdso src/widgets src/docks src/configdialog) # collect sources and other files file(GLOB_RECURSE SRC "src/*.cpp") file(GLOB_RECURSE HEADERS "src/*.h") +file(GLOB_RECURSE UI "src/*.ui") file(GLOB_RECURSE QRC "res/*.qrc") add_custom_target(format SOURCES ".clang-format" @@ -29,7 +30,7 @@ add_subdirectory(translations) add_definitions(-DVERSION="${CPACK_PACKAGE_VERSION}") # make executable -add_executable(${PROJECT_NAME} ${SRC} ${HEADERS} ${QRC} ${TRANSLATION_BIN_FILES} ${TRANSLATION_QRC}) +add_executable(${PROJECT_NAME} ${SRC} ${HEADERS} ${UI} ${QRC} ${TRANSLATION_BIN_FILES} ${TRANSLATION_QRC}) target_link_libraries(${PROJECT_NAME} Qt5::Widgets Qt5::PrintSupport Qt5::OpenGL ${OPENGL_LIBRARIES} ) target_compile_features(${PROJECT_NAME} PRIVATE cxx_range_for) if(MSVC) diff --git a/openhantek/src/analyse/dataanalyzer.cpp b/openhantek/src/analyse/dataanalyzer.cpp index 4f9c5dd..0f82b08 100644 --- a/openhantek/src/analyse/dataanalyzer.cpp +++ b/openhantek/src/analyse/dataanalyzer.cpp @@ -15,7 +15,7 @@ #include "settings.h" #include "utils/printutils.h" -std::unique_ptr DataAnalyzer::convertData(const DSOsamples *data, const DsoSettingsScope *scope) { +std::unique_ptr DataAnalyzer::convertData(const DSOsamples *data, const DsoSettingsScope *scope, unsigned physicalChannels) { QReadLocker locker(&data->lock); unsigned int channelCount = (unsigned int)scope->voltage.size(); @@ -26,9 +26,9 @@ std::unique_ptr DataAnalyzer::convertData(const DSOsamples * for (unsigned int channel = 0; channel < channelCount; ++channel) { DataChannel *const channelData = result->modifyData(channel); - bool gotDataForChannel = channel < scope->physicalChannels && channel < (unsigned int)data->data.size() && + bool gotDataForChannel = channel < physicalChannels && channel < (unsigned int)data->data.size() && !data->data.at(channel).empty(); - bool isMathChannel = channel >= scope->physicalChannels && + bool isMathChannel = channel >= physicalChannels && (scope->voltage[channel].used || scope->spectrum[channel].used) && result->channelCount() >= 2 && !result->data(0)->voltage.sample.empty() && !result->data(1)->voltage.sample.empty(); @@ -36,7 +36,7 @@ std::unique_ptr DataAnalyzer::convertData(const DSOsamples * if (!gotDataForChannel && !isMathChannel) { // Clear unused channels channelData->voltage.sample.clear(); - result->modifyData(scope->physicalChannels)->voltage.interval = 0; + result->modifyData(physicalChannels)->voltage.interval = 0; continue; } @@ -49,15 +49,15 @@ std::unique_ptr DataAnalyzer::convertData(const DSOsamples * } unsigned int size; - if (channel < scope->physicalChannels) { - size = data->data.at(channel).size(); + if (channel < physicalChannels) { + size = (unsigned) data->data.at(channel).size(); if (data->append) size += channelData->voltage.sample.size(); result->challengeMaxSamples(size); } else size = result->getMaxSamples(); // Physical channels - if (channel < scope->physicalChannels) { + if (channel < physicalChannels) { // Copy the buffer of the oscilloscope into the sample buffer if (data->append) channelData->voltage.sample.insert(channelData->voltage.sample.end(), data->data.at(channel).begin(), @@ -68,20 +68,20 @@ std::unique_ptr DataAnalyzer::convertData(const DSOsamples * // Resize the sample vector channelData->voltage.sample.resize(size); // Set sampling interval - result->modifyData(scope->physicalChannels)->voltage.interval = result->data(0)->voltage.interval; + result->modifyData(physicalChannels)->voltage.interval = result->data(0)->voltage.interval; // Resize the sample vector - result->modifyData(scope->physicalChannels) + result->modifyData(physicalChannels) ->voltage.sample.resize( qMin(result->data(0)->voltage.sample.size(), result->data(1)->voltage.sample.size())); // Calculate values and write them into the sample buffer std::vector::const_iterator ch1Iterator = result->data(0)->voltage.sample.begin(); std::vector::const_iterator ch2Iterator = result->data(1)->voltage.sample.begin(); - std::vector &resultData = result->modifyData(scope->physicalChannels)->voltage.sample; + std::vector &resultData = result->modifyData(physicalChannels)->voltage.sample; for (std::vector::iterator resultIterator = resultData.begin(); resultIterator != resultData.end(); ++resultIterator) { - switch (scope->voltage[scope->physicalChannels].math) { + switch (scope->voltage[physicalChannels].math) { case Dso::MathMode::ADD_CH1_CH2: *resultIterator = *ch1Iterator + *ch2Iterator; break; @@ -105,7 +105,7 @@ DataAnalyzer::~DataAnalyzer() { if (window) fftw_free(window); } -void DataAnalyzer::applySettings(DsoSettingsScope *scope) { this->scope = scope; } +void DataAnalyzer::applySettings(DsoSettings *settings) { this->settings = settings; } void DataAnalyzer::setSourceData(const DSOsamples *data) { sourceData = data; } @@ -113,8 +113,8 @@ std::unique_ptr DataAnalyzer::getNextResult() { return std:: void DataAnalyzer::samplesAvailable() { if (sourceData == nullptr) return; - std::unique_ptr result = convertData(sourceData, scope); - spectrumAnalysis(result.get(), lastWindow, lastRecordLength, window, scope); + std::unique_ptr result = convertData(sourceData, &settings->scope,settings->deviceSpecification->channels); + spectrumAnalysis(result.get(), lastWindow, lastRecordLength, window, &settings->scope); lastResult.swap(result); emit analyzed(); } @@ -134,11 +134,11 @@ void DataAnalyzer::spectrumAnalysis(DataAnalyzerResult *result, Dso::WindowFunct } // Calculate new window - unsigned int sampleCount = channelData->voltage.sample.size(); + size_t sampleCount = channelData->voltage.sample.size(); if (!lastWindowBuffer || lastWindow != scope->spectrumWindow || lastRecordLength != sampleCount) { if (lastWindowBuffer) fftw_free(lastWindowBuffer); lastWindowBuffer = fftw_alloc_real(sampleCount); - lastRecordLength = sampleCount; + lastRecordLength = (unsigned)sampleCount; unsigned int windowEnd = lastRecordLength - 1; lastWindow = scope->spectrumWindow; diff --git a/openhantek/src/analyse/dataanalyzer.h b/openhantek/src/analyse/dataanalyzer.h index d925a2d..3639d66 100644 --- a/openhantek/src/analyse/dataanalyzer.h +++ b/openhantek/src/analyse/dataanalyzer.h @@ -13,6 +13,7 @@ #include "utils/printutils.h" #include "enums.h" +class DsoSettings; struct DsoSettingsScope; //////////////////////////////////////////////////////////////////////////////// @@ -25,7 +26,7 @@ class DataAnalyzer : public QObject { public: ~DataAnalyzer(); - void applySettings(DsoSettingsScope *scope); + void applySettings(DsoSettings *settings); void setSourceData(const DSOsamples *data); std::unique_ptr getNextResult(); /** @@ -34,13 +35,13 @@ class DataAnalyzer : public QObject { void samplesAvailable(); private: - static std::unique_ptr convertData(const DSOsamples *data, const DsoSettingsScope *scope); + static std::unique_ptr convertData(const DSOsamples *data, const DsoSettingsScope *scope, unsigned physicalChannels); static void spectrumAnalysis(DataAnalyzerResult *result, Dso::WindowFunction &lastWindow, unsigned int lastRecordLength, double *&lastWindowBuffer, const DsoSettingsScope *scope); private: - DsoSettingsScope *scope; + DsoSettings *settings; unsigned int lastRecordLength = 0; ///< The record length of the previously analyzed data Dso::WindowFunction lastWindow = (Dso::WindowFunction)-1; ///< The previously used dft window function double *window = nullptr; diff --git a/openhantek/src/analyse/dataanalyzerresult.cpp b/openhantek/src/analyse/dataanalyzerresult.cpp index b3408f0..2fa46a2 100644 --- a/openhantek/src/analyse/dataanalyzerresult.cpp +++ b/openhantek/src/analyse/dataanalyzerresult.cpp @@ -9,13 +9,13 @@ DataAnalyzerResult::DataAnalyzerResult(unsigned int channelCount) { analyzedData /// \brief Returns the analyzed data. /// \param channel Channel, whose data should be returned. /// \return Analyzed data as AnalyzedData struct. -const DataChannel *DataAnalyzerResult::data(unsigned channel) const { +const DataChannel *DataAnalyzerResult::data(ChannelID channel) const { if (channel >= this->analyzedData.size()) return 0; return &this->analyzedData[(size_t)channel]; } -DataChannel *DataAnalyzerResult::modifyData(unsigned channel) { +DataChannel *DataAnalyzerResult::modifyData(ChannelID channel) { if (channel >= this->analyzedData.size()) throw new std::runtime_error("If you modfiy the DataAnalyzerResult, you " "need to set the channels first!"); diff --git a/openhantek/src/analyse/dataanalyzerresult.h b/openhantek/src/analyse/dataanalyzerresult.h index aa6e5a5..ae2f488 100644 --- a/openhantek/src/analyse/dataanalyzerresult.h +++ b/openhantek/src/analyse/dataanalyzerresult.h @@ -3,6 +3,7 @@ #pragma once #include +#include "hantekprotocol/definitions.h" //////////////////////////////////////////////////////////////////////////////// /// \struct SampleValues dataanalyzer.h @@ -25,8 +26,8 @@ struct DataChannel { class DataAnalyzerResult { public: DataAnalyzerResult(unsigned int channelCount); - const DataChannel *data(unsigned channel) const; - DataChannel *modifyData(unsigned channel); + const DataChannel *data(ChannelID channel) const; + DataChannel *modifyData(ChannelID channel); unsigned int sampleCount() const; unsigned int channelCount() const; diff --git a/openhantek/src/analyse/enums.cpp b/openhantek/src/analyse/enums.cpp new file mode 100644 index 0000000..fc49508 --- /dev/null +++ b/openhantek/src/analyse/enums.cpp @@ -0,0 +1,8 @@ +#include "enums.h" + +namespace Dso { + +Enum MathModeEnum; +Enum WindowFunctionEnum; + +} diff --git a/openhantek/src/analyse/enums.h b/openhantek/src/analyse/enums.h index 68054d3..a9872f9 100644 --- a/openhantek/src/analyse/enums.h +++ b/openhantek/src/analyse/enums.h @@ -9,11 +9,9 @@ namespace Dso { enum class MathMode { ADD_CH1_CH2, SUB_CH2_FROM_CH1, - SUB_CH1_FROM_CH2, - - First = ADD_CH1_CH2, - Last = SUB_CH1_FROM_CH2 + SUB_CH1_FROM_CH2 }; +extern Enum MathModeEnum; /// \enum WindowFunction /// \brief The supported window functions. @@ -34,11 +32,9 @@ enum class WindowFunction: int { NUTTALL, ///< Nuttall window, cont. first deriv. BLACKMANHARRIS, ///< Blackman-Harris window BLACKMANNUTTALL, ///< Blackman-Nuttall window - FLATTOP, ///< Flat top window - - First = RECTANGULAR, - Last = FLATTOP + FLATTOP ///< Flat top window }; +extern Enum WindowFunctionEnum; } diff --git a/openhantek/src/configdialog/DsoConfigColorsPage.cpp b/openhantek/src/configdialog/DsoConfigColorsPage.cpp index e11f86f..85e96e7 100644 --- a/openhantek/src/configdialog/DsoConfigColorsPage.cpp +++ b/openhantek/src/configdialog/DsoConfigColorsPage.cpp @@ -51,12 +51,12 @@ DsoConfigColorsPage::DsoConfigColorsPage(DsoSettings *settings, QWidget *parent) printSpectrumLabel = new QLabel(tr("Spectrum")); printSpectrumLabel->setAlignment(Qt::AlignHCenter); - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - colorLabel.append(new QLabel(settings->scope.voltage[channel].name)); - screenChannelColorBox.append(new ColorBox(colorSettings.screen.voltage[channel])); - screenSpectrumColorBox.append(new ColorBox(colorSettings.screen.spectrum[channel])); - printChannelColorBox.append(new ColorBox(colorSettings.print.voltage[channel])); - printSpectrumColorBox.append(new ColorBox(colorSettings.print.spectrum[channel])); + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { + colorLabel.push_back(new QLabel(settings->scope.voltage[channel].name)); + screenChannelColorBox.push_back(new ColorBox(colorSettings.screen.voltage[channel])); + screenSpectrumColorBox.push_back(new ColorBox(colorSettings.screen.spectrum[channel])); + printChannelColorBox.push_back(new ColorBox(colorSettings.print.voltage[channel])); + printSpectrumColorBox.push_back(new ColorBox(colorSettings.print.spectrum[channel])); } // Plot Area Layout @@ -106,7 +106,7 @@ DsoConfigColorsPage::DsoConfigColorsPage(DsoSettings *settings, QWidget *parent) colorsLayout->addWidget(printSpectrumLabel, row, COL_PRT_SPECTRUM); ++row; - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel, ++row) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel, ++row) { colorsLayout->addWidget(colorLabel[channel], row, COL_LABEL); colorsLayout->addWidget(screenChannelColorBox[channel], row, COL_SCR_CHANNEL); colorsLayout->addWidget(screenSpectrumColorBox[channel], row, COL_SCR_SPECTRUM); @@ -146,7 +146,7 @@ void DsoConfigColorsPage::saveSettings() { colorSettings.print.text = printTextColorBox->getColor(); // Graph category - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { colorSettings.screen.voltage[channel] = screenChannelColorBox[channel]->getColor(); colorSettings.screen.spectrum[channel] = screenSpectrumColorBox[channel]->getColor(); colorSettings.print.voltage[channel] = printChannelColorBox[channel]->getColor(); diff --git a/openhantek/src/configdialog/DsoConfigColorsPage.h b/openhantek/src/configdialog/DsoConfigColorsPage.h index 2197548..0007542 100644 --- a/openhantek/src/configdialog/DsoConfigColorsPage.h +++ b/openhantek/src/configdialog/DsoConfigColorsPage.h @@ -46,9 +46,9 @@ class DsoConfigColorsPage : public QWidget { QLabel *graphLabel; QLabel *screenChannelLabel, *screenSpectrumLabel, *printChannelLabel, *printSpectrumLabel; - QList colorLabel; - QList screenChannelColorBox; - QList screenSpectrumColorBox; - QList printChannelColorBox; - QList printSpectrumColorBox; + std::vector colorLabel; + std::vector screenChannelColorBox; + std::vector screenSpectrumColorBox; + std::vector printChannelColorBox; + std::vector printSpectrumColorBox; }; diff --git a/openhantek/src/configdialog/configdialog.cpp b/openhantek/src/configdialog/configdialog.cpp index 6c7286f..eabda2f 100644 --- a/openhantek/src/configdialog/configdialog.cpp +++ b/openhantek/src/configdialog/configdialog.cpp @@ -90,9 +90,9 @@ DsoConfigDialog::DsoConfigDialog(DsoSettings *settings, QWidget *parent, Qt::Win this->mainLayout->addLayout(this->buttonsLayout); this->setLayout(this->mainLayout); - connect(this->acceptButton, SIGNAL(clicked()), this, SLOT(accept())); - connect(this->applyButton, SIGNAL(clicked()), this, SLOT(apply())); - connect(this->rejectButton, SIGNAL(clicked()), this, SLOT(reject())); + connect(this->acceptButton, &QAbstractButton::clicked, this, &DsoConfigDialog::accept); + connect(this->applyButton, &QAbstractButton::clicked, this, &DsoConfigDialog::apply); + connect(this->rejectButton, &QAbstractButton::clicked, this, &QDialog::reject); } /// \brief Cleans up the dialog. @@ -116,8 +116,8 @@ void DsoConfigDialog::createIcons() { scopeButton->setIcon(QIcon(":config/scope.png")); scopeButton->setText(tr("Scope")); - connect(contentsWidget, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, - SLOT(changePage(QListWidgetItem *, QListWidgetItem *))); + connect(contentsWidget, &QListWidget::currentItemChanged, this, + &DsoConfigDialog::changePage); } /// \brief Saves the settings and closes the dialog. diff --git a/openhantek/src/docks/HorizontalDock.cpp b/openhantek/src/docks/HorizontalDock.cpp index 5011177..41780e7 100644 --- a/openhantek/src/docks/HorizontalDock.cpp +++ b/openhantek/src/docks/HorizontalDock.cpp @@ -59,8 +59,8 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo this->formatLabel = new QLabel(tr("Format")); this->formatComboBox = new QComboBox(); - for (int format = Dso::GRAPHFORMAT_TY; format < Dso::GRAPHFORMAT_COUNT; ++format) - this->formatComboBox->addItem(Dso::graphFormatString((Dso::GraphFormat)format)); + for (Dso::GraphFormat format: Dso::GraphFormatEnum) + this->formatComboBox->addItem(Dso::graphFormatString(format)); this->dockLayout = new QGridLayout(); this->dockLayout->setColumnMinimumWidth(0, 64); @@ -156,7 +156,7 @@ void HorizontalDock::setRecordLength(unsigned int recordLength) { /// \return Index of format-value, -1 on error. int HorizontalDock::setFormat(Dso::GraphFormat format) { QSignalBlocker blocker(formatComboBox); - if (format >= Dso::GRAPHFORMAT_TY && format <= Dso::GRAPHFORMAT_XY) { + if (format >= Dso::GraphFormat::TY && format <= Dso::GraphFormat::XY) { formatComboBox->setCurrentIndex(format); return format; } diff --git a/openhantek/src/docks/SpectrumDock.cpp b/openhantek/src/docks/SpectrumDock.cpp index cd4448d..358a582 100644 --- a/openhantek/src/docks/SpectrumDock.cpp +++ b/openhantek/src/docks/SpectrumDock.cpp @@ -26,42 +26,37 @@ SpectrumDock::SpectrumDock(DsoSettings *settings, QWidget *parent, Qt::WindowFla : QDockWidget(tr("Spectrum"), parent, flags), settings(settings) { // Initialize lists for comboboxes - this->magnitudeSteps << 1e0 << 2e0 << 3e0 << 6e0 << 1e1 << 2e1 << 3e1 << 6e1 << 1e2 << 2e2 << 3e2 - << 6e2; ///< Magnitude steps in dB/div - for (QList::iterator magnitude = this->magnitudeSteps.begin(); magnitude != this->magnitudeSteps.end(); - ++magnitude) - this->magnitudeStrings << valueToString(*magnitude, UNIT_DECIBEL, 0); + this->magnitudeSteps = { 1e0 , 2e0 , 3e0 , 6e0 , 1e1 , 2e1 , 3e1 , 6e1 , 1e2 , 2e2 , 3e2, 6e2 }; + for (const auto& magnitude: magnitudeSteps) + this->magnitudeStrings << valueToString(magnitude, UNIT_DECIBEL, 0); // Initialize elements - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - this->magnitudeComboBox.append(new QComboBox()); + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { + this->magnitudeComboBox.push_back(new QComboBox()); this->magnitudeComboBox[channel]->addItems(this->magnitudeStrings); - this->usedCheckBox.append(new QCheckBox(settings->scope.voltage[channel].name)); + this->usedCheckBox.push_back(new QCheckBox(settings->scope.voltage[channel].name)); } this->dockLayout = new QGridLayout(); this->dockLayout->setColumnMinimumWidth(0, 64); this->dockLayout->setColumnStretch(1, 1); - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - this->dockLayout->addWidget(this->usedCheckBox[channel], channel, 0); - this->dockLayout->addWidget(this->magnitudeComboBox[channel], channel, 1); - } - - this->dockWidget = new QWidget(); - SetupDockWidget(this, dockWidget, dockLayout); + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { + this->dockLayout->addWidget(this->usedCheckBox[channel], (int)channel, 0); + this->dockLayout->addWidget(this->magnitudeComboBox[channel], (int)channel, 1); - // Connect signals and slots - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - connect(this->magnitudeComboBox[channel], SIGNAL(currentIndexChanged(int)), this, SLOT(magnitudeSelected(int))); - connect(this->usedCheckBox[channel], SIGNAL(toggled(bool)), this, SLOT(usedSwitched(bool))); - } + // Connect signals and slots + connect(usedCheckBox[channel], &QCheckBox::toggled, this, &SpectrumDock::usedSwitched); + QComboBox* cmb = magnitudeComboBox[channel]; + connect(cmb, static_cast(&QComboBox::currentIndexChanged), this, &SpectrumDock::magnitudeSelected); - // Set values - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { + // Set values this->setMagnitude(channel, settings->scope.spectrum[channel].magnitude); this->setUsed(channel, settings->scope.spectrum[channel].used); } + + dockWidget = new QWidget(); + SetupDockWidget(this, dockWidget, dockLayout); } /// \brief Don't close the dock, just hide it @@ -76,32 +71,31 @@ void SpectrumDock::closeEvent(QCloseEvent *event) { /// \param channel The channel, whose magnitude should be set. /// \param magnitude The magnitude in dB. /// \return Index of magnitude-value, -1 on error. -int SpectrumDock::setMagnitude(int channel, double magnitude) { - if (channel < 0 || channel >= settings->scope.voltage.size()) return -1; - - int index = this->magnitudeSteps.indexOf(magnitude); - if (index != -1) this->magnitudeComboBox[channel]->setCurrentIndex(index); +int SpectrumDock::setMagnitude(ChannelID channel, double magnitude) { + if (channel >= settings->scope.voltage.size()) return -1; + auto indexIt = std::find(magnitudeSteps.begin(),magnitudeSteps.end(),magnitude); + if (indexIt == magnitudeSteps.end()) return -1; + int index = (int)std::distance(magnitudeSteps.begin(), indexIt); + magnitudeComboBox[channel]->setCurrentIndex(index); return index; } /// \brief Enables/disables a channel. /// \param channel The channel, that should be enabled/disabled. /// \param used True if the channel should be enabled, false otherwise. -/// \return Index of channel, -1 on error. -int SpectrumDock::setUsed(int channel, bool used) { - if (channel >= 0 && channel < settings->scope.voltage.size()) { - this->usedCheckBox[channel]->setChecked(used); - return channel; - } +/// \return Index of channel, INT_MAX on error. +unsigned SpectrumDock::setUsed(ChannelID channel, bool used) { + if (channel >= settings->scope.voltage.size()) return INT_MAX; - return -1; + this->usedCheckBox[channel]->setChecked(used); + return channel; } /// \brief Called when the source combo box changes it's value. /// \param index The index of the combo box item. -void SpectrumDock::magnitudeSelected(int index) { - int channel; +void SpectrumDock::magnitudeSelected(unsigned index) { + ChannelID channel; // Which combobox was it? for (channel = 0; channel < settings->scope.voltage.size(); ++channel) @@ -117,7 +111,7 @@ void SpectrumDock::magnitudeSelected(int index) { /// \brief Called when the used checkbox is switched. /// \param checked The check-state of the checkbox. void SpectrumDock::usedSwitched(bool checked) { - int channel; + ChannelID channel; // Which checkbox was it? for (channel = 0; channel < settings->scope.voltage.size(); ++channel) diff --git a/openhantek/src/docks/SpectrumDock.h b/openhantek/src/docks/SpectrumDock.h index d4e72a3..6bc6ba8 100644 --- a/openhantek/src/docks/SpectrumDock.h +++ b/openhantek/src/docks/SpectrumDock.h @@ -22,27 +22,27 @@ class SpectrumDock : public QDockWidget { public: SpectrumDock(DsoSettings *settings, QWidget *parent, Qt::WindowFlags flags = 0); - int setMagnitude(int channel, double magnitude); - int setUsed(int channel, bool used); + int setMagnitude(ChannelID channel, double magnitude); + unsigned setUsed(ChannelID channel, bool used); protected: void closeEvent(QCloseEvent *event); QGridLayout *dockLayout; ///< The main layout for the dock window QWidget *dockWidget; ///< The main widget for the dock window - QList usedCheckBox; ///< Enable/disable spectrum for a channel - QList magnitudeComboBox; ///< Select the vertical magnitude for the spectrums + std::vector usedCheckBox; ///< Enable/disable spectrum for a channel + std::vector magnitudeComboBox; ///< Select the vertical magnitude for the spectrums DsoSettings *settings; ///< The settings provided by the parent class - QList magnitudeSteps; ///< The selectable magnitude steps + std::vector magnitudeSteps; ///< The selectable magnitude steps in dB/div QStringList magnitudeStrings; ///< String representations for the magnitude steps public slots: - void magnitudeSelected(int index); + void magnitudeSelected(unsigned index); void usedSwitched(bool checked); signals: - void magnitudeChanged(unsigned int channel, double magnitude); ///< A magnitude has been selected - void usedChanged(unsigned int channel, bool used); ///< A spectrum has been enabled/disabled + void magnitudeChanged(ChannelID channel, double magnitude); ///< A magnitude has been selected + void usedChanged(ChannelID channel, bool used); ///< A spectrum has been enabled/disabled }; diff --git a/openhantek/src/docks/TriggerDock.cpp b/openhantek/src/docks/TriggerDock.cpp index 2d3d3bb..595846b 100644 --- a/openhantek/src/docks/TriggerDock.cpp +++ b/openhantek/src/docks/TriggerDock.cpp @@ -28,7 +28,7 @@ TriggerDock::TriggerDock(DsoSettings *settings, const std::vector & : QDockWidget(tr("Trigger"), parent, flags), settings(settings) { // Initialize lists for comboboxes - for (unsigned int channel = 0; channel < settings->scope.physicalChannels; ++channel) + for (unsigned int channel = 0; channel < settings->deviceSpecification->channels; ++channel) this->sourceStandardStrings << tr("CH%1").arg(channel + 1); for(const std::string& name: specialTriggers) this->sourceSpecialStrings.append(QString::fromStdString(name)); @@ -36,13 +36,13 @@ TriggerDock::TriggerDock(DsoSettings *settings, const std::vector & // Initialize elements this->modeLabel = new QLabel(tr("Mode")); this->modeComboBox = new QComboBox(); - for (int mode = Dso::TRIGGERMODE_AUTO; mode < Dso::TRIGGERMODE_COUNT; ++mode) - this->modeComboBox->addItem(Dso::triggerModeString((Dso::TriggerMode)mode)); + for (Dso::TriggerMode mode: Dso::TriggerModeEnum) + this->modeComboBox->addItem(Dso::triggerModeString(mode)); this->slopeLabel = new QLabel(tr("Slope")); this->slopeComboBox = new QComboBox(); - for (int slope = Dso::SLOPE_POSITIVE; slope < Dso::SLOPE_COUNT; ++slope) - this->slopeComboBox->addItem(Dso::slopeString((Dso::Slope)slope)); + for (Dso::Slope slope: Dso::SlopeEnum) + this->slopeComboBox->addItem(Dso::slopeString(slope)); this->sourceLabel = new QLabel(tr("Source")); this->sourceComboBox = new QComboBox(); @@ -63,9 +63,9 @@ TriggerDock::TriggerDock(DsoSettings *settings, const std::vector & SetupDockWidget(this, dockWidget, dockLayout); // Connect signals and slots - connect(this->modeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(modeSelected(int))); - connect(this->slopeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slopeSelected(int))); - connect(this->sourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(sourceSelected(int))); + connect(this->modeComboBox, static_cast(&QComboBox::currentIndexChanged), this, &TriggerDock::modeSelected); + connect(this->slopeComboBox, static_cast(&QComboBox::currentIndexChanged), this, &TriggerDock::slopeSelected); + connect(this->sourceComboBox, static_cast(&QComboBox::currentIndexChanged), this, &TriggerDock::sourceSelected); // Set values this->setMode(settings->scope.trigger.mode); @@ -84,25 +84,15 @@ void TriggerDock::closeEvent(QCloseEvent *event) { /// \brief Changes the trigger mode if the new mode is supported. /// \param mode The trigger mode. /// \return Index of mode-value, -1 on error. -int TriggerDock::setMode(Dso::TriggerMode mode) { - if (mode >= Dso::TRIGGERMODE_AUTO && mode < Dso::TRIGGERMODE_COUNT) { - this->modeComboBox->setCurrentIndex(mode); - return mode; - } - - return -1; +void TriggerDock::setMode(Dso::TriggerMode mode) { + this->modeComboBox->setCurrentIndex((int)mode); } /// \brief Changes the trigger slope if the new slope is supported. /// \param slope The trigger slope. /// \return Index of slope-value, -1 on error. -int TriggerDock::setSlope(Dso::Slope slope) { - if (slope >= Dso::SLOPE_POSITIVE && slope <= Dso::SLOPE_NEGATIVE) { - this->slopeComboBox->setCurrentIndex(slope); - return slope; - } - - return -1; +void TriggerDock::setSlope(Dso::Slope slope) { + this->slopeComboBox->setCurrentIndex((int)slope); } /// \brief Changes the trigger source if the new source is supported. @@ -114,7 +104,7 @@ int TriggerDock::setSource(bool special, unsigned int id) { (special && id >= (unsigned int)this->sourceSpecialStrings.count())) return -1; - int index = id; + int index = (int)id; if (special) index += this->sourceStandardStrings.count(); this->sourceComboBox->setCurrentIndex(index); diff --git a/openhantek/src/docks/TriggerDock.h b/openhantek/src/docks/TriggerDock.h index 451f022..78dbced 100644 --- a/openhantek/src/docks/TriggerDock.h +++ b/openhantek/src/docks/TriggerDock.h @@ -21,9 +21,9 @@ class TriggerDock : public QDockWidget { public: TriggerDock(DsoSettings *settings, const std::vector& specialTriggers, QWidget *parent, Qt::WindowFlags flags = 0); - int setMode(Dso::TriggerMode mode); + void setMode(Dso::TriggerMode mode); int setSource(bool special, unsigned int id); - int setSlope(Dso::Slope slope); + void setSlope(Dso::Slope slope); protected: void closeEvent(QCloseEvent *event); diff --git a/openhantek/src/docks/VoltageDock.cpp b/openhantek/src/docks/VoltageDock.cpp index 47f2563..4ef3ea6 100644 --- a/openhantek/src/docks/VoltageDock.cpp +++ b/openhantek/src/docks/VoltageDock.cpp @@ -26,184 +26,100 @@ VoltageDock::VoltageDock(DsoSettings *settings, QWidget *parent, Qt::WindowFlags : QDockWidget(tr("Voltage"), parent, flags), settings(settings) { // Initialize lists for comboboxes - for (int coupling = Dso::COUPLING_AC; coupling < Dso::COUPLING_COUNT; ++coupling) - this->couplingStrings.append(Dso::couplingString((Dso::Coupling)coupling)); + for (Dso::Coupling c: settings->deviceSpecification->couplings) + couplingStrings.append(Dso::couplingString(c)); - for( auto e: Enum() ) { - this->modeStrings.append(Dso::mathModeString(e)); + for( auto e: Dso::MathModeEnum ) { + modeStrings.append(Dso::mathModeString(e)); } - this->gainSteps << 1e-2 << 2e-2 << 5e-2 << 1e-1 << 2e-1 << 5e-1 << 1e0 << 2e0 << 5e0; ///< Voltage steps in V/div - for (QList::iterator gain = this->gainSteps.begin(); gain != this->gainSteps.end(); ++gain) - this->gainStrings << valueToString(*gain, UNIT_VOLTS, 0); + for (double gainStep: settings->scope.gainSteps) + gainStrings << valueToString(gainStep, UNIT_VOLTS, 0); - // Initialize elements - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - this->miscComboBox.append(new QComboBox()); - if (channel < (int)settings->scope.physicalChannels) - this->miscComboBox[channel]->addItems(this->couplingStrings); - else - this->miscComboBox[channel]->addItems(this->modeStrings); - - this->gainComboBox.append(new QComboBox()); - this->gainComboBox[channel]->addItems(this->gainStrings); + dockLayout = new QGridLayout(); + dockLayout->setColumnMinimumWidth(0, 64); + dockLayout->setColumnStretch(1, 1); - this->invertCheckBox.append(new QCheckBox(tr("Invert"))); + // Initialize elements + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { + ChannelBlock b; - this->usedCheckBox.append(new QCheckBox(settings->scope.voltage[channel].name)); - } + b.miscComboBox=(new QComboBox()); + b.gainComboBox=(new QComboBox()); + b.invertCheckBox=(new QCheckBox(tr("Invert"))); + b.usedCheckBox=(new QCheckBox(settings->scope.voltage[channel].name)); - this->dockLayout = new QGridLayout(); - this->dockLayout->setColumnMinimumWidth(0, 64); - this->dockLayout->setColumnStretch(1, 1); - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - this->dockLayout->addWidget(this->usedCheckBox[channel], channel * 3, 0); - this->dockLayout->addWidget(this->gainComboBox[channel], channel * 3, 1); - this->dockLayout->addWidget(this->miscComboBox[channel], channel * 3 + 1, 1); - this->dockLayout->addWidget(this->invertCheckBox[channel], channel * 3 + 2, 1); + if (channel < settings->deviceSpecification->channels) + b.miscComboBox->addItems(couplingStrings); + else + b.miscComboBox->addItems(modeStrings); + + b.gainComboBox->addItems(gainStrings); + + dockLayout->addWidget(b.usedCheckBox, (int)channel * 3, 0); + dockLayout->addWidget(b.gainComboBox, (int)channel * 3, 1); + dockLayout->addWidget(b.miscComboBox, (int)channel * 3 + 1, 1); + dockLayout->addWidget(b.invertCheckBox, (int)channel * 3 + 2, 1); + + connect(b.gainComboBox, static_cast(&QComboBox::currentIndexChanged), [this,channel](int index) { + this->settings->scope.voltage[channel].gainStepIndex = (unsigned)index; + emit gainChanged(channel, this->settings->scope.gain(channel)); + }); + connect(b.invertCheckBox, &QAbstractButton::toggled, [this,channel](bool checked) { + this->settings->scope.voltage[channel].inverted = checked; + }); + connect(b.miscComboBox, static_cast(&QComboBox::currentIndexChanged), [this,channel](int index){ + if (channel < this->settings->deviceSpecification->channels) { + this->settings->scope.voltage[channel].couplingIndex = (unsigned)index; + emit couplingChanged(channel, this->settings->coupling(channel)); + } else { + this->settings->scope.voltage[channel].math = (Dso::MathMode) index; + emit modeChanged(this->settings->scope.voltage[channel].math); + } + }); + connect(b.usedCheckBox, &QAbstractButton::toggled, [this,channel](bool checked) { + this->settings->scope.voltage[channel].used = checked; + emit usedChanged(channel, checked); + }); + + channelBlocks.push_back(std::move(b)); + + if (channel < settings->deviceSpecification->channels) + setCoupling(channel, settings->scope.voltage[channel].couplingIndex); + else + setMode(settings->scope.voltage[channel].math); + setGain(channel, settings->scope.voltage[channel].gainStepIndex); + setUsed(channel, settings->scope.voltage[channel].used); } - this->dockWidget = new QWidget(); + dockWidget = new QWidget(); SetupDockWidget(this, dockWidget, dockLayout); - - // Connect signals and slots - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - connect(this->gainComboBox[channel], SIGNAL(currentIndexChanged(int)), this, SLOT(gainSelected(int))); - connect(this->invertCheckBox[channel], SIGNAL(toggled(bool)), this, SLOT(invertSwitched(bool))); - connect(this->miscComboBox[channel], SIGNAL(currentIndexChanged(int)), this, SLOT(miscSelected(int))); - connect(this->usedCheckBox[channel], SIGNAL(toggled(bool)), this, SLOT(usedSwitched(bool))); - } - - // Set values - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { - if (channel < (int)settings->scope.physicalChannels) - this->setCoupling(channel, settings->scope.voltage[channel].coupling); - else - this->setMode(settings->scope.voltage[channel].math); - this->setGain(channel, settings->scope.voltage[channel].gain); - this->setUsed(channel, settings->scope.voltage[channel].used); - } } /// \brief Don't close the dock, just hide it /// \param event The close event that should be handled. void VoltageDock::closeEvent(QCloseEvent *event) { - this->hide(); - + hide(); event->accept(); } -/// \brief Sets the coupling for a channel. -/// \param channel The channel, whose coupling should be set. -/// \param coupling The coupling-mode. -/// \return Index of coupling-mode, -1 on error. -int VoltageDock::setCoupling(int channel, Dso::Coupling coupling) { - if (coupling < Dso::COUPLING_AC || coupling > Dso::COUPLING_GND) return -1; - if (channel < 0 || channel >= (int)settings->scope.physicalChannels) return -1; - - this->miscComboBox[channel]->setCurrentIndex(coupling); - return coupling; +void VoltageDock::setCoupling(ChannelID channel, unsigned couplingIndex) { + if (channel >= settings->deviceSpecification->channels) return; + if (couplingIndex >= settings->deviceSpecification->couplings.size()) return; + channelBlocks[channel].miscComboBox->setCurrentIndex((int)couplingIndex); } -/// \brief Sets the gain for a channel. -/// \param channel The channel, whose gain should be set. -/// \param gain The gain in volts. -/// \return Index of gain-value, -1 on error. -int VoltageDock::setGain(int channel, double gain) { - if (channel < 0 || channel >= settings->scope.voltage.size()) return -1; - - int index = this->gainSteps.indexOf(gain); - if (index != -1) this->gainComboBox[channel]->setCurrentIndex(index); - - return index; +void VoltageDock::setGain(ChannelID channel, unsigned gainStepIndex) { + if (channel >= settings->scope.voltage.size()) return; + if (gainStepIndex >= settings->scope.gainSteps.size()) return; + channelBlocks[channel].gainComboBox->setCurrentIndex((unsigned)gainStepIndex); } -/// \brief Sets the mode for the math channel. -/// \param mode The math-mode. -/// \return Index of math-mode, -1 on error. void VoltageDock::setMode(Dso::MathMode mode) { - miscComboBox[settings->scope.physicalChannels]->setCurrentIndex((int)mode); + channelBlocks[settings->deviceSpecification->channels].miscComboBox->setCurrentIndex((int)mode); } -/// \brief Enables/disables a channel. -/// \param channel The channel, that should be enabled/disabled. -/// \param used True if the channel should be enabled, false otherwise. -/// \return Index of channel, -1 on error. -int VoltageDock::setUsed(int channel, bool used) { - if (channel >= 0 && channel < settings->scope.voltage.size()) { - this->usedCheckBox[channel]->setChecked(used); - return channel; - } - - return -1; -} - -/// \brief Called when the gain combo box changes it's value. -/// \param index The index of the combo box item. -void VoltageDock::gainSelected(int index) { - int channel; - - // Which combobox was it? - for (channel = 0; channel < settings->scope.voltage.size(); ++channel) - if (this->sender() == this->gainComboBox[channel]) break; - - // Send signal if it was one of the comboboxes - if (channel < settings->scope.voltage.size()) { - settings->scope.voltage[channel].gain = this->gainSteps.at(index); - - emit gainChanged(channel, settings->scope.voltage[channel].gain); - } -} - -/// \brief Called when the misc combo box changes it's value. -/// \param index The index of the combo box item. -void VoltageDock::miscSelected(int index) { - int channel; - - // Which combobox was it? - for (channel = 0; channel < settings->scope.voltage.size(); ++channel) - if (this->sender() == this->miscComboBox[channel]) break; - - // Send signal if it was one of the comboboxes - if (channel < settings->scope.voltage.size()) { - if (channel < (int)settings->scope.physicalChannels) { - settings->scope.voltage[channel].coupling = (Dso::Coupling) index; - emit couplingChanged(channel, settings->scope.voltage[channel].coupling); - } else { - settings->scope.voltage[channel].math = (Dso::MathMode) index; - emit modeChanged(settings->scope.voltage[channel].math); - } - } -} - -/// \brief Called when the used checkbox is switched. -/// \param checked The check-state of the checkbox. -void VoltageDock::usedSwitched(bool checked) { - int channel; - - // Which checkbox was it? - for (channel = 0; channel < settings->scope.voltage.size(); ++channel) - if (this->sender() == this->usedCheckBox[channel]) break; - - // Send signal if it was one of the checkboxes - if (channel < settings->scope.voltage.size()) { - settings->scope.voltage[channel].used = checked; - emit usedChanged(channel, checked); - } -} - -/// \brief Called when the invert checkbox is switched. -/// \param checked The check-state of the checkbox. -void VoltageDock::invertSwitched(bool checked) { - int channel; - - // Which checkbox was it? - for (channel = 0; channel < settings->scope.voltage.size(); ++channel) - if (this->sender() == this->invertCheckBox[channel]) break; - - // Send signal if it was one of the checkboxes - if (channel < settings->scope.voltage.size()) { - settings->scope.voltage[channel].inverted = checked; - // Should we emit an event here? - } +void VoltageDock::setUsed(ChannelID channel, bool used) { + if (channel >= settings->scope.voltage.size()) return; + channelBlocks[channel].usedCheckBox->setChecked(used); } diff --git a/openhantek/src/docks/VoltageDock.h b/openhantek/src/docks/VoltageDock.h index 173341c..ee69ce8 100644 --- a/openhantek/src/docks/VoltageDock.h +++ b/openhantek/src/docks/VoltageDock.h @@ -4,13 +4,12 @@ #include #include +#include +#include +#include #include "settings.h" -class QLabel; -class QCheckBox; -class QComboBox; - class SiSpinBox; /// \brief Dock window for the voltage channel settings. @@ -22,34 +21,46 @@ class VoltageDock : public QDockWidget { public: VoltageDock(DsoSettings *settings, QWidget *parent, Qt::WindowFlags flags = 0); - int setCoupling(int channel, Dso::Coupling coupling); - int setGain(int channel, double gain); + /// \brief Sets the coupling for a channel. + /// \param channel The channel, whose coupling should be set. + /// \param coupling The coupling-mode. + void setCoupling(ChannelID channel, unsigned couplingIndex); + + /// \brief Sets the gain for a channel. + /// \param channel The channel, whose gain should be set. + /// \param gain The gain in volts. + void setGain(ChannelID channel, unsigned gainStepIndex); + + /// \brief Sets the mode for the math channel. + /// \param mode The math-mode. void setMode(Dso::MathMode mode); - int setUsed(int channel, bool used); + + /// \brief Enables/disables a channel. + /// \param channel The channel, that should be enabled/disabled. + /// \param used True if the channel should be enabled, false otherwise. + void setUsed(ChannelID channel, bool used); protected: void closeEvent(QCloseEvent *event); QGridLayout *dockLayout; ///< The main layout for the dock window QWidget *dockWidget; ///< The main widget for the dock window - QList usedCheckBox; ///< Enable/disable a specific channel - QList gainComboBox; ///< Select the vertical gain for the channels - QList miscComboBox; ///< Select coupling for real and mode for math channels - QList invertCheckBox; ///< Select if the channels should be displayed inverted + + struct ChannelBlock { + QCheckBox * usedCheckBox; ///< Enable/disable a specific channel + QComboBox * gainComboBox; ///< Select the vertical gain for the channels + QComboBox * miscComboBox; ///< Select coupling for real and mode for math channels + QCheckBox * invertCheckBox; ///< Select if the channels should be displayed inverted + }; + + std::vector channelBlocks; DsoSettings *settings; ///< The settings provided by the parent class QStringList couplingStrings; ///< The strings for the couplings QStringList modeStrings; ///< The strings for the math mode - QList gainSteps; ///< The selectable gain steps QStringList gainStrings; ///< String representations for the gain steps - protected slots: - void gainSelected(int index); - void miscSelected(int index); - void usedSwitched(bool checked); - void invertSwitched(bool checked); - signals: void couplingChanged(unsigned int channel, Dso::Coupling coupling); ///< A coupling has been selected void gainChanged(unsigned int channel, double gain); ///< A gain has been selected diff --git a/openhantek/src/dsowidget.cpp b/openhantek/src/dsowidget.cpp index 94294ec..d737664 100644 --- a/openhantek/src/dsowidget.cpp +++ b/openhantek/src/dsowidget.cpp @@ -16,9 +16,11 @@ #include "utils/dsoStrings.h" #include "utils/printutils.h" #include "widgets/levelslider.h" +#include "viewconstants.h" +#include "analyse/dataanalyzerresult.h" DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags flags) - : QWidget(parent, flags), settings(settings), generator(new GlGenerator(&settings->scope, &settings->view)), + : QWidget(parent, flags), settings(settings), generator(new GlGenerator()), mainScope(new GlScope(settings, generator)), zoomScope(new GlScope(settings, generator)) { // Palette for this widget @@ -31,7 +33,7 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla // The offset sliders for all possible channels offsetSlider = new LevelSlider(Qt::RightArrow); - for (unsigned channel = 0; channel < settings->scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { offsetSlider->addSlider(settings->scope.voltage[channel].name, channel); offsetSlider->setColor(channel, settings->view.screen.voltage[channel]); offsetSlider->setLimits(channel, -DIVS_VOLTAGE / 2, DIVS_VOLTAGE / 2); @@ -39,7 +41,7 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla offsetSlider->setValue(channel, settings->scope.voltage[channel].offset); offsetSlider->setIndexVisible(channel, settings->scope.voltage[channel].used); } - for (unsigned channel = 0; channel < settings->scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { offsetSlider->addSlider(settings->scope.spectrum[channel].name, settings->scope.voltage.size() + channel); offsetSlider->setColor(settings->scope.voltage.size() + channel, settings->view.screen.spectrum[channel]); offsetSlider->setLimits(settings->scope.voltage.size() + channel, -DIVS_VOLTAGE / 2, DIVS_VOLTAGE / 2); @@ -52,17 +54,17 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla triggerPositionSlider = new LevelSlider(Qt::DownArrow); triggerPositionSlider->addSlider(); triggerPositionSlider->setLimits(0, 0.0, 1.0); - triggerPositionSlider->setStep(0, 0.2 / DIVS_TIME); + triggerPositionSlider->setStep(0, 0.2 / (double)DIVS_TIME); triggerPositionSlider->setValue(0, settings->scope.trigger.position); triggerPositionSlider->setIndexVisible(0, true); // The sliders for the trigger levels triggerLevelSlider = new LevelSlider(Qt::LeftArrow); - for (int channel = 0; channel < (int)settings->scope.physicalChannels; ++channel) { - triggerLevelSlider->addSlider(channel); + for (ChannelID channel = 0; channel < settings->deviceSpecification->channels; ++channel) { + triggerLevelSlider->addSlider((int)channel); triggerLevelSlider->setColor( channel, - (!settings->scope.trigger.special && channel == (int)settings->scope.trigger.source) + (!settings->scope.trigger.special && channel == settings->scope.trigger.source) ? settings->view.screen.voltage[channel] : settings->view.screen.voltage[channel].darker()); adaptTriggerLevelSlider(channel); @@ -142,33 +144,33 @@ DsoWidget::DsoWidget(DsoSettings *settings, QWidget *parent, Qt::WindowFlags fla measurementLayout->setColumnStretch(3, 2); measurementLayout->setColumnStretch(4, 3); measurementLayout->setColumnStretch(5, 3); - for (int channel = 0; channel < (int)settings->scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { tablePalette.setColor(QPalette::WindowText, settings->view.screen.voltage[channel]); - measurementNameLabel.append(new QLabel(settings->scope.voltage[channel].name)); + measurementNameLabel.push_back(new QLabel(settings->scope.voltage[channel].name)); measurementNameLabel[channel]->setPalette(tablePalette); - measurementMiscLabel.append(new QLabel()); + measurementMiscLabel.push_back(new QLabel()); measurementMiscLabel[channel]->setPalette(tablePalette); - measurementGainLabel.append(new QLabel()); + measurementGainLabel.push_back(new QLabel()); measurementGainLabel[channel]->setAlignment(Qt::AlignRight); measurementGainLabel[channel]->setPalette(tablePalette); tablePalette.setColor(QPalette::WindowText, settings->view.screen.spectrum[channel]); - measurementMagnitudeLabel.append(new QLabel()); + measurementMagnitudeLabel.push_back(new QLabel()); measurementMagnitudeLabel[channel]->setAlignment(Qt::AlignRight); measurementMagnitudeLabel[channel]->setPalette(tablePalette); - measurementAmplitudeLabel.append(new QLabel()); + measurementAmplitudeLabel.push_back(new QLabel()); measurementAmplitudeLabel[channel]->setAlignment(Qt::AlignRight); measurementAmplitudeLabel[channel]->setPalette(palette); - measurementFrequencyLabel.append(new QLabel()); + measurementFrequencyLabel.push_back(new QLabel()); measurementFrequencyLabel[channel]->setAlignment(Qt::AlignRight); measurementFrequencyLabel[channel]->setPalette(palette); setMeasurementVisible(channel, settings->scope.voltage[channel].used); - measurementLayout->addWidget(measurementNameLabel[channel], channel, 0); - measurementLayout->addWidget(measurementMiscLabel[channel], channel, 1); - measurementLayout->addWidget(measurementGainLabel[channel], channel, 2); - measurementLayout->addWidget(measurementMagnitudeLabel[channel], channel, 3); - measurementLayout->addWidget(measurementAmplitudeLabel[channel], channel, 4); - measurementLayout->addWidget(measurementFrequencyLabel[channel], channel, 5); - if ((unsigned)channel < settings->scope.physicalChannels) + measurementLayout->addWidget(measurementNameLabel[channel], (int)channel, 0); + measurementLayout->addWidget(measurementMiscLabel[channel], (int)channel, 1); + measurementLayout->addWidget(measurementGainLabel[channel], (int)channel, 2); + measurementLayout->addWidget(measurementMagnitudeLabel[channel], (int)channel, 3); + measurementLayout->addWidget(measurementAmplitudeLabel[channel], (int)channel, 4); + measurementLayout->addWidget(measurementFrequencyLabel[channel], (int)channel, 5); + if ((unsigned)channel < settings->deviceSpecification->channels) updateVoltageCoupling((unsigned)channel); else updateMathMode(); @@ -233,15 +235,15 @@ void DsoWidget::showNewData(std::unique_ptr data) { } /// \brief Set the trigger level sliders minimum and maximum to the new values. -void DsoWidget::adaptTriggerLevelSlider(unsigned int channel) { +void DsoWidget::adaptTriggerLevelSlider(ChannelID channel) { triggerLevelSlider->setLimits( - channel, (-DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.voltage[channel].gain, - (DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.voltage[channel].gain); - triggerLevelSlider->setStep(channel, settings->scope.voltage[channel].gain * 0.2); + (int)channel, (-DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.gain(channel), + (DIVS_VOLTAGE / 2 - settings->scope.voltage[channel].offset) * settings->scope.gain(channel)); + triggerLevelSlider->setStep((int)channel, settings->scope.gain(channel) * 0.2); } /// \brief Show/Hide a line of the measurement table. -void DsoWidget::setMeasurementVisible(unsigned int channel, bool visible) { +void DsoWidget::setMeasurementVisible(ChannelID channel, bool visible) { measurementNameLabel[channel]->setVisible(visible); measurementMiscLabel[channel]->setVisible(visible); measurementGainLabel[channel]->setVisible(visible); @@ -272,7 +274,7 @@ void DsoWidget::updateMarkerDetails() { } /// \brief Update the label about the trigger settings -void DsoWidget::updateSpectrumDetails(unsigned int channel) { +void DsoWidget::updateSpectrumDetails(ChannelID channel) { setMeasurementVisible(channel, settings->scope.voltage[channel].used || settings->scope.spectrum[channel].used); if (settings->scope.spectrum[channel].used) @@ -299,13 +301,13 @@ void DsoWidget::updateTriggerDetails() { } /// \brief Update the label about the trigger settings -void DsoWidget::updateVoltageDetails(unsigned int channel) { - if (channel >= (unsigned int)settings->scope.voltage.size()) return; +void DsoWidget::updateVoltageDetails(ChannelID channel) { + if (channel >= settings->scope.voltage.size()) return; setMeasurementVisible(channel, settings->scope.voltage[channel].used || settings->scope.spectrum[channel].used); if (settings->scope.voltage[channel].used) - measurementGainLabel[channel]->setText(valueToString(settings->scope.voltage[channel].gain, UNIT_VOLTS, 3) + + measurementGainLabel[channel]->setText(valueToString(settings->scope.gain(channel), UNIT_VOLTS, 3) + tr("/div")); else measurementGainLabel[channel]->setText(QString()); @@ -355,12 +357,12 @@ void DsoWidget::updateTriggerSlope() { updateTriggerDetails(); } /// \brief Handles sourceChanged signal from the trigger dock. void DsoWidget::updateTriggerSource() { // Change the colors of the trigger sliders - if (settings->scope.trigger.special || settings->scope.trigger.source >= settings->scope.physicalChannels) + if (settings->scope.trigger.special || settings->scope.trigger.source >= settings->deviceSpecification->channels) triggerPositionSlider->setColor(0, settings->view.screen.border); else triggerPositionSlider->setColor(0, settings->view.screen.voltage[settings->scope.trigger.source]); - for (int channel = 0; channel < (int)settings->scope.physicalChannels; ++channel) + for (int channel = 0; channel < (int)settings->deviceSpecification->channels; ++channel) triggerLevelSlider->setColor( channel, (!settings->scope.trigger.special && channel == (int)settings->scope.trigger.source) @@ -375,13 +377,13 @@ void DsoWidget::updateTriggerSource() { void DsoWidget::updateVoltageCoupling(unsigned int channel) { if (channel >= (unsigned int)settings->scope.voltage.size()) return; - measurementMiscLabel[channel]->setText(Dso::couplingString(settings->scope.voltage[channel].coupling)); + measurementMiscLabel[channel]->setText(Dso::couplingString(settings->coupling(channel))); } /// \brief Handles modeChanged signal from the voltage dock. void DsoWidget::updateMathMode() { - measurementMiscLabel[settings->scope.physicalChannels]->setText( - Dso::mathModeString(settings->scope.voltage[settings->scope.physicalChannels].math)); + measurementMiscLabel[settings->deviceSpecification->channels]->setText( + Dso::mathModeString(settings->scope.voltage[settings->deviceSpecification->channels].math)); } /// \brief Handles gainChanged signal from the voltage dock. @@ -389,7 +391,7 @@ void DsoWidget::updateMathMode() { void DsoWidget::updateVoltageGain(unsigned int channel) { if (channel >= (unsigned int)settings->scope.voltage.size()) return; - if (channel < settings->scope.physicalChannels) adaptTriggerLevelSlider(channel); + if (channel < settings->deviceSpecification->channels) adaptTriggerLevelSlider(channel); updateVoltageDetails(channel); } @@ -445,7 +447,8 @@ void DsoWidget::doShowNewData() { exportNextFrame.reset(nullptr); } - bool triggered = generator->generateGraphs(data.get()); + bool triggered = generator->generateGraphs(data.get(), settings->view.digitalPhosphorDraws(),&settings->scope,settings->deviceSpecification->channels); + QPalette triggerLabelPalette = palette(); triggerLabelPalette.setColor(QPalette::WindowText, Qt::black); triggerLabelPalette.setColor(QPalette::Background, triggered ? Qt::green : Qt::red); @@ -453,8 +456,8 @@ void DsoWidget::doShowNewData() { updateRecordLength(data.get()->getMaxSamples()); - for (int channel = 0; channel < (int)settings->scope.voltage.size(); ++channel) { - if (settings->scope.voltage[(unsigned)channel].used && data.get()->data(channel)) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { + if (settings->scope.voltage[channel].used && data.get()->data(channel)) { // Amplitude string representation (4 significant digits) measurementAmplitudeLabel[channel]->setText( valueToString(data.get()->data(channel)->amplitude, UNIT_VOLTS, 4)); @@ -468,11 +471,11 @@ void DsoWidget::doShowNewData() { /// \brief Handles valueChanged signal from the offset sliders. /// \param channel The channel whose offset was changed. /// \param value The new offset for the channel. -void DsoWidget::updateOffset(unsigned channel, double value) { +void DsoWidget::updateOffset(ChannelID channel, double value) { if (channel < settings->scope.voltage.size()) { settings->scope.voltage[channel].offset = value; - if (channel < settings->scope.physicalChannels) adaptTriggerLevelSlider(channel); + if (channel < settings->deviceSpecification->channels) adaptTriggerLevelSlider(channel); } else if (channel < settings->scope.voltage.size() * 2) settings->scope.spectrum[channel - settings->scope.voltage.size()].offset = value; diff --git a/openhantek/src/dsowidget.h b/openhantek/src/dsowidget.h index baf3dac..025be27 100644 --- a/openhantek/src/dsowidget.h +++ b/openhantek/src/dsowidget.h @@ -31,12 +31,12 @@ class DsoWidget : public QWidget { void showNewData(std::unique_ptr data); protected: - void adaptTriggerLevelSlider(unsigned int channel); - void setMeasurementVisible(unsigned int channel, bool visible); + void adaptTriggerLevelSlider(ChannelID channel); + void setMeasurementVisible(ChannelID channel, bool visible); void updateMarkerDetails(); - void updateSpectrumDetails(unsigned int channel); + void updateSpectrumDetails(ChannelID channel); void updateTriggerDetails(); - void updateVoltageDetails(unsigned int channel); + void updateVoltageDetails(ChannelID channel); QGridLayout *mainLayout; ///< The main layout for this widget LevelSlider *offsetSlider; ///< The sliders for the graph offsets @@ -61,12 +61,12 @@ class DsoWidget : public QWidget { QLabel *markerFrequencybaseLabel; ///< The frequencybase for the zoomed scope QGridLayout *measurementLayout; ///< The table for the signal details - QList measurementNameLabel; ///< The name of the channel - QList measurementGainLabel; ///< The gain for the voltage (V/div) - QList measurementMagnitudeLabel; ///< The magnitude for the spectrum (dB/div) - QList measurementMiscLabel; ///< Coupling or math mode - QList measurementAmplitudeLabel; ///< Amplitude of the signal (V) - QList measurementFrequencyLabel; ///< Frequency of the signal (Hz) + std::vector measurementNameLabel; ///< The name of the channel + std::vector measurementGainLabel; ///< The gain for the voltage (V/div) + std::vector measurementMagnitudeLabel; ///< The magnitude for the spectrum (dB/div) + std::vector measurementMiscLabel; ///< Coupling or math mode + std::vector measurementAmplitudeLabel; ///< Amplitude of the signal (V) + std::vector measurementFrequencyLabel; ///< Frequency of the signal (Hz) DsoSettings *settings; ///< The settings provided by the main window GlGenerator *generator; ///< The generator for the OpenGL vertex arrays @@ -111,7 +111,7 @@ class DsoWidget : public QWidget { private slots: // Sliders - void updateOffset(unsigned channel, double value); + void updateOffset(ChannelID channel, double value); void updateTriggerPosition(int index, double value); void updateTriggerLevel(int channel, double value); void updateMarker(int marker, double value); diff --git a/openhantek/src/exporter.cpp b/openhantek/src/exporter.cpp index d675d64..606f808 100644 --- a/openhantek/src/exporter.cpp +++ b/openhantek/src/exporter.cpp @@ -20,6 +20,7 @@ #include "analyse/dataanalyzerresult.h" #include "glgenerator.h" #include "settings.h" +#include "viewconstants.h" #include "utils/dsoStrings.h" #include "utils/printutils.h" @@ -145,16 +146,16 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) { painter.setPen(colorValues->voltage[channel]); painter.drawText(QRectF(0, top, lineHeight * 4, lineHeight), settings->scope.voltage[channel].name); // Print coupling/math mode - if ((unsigned int)channel < settings->scope.physicalChannels) + if ((unsigned int)channel < settings->deviceSpecification->channels) painter.drawText(QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight), - Dso::couplingString(settings->scope.voltage[channel].coupling)); + Dso::couplingString(settings->coupling(channel))); else painter.drawText(QRectF(lineHeight * 4, top, lineHeight * 2, lineHeight), Dso::mathModeString(settings->scope.voltage[channel].math)); // Print voltage gain painter.drawText(QRectF(lineHeight * 6, top, stretchBase * 2, lineHeight), - valueToString(settings->scope.voltage[channel].gain, UNIT_VOLTS, 0) + tr("/div"), + valueToString(settings->scope.gain(channel), UNIT_VOLTS, 0) + tr("/div"), QTextOption(Qt::AlignRight)); // Print spectrum magnitude if (settings->scope.spectrum[channel].used) { @@ -229,9 +230,9 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) { for (int zoomed = 0; zoomed < (settings->view.zoom ? 2 : 1); ++zoomed) { switch (settings->scope.horizontal.format) { - case Dso::GRAPHFORMAT_TY: + case Dso::GraphFormat::TY: // Add graphs for channels - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { if (settings->scope.voltage[channel].used && result->data(channel)) { painter.setPen(QPen(colorValues->voltage[channel], 0)); @@ -257,7 +258,7 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) { for (unsigned int position = firstPosition; position <= lastPosition; ++position) graph[position - firstPosition] = QPointF(position * horizontalFactor - DIVS_TIME / 2, result->data(channel)->voltage.sample[position] / - settings->scope.voltage[channel].gain + + settings->scope.gain(channel) + settings->scope.voltage[channel].offset); painter.drawPolyline(graph, lastPosition - firstPosition + 1); @@ -266,7 +267,7 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) { } // Add spectrum graphs - for (unsigned channel = 0; channel < settings->scope.spectrum.size(); ++channel) { + for (ChannelID channel = 0; channel < settings->scope.spectrum.size(); ++channel) { if (settings->scope.spectrum[channel].used && result->data(channel)) { painter.setPen(QPen(colorValues->spectrum[channel], 0)); @@ -302,7 +303,7 @@ bool Exporter::exportSamples(const DataAnalyzerResult *result) { } break; - case Dso::GRAPHFORMAT_XY: + case Dso::GraphFormat::XY: break; default: diff --git a/openhantek/src/glgenerator.cpp b/openhantek/src/glgenerator.cpp index d72c122..d12b1dc 100644 --- a/openhantek/src/glgenerator.cpp +++ b/openhantek/src/glgenerator.cpp @@ -1,12 +1,27 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include #include "glgenerator.h" #include "utils/printutils.h" #include "settings.h" +#include "analyse/dataanalyzerresult.h" +#include "viewconstants.h" +#include "hantekdso/softwaretrigger.h" -GlGenerator::GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view) : settings(scope), view(view) { +static const SampleValues& useSamplesOf(Dso::ChannelMode mode, ChannelID channel, const DataAnalyzerResult *result, const DsoSettingsScope *scope) { + static SampleValues emptyDefault; + if (mode == Dso::ChannelMode::Voltage) { + if (!scope->voltage[channel].used || !result->data(channel)) return emptyDefault; + return result->data(channel)->voltage; + } else { + if (!scope->spectrum[channel].used || !result->data(channel)) return emptyDefault; + return result->data(channel)->spectrum; + } +} + +GlGenerator::GlGenerator() { // Grid const int DIVS_TIME_S2 = (int)DIVS_TIME - 2; const int DIVS_VOLTAGE_S2 = (int)DIVS_VOLTAGE - 2; @@ -97,109 +112,24 @@ GlGenerator::GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view) : setti *(glIterator++) = DIVS_VOLTAGE / 2; } -const std::vector &GlGenerator::channel(int mode, unsigned channel, unsigned index) const { - return vaChannel[mode][channel][index]; +const std::vector &GlGenerator::channel(Dso::ChannelMode mode, ChannelID channel, unsigned index) const { + return vaChannel[(unsigned)mode][channel][index]; } const std::vector &GlGenerator::grid(int a) const { return vaGrid[a]; } bool GlGenerator::isReady() const { return ready; } -GlGenerator::PrePostStartTriggerSamples GlGenerator::computeSoftwareTriggerTY(const DataAnalyzerResult *result) -{ - unsigned int preTrigSamples = 0; - unsigned int postTrigSamples = 0; - unsigned int swTriggerStart = 0; - unsigned int channel = settings->trigger.source; - - // check trigger point for software trigger - if (settings->trigger.mode != Dso::TRIGGERMODE_SOFTWARE || channel >= settings->physicalChannels) - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); - - // Trigger channel not in use - if (!settings->voltage[channel].used || !result->data(channel) || - result->data(channel)->voltage.sample.empty()) - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); - - const std::vector& samples = result->data(channel)->voltage.sample; - double level = settings->voltage[channel].trigger; - size_t sampleCount = samples.size(); - double timeDisplay = settings->horizontal.timebase * DIVS_TIME; - double samplesDisplay = timeDisplay * settings->horizontal.samplerate; - if (samplesDisplay >= sampleCount) { - // For sure not enough samples to adjust for jitter. - // Following options exist: - // 1: Decrease sample rate - // 2: Change trigger mode to auto - // 3: Ignore samples - // For now #3 is chosen - timestampDebug(QString("Too few samples to make a steady " - "picture. Decrease sample rate")); - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); - } - preTrigSamples = (unsigned)(settings->trigger.position * samplesDisplay); - postTrigSamples = (unsigned)sampleCount - ((unsigned)samplesDisplay - preTrigSamples); - - const int swTriggerThreshold = 7; - const int swTriggerSampleSet = 11; - double prev; - bool (*opcmp)(double,double,double); - bool (*smplcmp)(double,double); - if (settings->trigger.slope == Dso::SLOPE_POSITIVE) { - prev = INT_MAX; - opcmp = [](double value, double level, double prev) { return value > level && prev <= level;}; - smplcmp = [](double sampleK, double value) { return sampleK >= value;}; - } else { - prev = INT_MIN; - opcmp = [](double value, double level, double prev) { return value < level && prev >= level;}; - smplcmp = [](double sampleK, double value) { return sampleK < value;}; - } - - for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) { - double value = samples[i]; - if (opcmp(value, level, prev)) { - int rising = 0; - for (unsigned int k = i + 1; k < i + swTriggerSampleSet && k < sampleCount; k++) { - if (smplcmp(samples[k], value)) { rising++; } - } - if (rising > swTriggerThreshold) { - swTriggerStart = i; - break; - } - } - prev = value; - } - if (swTriggerStart == 0) { - timestampDebug(QString("Trigger not asserted. Data ignored")); - preTrigSamples = 0; // preTrigSamples may never be greater than swTriggerStart - postTrigSamples = 0; - } - return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); -} - -const SampleValues& GlGenerator::useSamplesOf(int mode, unsigned channel, const DataAnalyzerResult *result) const -{ - static SampleValues emptyDefault; - if (mode == Dso::CHANNELMODE_VOLTAGE) { - if (!settings->voltage[channel].used || !result->data(channel)) return emptyDefault; - return result->data(channel)->voltage; - } else { - if (!settings->spectrum[channel].used || !result->data(channel)) return emptyDefault; - return result->data(channel)->spectrum; - } -} - -bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { - - unsigned digitalPhosphorDepth = view->digitalPhosphor ? view->digitalPhosphorDepth : 1; +bool GlGenerator::generateGraphs(const DataAnalyzerResult *result, unsigned digitalPhosphorDepth, + const DsoSettingsScope *scope, unsigned physicalChannels) { // Handle all digital phosphor related list manipulations - for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { - DrawLinesWithHistoryPerChannel& d = vaChannel[mode]; + for (Dso::ChannelMode mode: Dso::ChannelModeEnum) { + DrawLinesWithHistoryPerChannel& d = vaChannel[(unsigned)mode]; // Resize to the number of channels - d.resize(settings->voltage.size()); + d.resize(scope->voltage.size()); - for (unsigned int channel = 0; channel < vaChannel[mode].size(); ++channel) { + for (unsigned int channel = 0; channel < vaChannel[(unsigned)mode].size(); ++channel) { DrawLinesWithHistory& drawLinesHistory = d[channel]; // Move the last list element to the front if (digitalPhosphorDepth > 1 && drawLinesHistory.size()) @@ -216,16 +146,18 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { unsigned postTrigSamples=0; unsigned swTriggerStart=0; bool triggered = false; - switch (settings->horizontal.format) { - case Dso::GRAPHFORMAT_TY: - std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = computeSoftwareTriggerTY(result); + + switch (scope->horizontal.format) { + case Dso::GraphFormat::TY: + std::tie(preTrigSamples, postTrigSamples, swTriggerStart) = SoftwareTrigger::computeTY(result, scope, physicalChannels); triggered = postTrigSamples > preTrigSamples; + // Add graphs for channels - for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { - DrawLinesWithHistoryPerChannel& dPerChannel = vaChannel[mode]; - for (unsigned channel = 0; channel < settings->voltage.size(); ++channel) { + for (Dso::ChannelMode mode: Dso::ChannelModeEnum) { + DrawLinesWithHistoryPerChannel& dPerChannel = vaChannel[(unsigned)mode]; + for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) { DrawLinesWithHistory& withHistory = dPerChannel[channel]; - const SampleValues& samples = useSamplesOf(mode, channel, result); + const SampleValues& samples = useSamplesOf(mode, channel, result, scope); // Check if this channel is used and available at the data analyzer if (samples.sample.empty()) { @@ -236,10 +168,11 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { } // Check if the sample count has changed size_t sampleCount = samples.sample.size(); - if (sampleCount>9000) { - throw new std::runtime_error(""); + if (sampleCount>500000) { + qWarning() << "Sample count too high!"; + throw new std::runtime_error("Sample count too high!"); } - if (mode == Dso::CHANNELMODE_VOLTAGE) + if (mode == Dso::ChannelMode::Voltage) sampleCount -= (swTriggerStart - preTrigSamples); size_t neededSize = sampleCount * 2; @@ -258,17 +191,17 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { // What's the horizontal distance between sampling points? float horizontalFactor; - if (mode == Dso::CHANNELMODE_VOLTAGE) - horizontalFactor = (float)(samples.interval / settings->horizontal.timebase); + if (mode == Dso::ChannelMode::Voltage) + horizontalFactor = (float)(samples.interval / scope->horizontal.timebase); else - horizontalFactor = (float)(samples.interval / settings->horizontal.frequencybase); + horizontalFactor = (float)(samples.interval / scope->horizontal.frequencybase); // Fill vector array - if (mode == Dso::CHANNELMODE_VOLTAGE) { + if (mode == Dso::ChannelMode::Voltage) { std::vector::const_iterator dataIterator = samples.sample.begin(); - const float gain = (float) settings->voltage[channel].gain; - const float offset = (float) settings->voltage[channel].offset; - const float invert = settings->voltage[channel].inverted ? -1.0f : 1.0f; + const float gain = (float) scope->gain(channel); + const float offset = (float) scope->voltage[channel].offset; + const float invert = scope->voltage[channel].inverted ? -1.0f : 1.0f; std::advance(dataIterator, swTriggerStart - preTrigSamples); @@ -278,8 +211,8 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { } } else { std::vector::const_iterator dataIterator = samples.sample.begin(); - const float magnitude = (float)settings->spectrum[channel].magnitude; - const float offset = (float)settings->spectrum[channel].offset; + const float magnitude = (float)scope->spectrum[channel].magnitude; + const float offset = (float)scope->spectrum[channel].offset; for (unsigned int position = 0; position < sampleCount; ++position) { *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2; @@ -290,19 +223,19 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { } break; - case Dso::GRAPHFORMAT_XY: + case Dso::GraphFormat::XY: triggered = true; - for (unsigned channel = 0; channel < settings->voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < scope->voltage.size(); ++channel) { // For even channel numbers check if this channel is used and this and the // following channel are available at the data analyzer - if (channel % 2 == 0 && channel + 1 < settings->voltage.size() && settings->voltage[channel].used && + if (channel % 2 == 0 && channel + 1 < scope->voltage.size() && scope->voltage[channel].used && result->data(channel) && !result->data(channel)->voltage.sample.empty() && result->data(channel + 1) && !result->data(channel + 1)->voltage.sample.empty()) { // Check if the sample count has changed const size_t sampleCount = std::min(result->data(channel)->voltage.sample.size(), result->data(channel + 1)->voltage.sample.size()); const size_t neededSize = sampleCount * 2; - DrawLinesWithHistory& withHistory = vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel]; + DrawLinesWithHistory& withHistory = vaChannel[(unsigned)Dso::ChannelMode::Voltage][(size_t)channel]; for (unsigned index = 0; index < digitalPhosphorDepth; ++index) { if (withHistory[index].size() != neededSize) withHistory[index].clear(); // Something was changed, drop old traces @@ -320,12 +253,12 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { unsigned int yChannel = channel + 1; std::vector::const_iterator xIterator = result->data(xChannel)->voltage.sample.begin(); std::vector::const_iterator yIterator = result->data(yChannel)->voltage.sample.begin(); - const double xGain = settings->voltage[xChannel].gain; - const double yGain = settings->voltage[yChannel].gain; - const double xOffset = settings->voltage[xChannel].offset; - const double yOffset = settings->voltage[yChannel].offset; - const double xInvert = settings->voltage[xChannel].inverted ? -1.0 : 1.0; - const double yInvert = settings->voltage[yChannel].inverted ? -1.0 : 1.0; + const double xGain = scope->gain(xChannel); + const double yGain = scope->gain(yChannel); + const double xOffset = scope->voltage[xChannel].offset; + const double yOffset = scope->voltage[yChannel].offset; + const double xInvert = scope->voltage[xChannel].inverted ? -1.0 : 1.0; + const double yInvert = scope->voltage[yChannel].inverted ? -1.0 : 1.0; for (unsigned int position = 0; position < sampleCount; ++position) { *(glIterator++) = (GLfloat)( *(xIterator++) / xGain * xInvert + xOffset); @@ -333,18 +266,15 @@ bool GlGenerator::generateGraphs(const DataAnalyzerResult *result) { } } else { // Delete all vector arrays - for (unsigned int index = 0; index < (unsigned)digitalPhosphorDepth; ++index) - vaChannel[Dso::CHANNELMODE_VOLTAGE][(size_t)channel][index].clear(); + for (unsigned index = 0; index < digitalPhosphorDepth; ++index) + vaChannel[(unsigned)Dso::ChannelMode::Voltage][channel][index].clear(); } // Delete all spectrum graphs - for (unsigned int index = 0; index < (unsigned)digitalPhosphorDepth; ++index) - vaChannel[Dso::CHANNELMODE_SPECTRUM][(size_t)channel][index].clear(); + for (unsigned index = 0; index < digitalPhosphorDepth; ++index) + vaChannel[(unsigned)Dso::ChannelMode::Spectrum][channel][index].clear(); } break; - - default: - break; } emit graphsGenerated(); diff --git a/openhantek/src/glgenerator.h b/openhantek/src/glgenerator.h index 7ea4322..9eb5f7b 100644 --- a/openhantek/src/glgenerator.h +++ b/openhantek/src/glgenerator.h @@ -7,11 +7,11 @@ #include #include -#include "analyse/dataanalyzerresult.h" -#include "scopesettings.h" -#include "viewconstants.h" -#include "viewsettings.h" -class GlScope; +#include "hantekdso/enums.h" +#include "hantekprotocol/definitions.h" + +struct DsoSettingsScope; +class DataAnalyzerResult; //////////////////////////////////////////////////////////////////////////////// /// \class GlGenerator @@ -23,26 +23,22 @@ class GlGenerator : public QObject { /// \brief Initializes the scope widget. /// \param settings The target settings object. /// \param parent The parent widget. - GlGenerator(DsoSettingsScope *scope, DsoSettingsView *view); - bool generateGraphs(const DataAnalyzerResult *result); - const std::vector &channel(int mode, unsigned channel, unsigned index) const; + + GlGenerator(); + bool generateGraphs(const DataAnalyzerResult *result, unsigned digitalPhosphorDepth, const DsoSettingsScope *scope, + unsigned physicalChannels); + const std::vector &channel(Dso::ChannelMode mode, ChannelID channel, unsigned index) const; + const std::vector &grid(int a) const; bool isReady() const; private: - typedef std::tuple PrePostStartTriggerSamples; typedef std::vector DrawLines; typedef std::deque DrawLinesWithHistory; typedef std::vector DrawLinesWithHistoryPerChannel; - DrawLinesWithHistoryPerChannel vaChannel[Dso::CHANNELMODE_COUNT]; - - PrePostStartTriggerSamples computeSoftwareTriggerTY(const DataAnalyzerResult *result); - DsoSettingsScope *settings; - DsoSettingsView *view; + DrawLinesWithHistoryPerChannel vaChannel[Dso::ChannelModes]; std::vector vaGrid[3]; bool ready = false; - - const SampleValues &useSamplesOf(int mode, unsigned channel, const DataAnalyzerResult *result) const; signals: void graphsGenerated(); ///< The graphs are ready to be drawn }; diff --git a/openhantek/src/glscope.cpp b/openhantek/src/glscope.cpp index 267088c..3846746 100644 --- a/openhantek/src/glscope.cpp +++ b/openhantek/src/glscope.cpp @@ -8,13 +8,13 @@ #include "glgenerator.h" #include "settings.h" +#include "viewconstants.h" GlScope::GlScope(DsoSettings *settings, const GlGenerator *generator, QWidget *parent) : GL_WIDGET_CLASS(parent), settings(settings), generator(generator) { connect(generator, &GlGenerator::graphsGenerated, [this]() { update(); }); } -/// \brief Initializes OpenGL output. void GlScope::initializeGL() { glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); @@ -23,7 +23,7 @@ void GlScope::initializeGL() { glPointSize(1); QColor bg = settings->view.screen.background; - glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); + glClearColor((GLfloat)bg.redF(), (GLfloat)bg.greenF(), (GLfloat)bg.blueF(), (GLfloat)bg.alphaF()); glShadeModel(GL_SMOOTH /*GL_FLAT*/); glLineStipple(1, 0x3333); @@ -31,20 +31,18 @@ void GlScope::initializeGL() { glEnableClientState(GL_VERTEX_ARRAY); } -/// \brief Draw the graphs and the grid. void GlScope::paintGL() { // Clear OpenGL buffer and configure settings glClear(GL_COLOR_BUFFER_BIT); glLineWidth(1); - int digitalPhosphorDepth = settings->view.digitalPhosphor ? settings->view.digitalPhosphorDepth : 1; - if (generator->isReady()) { drawGraph(digitalPhosphorDepth); } + if (generator->isReady()) { drawGraph(settings->view.digitalPhosphorDraws()); } if (!this->zoomed) { // Draw vertical lines at marker positions glEnable(GL_LINE_STIPPLE); QColor trColor = settings->view.screen.markers; - glColor4f(trColor.redF(), trColor.greenF(), trColor.blueF(), trColor.alphaF()); + glColor4f((GLfloat)trColor.redF(), (GLfloat)trColor.greenF(), (GLfloat)trColor.blueF(), (GLfloat)trColor.alphaF()); for (int marker = 0; marker < MARKER_COUNT; ++marker) { if (!settings->scope.horizontal.marker_visible[marker]) continue; @@ -54,11 +52,11 @@ void GlScope::paintGL() { vaMarker[marker][3] = DIVS_VOLTAGE; } - vaMarker[marker][0] = settings->scope.horizontal.marker[marker]; - vaMarker[marker][2] = settings->scope.horizontal.marker[marker]; + vaMarker[marker][0] = (GLfloat)settings->scope.horizontal.marker[marker]; + vaMarker[marker][2] = (GLfloat)settings->scope.horizontal.marker[marker]; glVertexPointer(2, GL_FLOAT, 0, &vaMarker[marker].front()); - glDrawArrays(GL_LINES, 0, vaMarker[marker].size() / 2); + glDrawArrays(GL_LINES, 0, (GLsizei)vaMarker[marker].size() / 2); } glDisable(GL_LINE_STIPPLE); @@ -68,9 +66,6 @@ void GlScope::paintGL() { this->drawGrid(); } -/// \brief Resize the widget. -/// \param width The new width of the widget. -/// \param height The new height of the widget. void GlScope::resizeGL(int width, int height) { glViewport(0, 0, (GLint)width, (GLint)height); @@ -80,8 +75,8 @@ void GlScope::resizeGL(int width, int height) { glLoadIdentity(); GLdouble pixelizationWidthCorrection = (width > 0) ? (GLdouble)width / (width - 1) : 1; GLdouble pixelizationHeightCorrection = (height > 0) ? (GLdouble)height / (height - 1) : 1; - glOrtho(-(DIVS_TIME / 2) * pixelizationWidthCorrection, (DIVS_TIME / 2) * pixelizationWidthCorrection, - -(DIVS_VOLTAGE / 2) * pixelizationHeightCorrection, (DIVS_VOLTAGE / 2) * pixelizationHeightCorrection, -1.0, + glOrtho(-(DIVS_TIME / 2.0) * pixelizationWidthCorrection, (DIVS_TIME / 2.0) * pixelizationWidthCorrection, + -(DIVS_VOLTAGE / 2.0) * pixelizationHeightCorrection, (DIVS_VOLTAGE / 2.0) * pixelizationHeightCorrection, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); @@ -89,9 +84,8 @@ void GlScope::resizeGL(int width, int height) { /// \brief Set the zoom mode for this GlScope. /// \param zoomed true magnifies the area between the markers. -void GlScope::setZoomMode(bool zoomed) { this->zoomed = zoomed; } +void GlScope::setZoomMode(bool zoomEnabled) { this->zoomed = zoomEnabled; } -/// \brief Draw the grid. void GlScope::drawGrid() { glDisable(GL_POINT_SMOOTH); glDisable(GL_LINE_SMOOTH); @@ -99,35 +93,35 @@ void GlScope::drawGrid() { QColor color; // Grid color = settings->view.screen.grid; - glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF()); + glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF()); glVertexPointer(2, GL_FLOAT, 0, &generator->grid(0).front()); - glDrawArrays(GL_POINTS, 0, generator->grid(0).size() / 2); + glDrawArrays(GL_POINTS, 0, (GLsizei) generator->grid(0).size() / 2); // Axes color = settings->view.screen.axes; - glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF()); + glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF()); glVertexPointer(2, GL_FLOAT, 0, &generator->grid(1).front()); - glDrawArrays(GL_LINES, 0, generator->grid(1).size() / 2); + glDrawArrays(GL_LINES, 0, (GLsizei) generator->grid(1).size() / 2); // Border color = settings->view.screen.border; - glColor4f(color.redF(), color.greenF(), color.blueF(), color.alphaF()); + glColor4f((GLfloat)color.redF(), (GLfloat)color.greenF(), (GLfloat)color.blueF(), (GLfloat)color.alphaF()); glVertexPointer(2, GL_FLOAT, 0, &generator->grid(2).front()); - glDrawArrays(GL_LINE_LOOP, 0, generator->grid(2).size() / 2); + glDrawArrays(GL_LINE_LOOP, 0, (GLsizei) generator->grid(2).size() / 2); } -void GlScope::drawGraphDepth(int mode, int channel, int index) { +void GlScope::drawGraphDepth(Dso::ChannelMode mode, ChannelID channel, unsigned index) { if (generator->channel(mode, channel, index).empty()) return; QColor trColor; - if (mode == Dso::CHANNELMODE_VOLTAGE) + if (mode == Dso::ChannelMode::Voltage) trColor = settings->view.screen.voltage[channel].darker(fadingFactor[index]); else trColor = settings->view.screen.spectrum[channel].darker(fadingFactor[index]); - glColor4f(trColor.redF(), trColor.greenF(), trColor.blueF(), trColor.alphaF()); + glColor4f((GLfloat)trColor.redF(), (GLfloat)trColor.greenF(), (GLfloat)trColor.blueF(), (GLfloat)trColor.alphaF()); glVertexPointer(2, GL_FLOAT, 0, &generator->channel(mode, channel, index).front()); glDrawArrays((settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, - generator->channel(mode, channel, index).size() / 2); + (GLsizei)generator->channel(mode, channel, index).size() / 2); } -void GlScope::drawGraph(int digitalPhosphorDepth) { +void GlScope::drawGraph(unsigned digitalPhosphorDepth) { if (settings->view.antialiasing) { glEnable(GL_POINT_SMOOTH); glEnable(GL_LINE_SMOOTH); @@ -137,57 +131,53 @@ void GlScope::drawGraph(int digitalPhosphorDepth) { // Apply zoom settings via matrix transformation if (this->zoomed) { glPushMatrix(); - glScalef(DIVS_TIME / fabs(settings->scope.horizontal.marker[1] - settings->scope.horizontal.marker[0]), 1.0, - 1.0); - glTranslatef(-(settings->scope.horizontal.marker[0] + settings->scope.horizontal.marker[1]) / 2, 0.0, 0.0); + glScalef(DIVS_TIME / (GLfloat)fabs(settings->scope.horizontal.marker[1] - settings->scope.horizontal.marker[0]), 1.0f, + 1.0f); + glTranslatef((GLfloat)-(settings->scope.horizontal.marker[0] + settings->scope.horizontal.marker[1]) / 2, 0.0f, 0.0f); } // Values we need for the fading of the digital phosphor - if ((int)fadingFactor.size() != digitalPhosphorDepth) { - fadingFactor.resize((size_t)digitalPhosphorDepth); + if (fadingFactor.size() != digitalPhosphorDepth) { + fadingFactor.resize(digitalPhosphorDepth); fadingFactor[0] = 100; double fadingRatio = pow(10.0, 2.0 / digitalPhosphorDepth); for (size_t index = 1; index < (size_t)digitalPhosphorDepth; ++index) - fadingFactor[index] = fadingFactor[index - 1] * fadingRatio; + fadingFactor[index] = int(fadingFactor[index - 1] * fadingRatio); } switch (settings->scope.horizontal.format) { - case Dso::GRAPHFORMAT_TY: + case Dso::GraphFormat::TY: // Real and virtual channels - for (int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { - for (int channel = 0; channel < settings->scope.voltage.size(); ++channel) { + for (Dso::ChannelMode mode: Dso::ChannelModeEnum) { + for (ChannelID channel = 0; channel < settings->scope.voltage.size(); ++channel) { if (!channelUsed(mode, channel)) continue; // Draw graph for all available depths - for (int index = digitalPhosphorDepth - 1; index >= 0; index--) { - drawGraphDepth(mode, channel, index); + for (unsigned index = digitalPhosphorDepth; index > 0; index--) { + drawGraphDepth(mode, channel, index-1); } } } break; - - case Dso::GRAPHFORMAT_XY: + case Dso::GraphFormat::XY: + const Dso::ChannelMode mode = Dso::ChannelMode::Voltage; // Real and virtual channels - for (int channel = 0; channel < settings->scope.voltage.size() - 1; channel += 2) { - if (settings->scope.voltage[channel].used) { - for (int index = digitalPhosphorDepth - 1; index >= 0; index--) { - drawGraphDepth(Dso::CHANNELMODE_VOLTAGE, channel, index); - } + for (ChannelID channel = 0; channel < settings->scope.voltage.size() - 1; channel += 2) { + if (!channelUsed(mode, channel)) continue; + for (unsigned index = digitalPhosphorDepth; index > 0; index--) { + drawGraphDepth(mode, channel, index-1); } } break; - - default: - break; } glDisable(GL_POINT_SMOOTH); glDisable(GL_LINE_SMOOTH); - if (this->zoomed) glPopMatrix(); + if (zoomed) glPopMatrix(); } -bool GlScope::channelUsed(int mode, int channel) { - return (mode == Dso::CHANNELMODE_VOLTAGE) ? settings->scope.voltage[channel].used +bool GlScope::channelUsed(Dso::ChannelMode mode, ChannelID channel) { + return (mode == Dso::ChannelMode::Voltage) ? settings->scope.voltage[channel].used : settings->scope.spectrum[channel].used; } diff --git a/openhantek/src/glscope.h b/openhantek/src/glscope.h index 8e27f24..362d6d3 100644 --- a/openhantek/src/glscope.h +++ b/openhantek/src/glscope.h @@ -5,6 +5,7 @@ #include #include #include + #if (QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)) #include using GL_WIDGET_CLASS = QOpenGLWidget; @@ -13,11 +14,12 @@ using GL_WIDGET_CLASS = QOpenGLWidget; using GL_WIDGET_CLASS = QGLWidget; #endif +#include "hantekdso/enums.h" +#include "hantekprotocol/definitions.h" + class GlGenerator; class DsoSettings; -//////////////////////////////////////////////////////////////////////////////// -/// \class GlScope glscope.h /// \brief OpenGL accelerated widget that displays the oscilloscope screen. class GlScope : public GL_WIDGET_CLASS { Q_OBJECT @@ -28,22 +30,37 @@ class GlScope : public GL_WIDGET_CLASS { /// \param parent The parent widget. GlScope(DsoSettings *settings, const GlGenerator *generator, QWidget *parent = 0); - void setZoomMode(bool zoomed); + void setZoomMode(bool zoomEnabled); protected: + /// \brief Initializes OpenGL output. void initializeGL() override; + + /// \brief Draw the graphs and the grid. void paintGL() override; + + /// \brief Resize the widget. + /// \param width The new width of the widget. + /// \param height The new height of the widget. void resizeGL(int width, int height) override; + /// \brief Draw the grid. void drawGrid(); - void drawGraphDepth(int mode, int channel, int index); - void drawGraph(int digitalPhosphorDepth); - bool channelUsed(int mode, int channel); + + void drawGraphDepth(Dso::ChannelMode mode, ChannelID channel, unsigned index); + void drawGraph(unsigned digitalPhosphorDepth); + + /** + * @brief Return true if the given channel with the given mode is used + * @param mode The channel mode (spectrum/voltage) + * @param channel The channel + */ + bool channelUsed(Dso::ChannelMode mode, ChannelID channel); private: DsoSettings *settings; const GlGenerator *generator; - std::vector fadingFactor; + std::vector fadingFactor; std::vector vaMarker[2]; bool zoomed = false; diff --git a/openhantek/src/hantekdso/controlindexes.h b/openhantek/src/hantekdso/controlindexes.h deleted file mode 100644 index 6f0d2a7..0000000 --- a/openhantek/src/hantekdso/controlindexes.h +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ - -#pragma once - -namespace Hantek { - -////////////////////////////////////////////////////////////////////////////// -/// \enum ControlIndex -/// \brief The array indices for the waiting control commands. -enum ControlIndex { - CONTROLINDEX_SETOFFSET, - CONTROLINDEX_SETRELAYS, - CONTROLINDEX_SETVOLTDIV_CH1, - CONTROLINDEX_SETVOLTDIV_CH2, - CONTROLINDEX_SETTIMEDIV, ///< For 6022BL/BE - CONTROLINDEX_ACQUIIRE_HARD_DATA, ///< For 6022BL/BE - CONTROLINDEX_COUNT -}; - -} diff --git a/openhantek/src/hantekdso/controlsettings.cpp b/openhantek/src/hantekdso/controlsettings.cpp index b3f0d4a..8ee3c76 100644 --- a/openhantek/src/hantekdso/controlsettings.cpp +++ b/openhantek/src/hantekdso/controlsettings.cpp @@ -1,13 +1,13 @@ #include "controlsettings.h" -namespace Hantek { +namespace Dso { ControlSettings::ControlSettings(ControlSamplerateLimits* limits, size_t channelCount) { samplerate.limits = limits; trigger.level.resize(channelCount); voltage.resize(channelCount); - for (unsigned channel = 0; channel < channelCount; ++channel) { + for (ChannelID channel = 0; channel < channelCount; ++channel) { trigger.level[channel] = 0.0; voltage[channel].gain = 0; voltage[channel].offset = 0.0; diff --git a/openhantek/src/hantekdso/controlsettings.h b/openhantek/src/hantekdso/controlsettings.h index a03ef04..98fca3b 100644 --- a/openhantek/src/hantekdso/controlsettings.h +++ b/openhantek/src/hantekdso/controlsettings.h @@ -1,8 +1,9 @@ #pragma once +#include "controlspecification.h" #include "enums.h" -namespace Hantek { +namespace Dso { struct ControlSamplerateLimits; @@ -10,9 +11,9 @@ struct ControlSamplerateLimits; /// \struct ControlSettingsSamplerateTarget hantek/control.h /// \brief Stores the target samplerate settings of the device. struct ControlSettingsSamplerateTarget { - double samplerate; ///< The target samplerate set via setSamplerate - double duration; ///< The target record time set via setRecordTime - bool samplerateSet; ///< true means samplerate was set last, false duration + double samplerate; ///< The target samplerate set via setSamplerate + double duration; ///< The target record time set via setRecordTime + enum SamplerrateSet { Duration, Samplerrate } samplerateSet; }; ////////////////////////////////////////////////////////////////////////////// @@ -21,21 +22,21 @@ struct ControlSettingsSamplerateTarget { struct ControlSettingsSamplerate { ControlSettingsSamplerateTarget target; ///< The target samplerate values ControlSamplerateLimits *limits; ///< The samplerate limits - unsigned int downsampler = 1; ///< The variable downsampling factor - double current = 1e8; ///< The current samplerate + unsigned int downsampler = 1; ///< The variable downsampling factor + double current = 1e8; ///< The current samplerate }; ////////////////////////////////////////////////////////////////////////////// /// \struct ControlSettingsTrigger hantek/control.h /// \brief Stores the current trigger settings of the device. struct ControlSettingsTrigger { - std::vector level; ///< The trigger level for each channel in V - double position = 0.0; ///< The current pretrigger position - unsigned int point = 0; ///< The trigger position in Hantek coding - Dso::TriggerMode mode = Dso::TRIGGERMODE_NORMAL; ///< The trigger mode - Dso::Slope slope = Dso::SLOPE_POSITIVE; ///< The trigger slope - bool special = false; ///< true, if the trigger source is special - unsigned int source = 0; ///< The trigger source + std::vector level; ///< The trigger level for each channel in V + double position = 0.0; ///< The current pretrigger position + unsigned int point = 0; ///< The trigger position in Hantek coding + Dso::TriggerMode mode = Dso::TriggerMode::NORMAL; ///< The trigger mode + Dso::Slope slope = Dso::Slope::Positive; ///< The trigger slope + bool special = false; ///< true, if the trigger source is special + unsigned int source = 0; ///< The trigger source }; ////////////////////////////////////////////////////////////////////////////// @@ -53,14 +54,12 @@ struct ControlSettingsVoltage { /// \brief Stores the current settings of the device. struct ControlSettings { ControlSettings(ControlSamplerateLimits *limits, size_t channelCount); - ControlSettingsSamplerate samplerate; ///< The samplerate settings + ControlSettingsSamplerate samplerate; ///< The samplerate settings std::vector voltage; ///< The amplification settings - ControlSettingsTrigger trigger; ///< The trigger settings - unsigned recordLengthId = 1; ///< The id in the record length array - unsigned usedChannels = 0; ///< Number of activated channels + ControlSettingsTrigger trigger; ///< The trigger settings + RecordLengthID recordLengthId = 1; ///< The id in the record length array + unsigned usedChannels = 0; ///< Number of activated channels // Software trigger, margin const unsigned swtriggerSampleMargin = 2000; }; - } - diff --git a/openhantek/src/hantekdso/controlspecification.h b/openhantek/src/hantekdso/controlspecification.h index b646994..12aef12 100644 --- a/openhantek/src/hantekdso/controlspecification.h +++ b/openhantek/src/hantekdso/controlspecification.h @@ -2,58 +2,33 @@ #pragma once -#include "hantekprotocol/controlvalue.h" +#include "enums.h" #include "hantekprotocol/bulkcode.h" #include "hantekprotocol/controlcode.h" +#include "hantekprotocol/controlvalue.h" #include "hantekprotocol/definitions.h" #include -namespace Hantek { +namespace Dso { -typedef unsigned RecordLengthID; -typedef unsigned ChannelID; +using namespace Hantek; -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSpecificationCommandsBulk hantek/control.h /// \brief Stores the bulk command codes used for this device. struct ControlSpecificationCommandsBulk { - BulkCode setChannels = (BulkCode)-1; ///< Command for setting used channels - BulkCode setSamplerate = (BulkCode)-1; ///< Command for samplerate settings - BulkCode setGain = (BulkCode)-1; ///< Command for gain settings (Usually in combination with - /// CONTROL_SETRELAYS) - BulkCode setRecordLength = (BulkCode)-1; ///< Command for buffer settings - BulkCode setTrigger = (BulkCode)-1; ///< Command for trigger settings - BulkCode setPretrigger = (BulkCode)-1; ///< Command for pretrigger settings + BulkCode setChannels = BulkCode::INVALID; ///< Command for setting used channels + BulkCode setSamplerate = BulkCode::INVALID; ///< Command for samplerate settings + BulkCode setGain = BulkCode::SETGAIN; ///< Command for gain settings (Usually in combination with + /// CONTROL_SETRELAYS) + BulkCode setRecordLength = BulkCode::INVALID; ///< Command for buffer settings + BulkCode setTrigger = BulkCode::INVALID; ///< Command for trigger settings + BulkCode setPretrigger = BulkCode::INVALID; ///< Command for pretrigger settings }; -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSpecificationCommandsControl hantek/control.h -/// \brief Stores the control command codes used for this device. -struct ControlSpecificationCommandsControl { - ControlCode setOffset = (ControlCode)-1; ///< Command for setting offset calibration data - ControlCode setRelays = (ControlCode)-1; ///< Command for setting gain relays (Usually in - /// combination with BulkCode::SETGAIN) -}; - -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSpecificationCommandsValues hantek/control.h -/// \brief Stores the control value codes used for this device. -struct ControlSpecificationCommandsValues { - ControlValue offsetLimits = VALUE_OFFSETLIMITS; ///< Code for channel offset limits - ControlValue voltageLimits = (ControlValue)-1; ///< Code for voltage limits -}; - -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSpecificationCommands hantek/control.h /// \brief Stores the command codes used for this device. struct ControlSpecificationCommands { - ControlSpecificationCommandsBulk bulk; ///< The used bulk commands - ControlSpecificationCommandsControl control; ///< The used control commands - ControlSpecificationCommandsValues values; ///< The used control values + ControlSpecificationCommandsBulk bulk; ///< The used bulk commands }; -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSamplerateLimits hantek/control.h /// \brief Stores the samplerate limits for calculations. struct ControlSamplerateLimits { double base; ///< The base for sample rate calculations @@ -62,12 +37,10 @@ struct ControlSamplerateLimits { std::vector recordLengths; ///< Available record lengths, UINT_MAX means rolling }; -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSpecificationSamplerate hantek/control.h /// \brief Stores the samplerate limits. struct ControlSpecificationSamplerate { - ControlSamplerateLimits single = {50e6, 50e6, 0, std::vector()}; ///< The limits for single channel mode - ControlSamplerateLimits multi = {100e6, 100e6, 0, std::vector()}; ///< The limits for multi channel mode + ControlSamplerateLimits single = {50e6, 50e6, 0, std::vector()}; ///< The limits for single channel mode + ControlSamplerateLimits multi = {100e6, 100e6, 0, std::vector()}; ///< The limits for multi channel mode }; struct ControlSpecificationGainLevel { @@ -87,17 +60,17 @@ struct SpecialTriggerChannel { int hardwareID; }; -////////////////////////////////////////////////////////////////////////////// -/// \struct ControlSpecification hantek/control.h /// \brief Stores the specifications of the currently connected device. struct ControlSpecification { + ChannelID channels = HANTEK_CHANNELS; + // Interface ControlSpecificationCommands command; ///< The commands for this device // Limits - ControlSpecificationSamplerate samplerate; ///< The samplerate specifications - std::vector bufferDividers; ///< Samplerate dividers for record lengths - unsigned char sampleSize; ///< Number of bits per sample + ControlSpecificationSamplerate samplerate; ///< The samplerate specifications + std::vector bufferDividers; ///< Samplerate dividers for record lengths + unsigned char sampleSize; ///< Number of bits per sample // Calibration /// The sample values at the top of the screen @@ -112,6 +85,7 @@ struct ControlSpecification { std::vector fixedSampleRates; std::vector specialTriggerChannels; + std::vector couplings = {Dso::Coupling::DC, Dso::Coupling::AC}; bool isFixedSamplerateDevice = false; bool isSoftwareTriggerDevice = false; @@ -120,6 +94,4 @@ struct ControlSpecification { bool supportsOffset = true; bool supportsCouplingRelays = true; }; - } - diff --git a/openhantek/src/hantekdso/dsomodel.cpp b/openhantek/src/hantekdso/dsomodel.cpp index 33b1ee4..f9a10d9 100644 --- a/openhantek/src/hantekdso/dsomodel.cpp +++ b/openhantek/src/hantekdso/dsomodel.cpp @@ -4,6 +4,6 @@ #include "dsomodel.h" DSOModel::DSOModel(int id, long vendorID, long productID, long vendorIDnoFirmware, - long productIDnoFirmware, const std::string &firmwareToken, const std::string &name, const Hantek::ControlSpecification &specification) + long productIDnoFirmware, const std::string &firmwareToken, const std::string &name, const Dso::ControlSpecification &specification) : ID(id), vendorID(vendorID), productID(productID), vendorIDnoFirmware(vendorIDnoFirmware), productIDnoFirmware(productIDnoFirmware), firmwareToken(firmwareToken), name(name), specification(specification) {} diff --git a/openhantek/src/hantekdso/dsomodel.h b/openhantek/src/hantekdso/dsomodel.h index dda3061..2896dba 100644 --- a/openhantek/src/hantekdso/dsomodel.h +++ b/openhantek/src/hantekdso/dsomodel.h @@ -25,12 +25,12 @@ class DSOModel { /// The firmwareToken is the "devicename" of the pattern above. std::string firmwareToken; std::string name; ///< User visible name. Does not need internationalisation/translation. - Hantek::ControlSpecification specification; + Dso::ControlSpecification specification; public: /// This model may need to modify the HantekDsoControl class to work correctly virtual void applyRequirements(HantekDsoControl*) const = 0; DSOModel(int id, long vendorID, long productID, long vendorIDnoFirmware, long productIDnoFirmware, - const std::string& firmwareToken, const std::string& name, const Hantek::ControlSpecification& specification); + const std::string& firmwareToken, const std::string& name, const Dso::ControlSpecification& specification); virtual ~DSOModel() = default; }; diff --git a/openhantek/src/hantekdso/enums.cpp b/openhantek/src/hantekdso/enums.cpp new file mode 100644 index 0000000..344fadd --- /dev/null +++ b/openhantek/src/hantekdso/enums.cpp @@ -0,0 +1,8 @@ +#include "enums.h" + +namespace Dso { + Enum TriggerModeEnum; + Enum SlopeEnum; + Enum GraphFormatEnum; + Enum ChannelModeEnum; +} diff --git a/openhantek/src/hantekdso/enums.h b/openhantek/src/hantekdso/enums.h index e646544..d5856c6 100644 --- a/openhantek/src/hantekdso/enums.h +++ b/openhantek/src/hantekdso/enums.h @@ -1,50 +1,51 @@ #pragma once -#include #include "utils/enumclass.h" +#include namespace Dso { /// \enum ChannelMode /// \brief The channel display modes. -enum ChannelMode { - CHANNELMODE_VOLTAGE, ///< Standard voltage view - CHANNELMODE_SPECTRUM, ///< Spectrum view - CHANNELMODE_COUNT ///< The total number of modes +enum class ChannelMode { + Voltage, ///< Standard voltage view + Spectrum ///< Spectrum view }; +constexpr int ChannelModes = 2; +extern Enum ChannelModeEnum; /// \enum GraphFormat /// \brief The possible viewing formats for the graphs on the scope. enum GraphFormat { - GRAPHFORMAT_TY, ///< The standard mode - GRAPHFORMAT_XY, ///< CH1 on X-axis, CH2 on Y-axis - GRAPHFORMAT_COUNT ///< The total number of formats + TY, ///< The standard mode + XY ///< CH1 on X-axis, CH2 on Y-axis }; +extern Enum GraphFormatEnum; + /// \enum Coupling /// \brief The coupling modes for the channels. -enum Coupling { - COUPLING_AC, ///< Offset filtered out by condensator - COUPLING_DC, ///< No filtering - COUPLING_GND, ///< Channel is grounded - COUPLING_COUNT ///< The total number of coupling modes +enum class Coupling { + AC, ///< Offset filtered out by condensator + DC, ///< No filtering + GND ///< Channel is grounded }; /// \enum TriggerMode /// \brief The different triggering modes. -enum TriggerMode { - TRIGGERMODE_AUTO, ///< Automatic without trigger event - TRIGGERMODE_NORMAL, ///< Normal mode - TRIGGERMODE_SINGLE, ///< Stop after the first trigger event - TRIGGERMODE_SOFTWARE, ///< Software trigger mode - TRIGGERMODE_COUNT ///< The total number of modes +enum class TriggerMode { + AUTO, ///< Automatic without trigger event + NORMAL, ///< Normal mode + SINGLE, ///< Stop after the first trigger event + SOFTWARE ///< Software trigger mode }; +extern Enum TriggerModeEnum; /// \enum Slope /// \brief The slope that causes a trigger. -enum Slope { - SLOPE_POSITIVE, ///< From lower to higher voltage - SLOPE_NEGATIVE, ///< From higher to lower voltage - SLOPE_COUNT ///< Total number of trigger slopes +enum class Slope : uint8_t { + Positive = 0, ///< From lower to higher voltage + Negative = 1 ///< From higher to lower voltage }; +extern Enum SlopeEnum; /// \enum InterpolationMode /// \brief The different interpolation modes for the graphs. @@ -62,4 +63,3 @@ Q_DECLARE_METATYPE(Dso::Coupling) Q_DECLARE_METATYPE(Dso::GraphFormat) Q_DECLARE_METATYPE(Dso::ChannelMode) Q_DECLARE_METATYPE(Dso::InterpolationMode) - diff --git a/openhantek/src/hantekdso/hantekdsocontrol.cpp b/openhantek/src/hantekdso/hantekdsocontrol.cpp index 033ac6f..1166749 100644 --- a/openhantek/src/hantekdso/hantekdsocontrol.cpp +++ b/openhantek/src/hantekdso/hantekdsocontrol.cpp @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0+ +#include #include #include +#include #include -#include #include #include @@ -17,9 +18,9 @@ #include "models/modelDSO6022.h" #include "usb/usbdevice.h" #include "utils/printutils.h" -#include using namespace Hantek; +using namespace Dso; /// \brief Start sampling process. void HantekDsoControl::startSampling() { @@ -35,7 +36,7 @@ void HantekDsoControl::startSampling() { if (specification.isFixedSamplerateDevice) { // Convert to GUI presentable values (1e5 -> 1.0, 48e6 -> 480.0 etc) QList sampleSteps; - for (auto& v : specification.fixedSampleRates) { sampleSteps << v.samplerate / 1e5; } + for (auto &v : specification.fixedSampleRates) { sampleSteps << v.samplerate / 1e5; } emit samplerateSet(1, sampleSteps); } @@ -48,12 +49,9 @@ void HantekDsoControl::stopSampling() { emit samplingStopped(); } -const std::vector HantekDsoControl::getSpecialTriggerSources() -{ +const std::vector HantekDsoControl::getSpecialTriggerSources() { std::vector sources; - for (auto& v: specification.specialTriggerChannels) { - sources.push_back(v.name); - } + for (auto &v : specification.specialTriggerChannels) { sources.push_back(v.name); } return sources; } @@ -61,26 +59,22 @@ USBDevice *HantekDsoControl::getDevice() { return device; } const DSOsamples &HantekDsoControl::getLastSamples() { return result; } -HantekDsoControl::HantekDsoControl(USBDevice *device) : device(device), - specification(device->getModel()->specification), controlsettings(&(specification.samplerate.single), HANTEK_CHANNELS) { +HantekDsoControl::HantekDsoControl(USBDevice *device) + : device(device), specification(device->getModel()->specification), + controlsettings(&(specification.samplerate.single), specification.channels) { if (device == nullptr) throw new std::runtime_error("No usb device for HantekDsoControl"); - // Transmission-ready control commands - this->control[CONTROLINDEX_SETOFFSET] = new ControlSetOffset(); - this->controlCode[CONTROLINDEX_SETOFFSET] = CONTROL_SETOFFSET; - this->control[CONTROLINDEX_SETRELAYS] = new ControlSetRelays(); - this->controlCode[CONTROLINDEX_SETRELAYS] = CONTROL_SETRELAYS; - - // Instantiate the commands needed for all models - command[(uint8_t)BulkCode::FORCETRIGGER] = new BulkForceTrigger(); - command[(uint8_t)BulkCode::STARTSAMPLING] = new BulkCaptureStart(); - command[(uint8_t)BulkCode::ENABLETRIGGER] = new BulkTriggerEnabled(); - command[(uint8_t)BulkCode::GETDATA] = new BulkGetData(); - command[(uint8_t)BulkCode::GETCAPTURESTATE] = new BulkGetCaptureState(); - command[(uint8_t)BulkCode::SETGAIN] = new BulkSetGain(); - - if (specification.useControlNoBulk) + if (specification.useControlNoBulk) { device->setEnableBulkTransfer(false); + } else { + // Instantiate the commands needed for all bulk-command-enabled models + addCommand(BulkCode::FORCETRIGGER, new BulkForceTrigger(), false); + addCommand(BulkCode::STARTSAMPLING, new BulkCaptureStart(), false); + addCommand(BulkCode::ENABLETRIGGER, new BulkTriggerEnabled(), false); + addCommand(BulkCode::GETDATA, new BulkGetData(), false); + addCommand(BulkCode::GETCAPTURESTATE, new BulkGetCaptureState(), false); + addCommand(BulkCode::SETGAIN, new BulkSetGain(), false); + } // Apply special requirements by the devices model device->getModel()->applyRequirements(this); @@ -89,11 +83,21 @@ HantekDsoControl::HantekDsoControl(USBDevice *device) : device(device), } HantekDsoControl::~HantekDsoControl() { - for (int cIndex = 0; cIndex < (uint8_t)BulkCode::COUNT; ++cIndex) { delete command[cIndex]; } - for (int cIndex = 0; cIndex < CONTROLINDEX_COUNT; ++cIndex) { delete control[cIndex]; } + while (firstBulkCommand) { + BulkCommand *t = firstBulkCommand->next; + delete firstBulkCommand; + firstBulkCommand = t; + } + while (firstControlCommand) { + ControlCommand *t = firstControlCommand->next; + delete firstControlCommand; + firstControlCommand = t; + } } -unsigned HantekDsoControl::getChannelCount() { return HANTEK_CHANNELS; } +unsigned HantekDsoControl::getChannelCount() { return specification.channels; } + +const ControlSettings *HantekDsoControl::getDeviceSettings() const { return &controlsettings; } const std::vector &HantekDsoControl::getAvailableRecordLengths() { // return controlsettings.samplerate.limits->recordLengths; @@ -114,7 +118,7 @@ void HantekDsoControl::updateInterval() { // Check the current oscilloscope state everytime 25% of the time the buffer // should be refilled if (isRollMode()) - cycleTime = (int)((double)device->getPacketSize() / (isFastRate() ? 1 : HANTEK_CHANNELS) / + cycleTime = (int)((double)device->getPacketSize() / (isFastRate() ? 1 : specification.channels) / controlsettings.samplerate.current * 250); else cycleTime = (int)((double)getRecordLength() / controlsettings.samplerate.current * 250); @@ -137,8 +141,9 @@ unsigned HantekDsoControl::getRecordLength() const { Dso::ErrorCode HantekDsoControl::retrieveChannelLevelData() { // Get channel level data - int errorCode = device->controlRead(CONTROL_VALUE, (unsigned char *)&(specification.offsetLimit), - sizeof(specification.offsetLimit), (int)VALUE_OFFSETLIMITS); + int errorCode = + device->controlRead((uint8_t)ControlCode::CONTROL_VALUE, (unsigned char *)&(specification.offsetLimit), + sizeof(specification.offsetLimit), (uint8_t)ControlValue::VALUE_OFFSETLIMITS); if (errorCode < 0) { qWarning() << tr("Couldn't get channel level data from oscilloscope"); emit statusMessage(tr("Couldn't get channel level data from oscilloscope"), 0); @@ -164,7 +169,7 @@ std::pair HantekDsoControl::getCaptureState() const { if (!specification.supportsCaptureState) return std::make_pair(CAPTURE_READY, 0); - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::GETCAPTURESTATE], 1); + errorCode = device->bulkCommand(getCommand(BulkCode::GETCAPTURESTATE), 1); if (errorCode < 0) { qWarning() << "Getting capture state failed: " << libUsbErrorString(errorCode); return std::make_pair(CAPTURE_ERROR, 0); @@ -181,14 +186,18 @@ std::pair HantekDsoControl::getCaptureState() const { } std::vector HantekDsoControl::getSamples(unsigned &previousSampleCount) const { + int errorCode; if (!specification.useControlNoBulk) { // Request data - int errorCode = device->bulkCommand(command[(uint8_t)BulkCode::GETDATA], 1); - if (errorCode < 0) { - qWarning() << "Getting sample data failed: " << libUsbErrorString(errorCode); - emit communicationError(); - return std::vector(); - } + errorCode = device->bulkCommand(getCommand(BulkCode::GETDATA), 1); + } else { + const ControlCommand *bulkCommand = getCommand(ControlCode::CONTROL_ACQUIIRE_HARD_DATA); + errorCode = device->controlWrite((uint8_t)bulkCommand->code, bulkCommand->data(), bulkCommand->getSize()); + } + if (errorCode < 0) { + qWarning() << "Getting sample data failed: " << libUsbErrorString(errorCode); + emit communicationError(); + return std::vector(); } unsigned totalSampleCount = this->getSampleCount(); @@ -226,8 +235,8 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector result.samplerate = controlsettings.samplerate.current; result.append = isRollMode(); // Prepare result buffers - result.data.resize(HANTEK_CHANNELS); - for (int channelCounter = 0; channelCounter < HANTEK_CHANNELS; ++channelCounter) + result.data.resize(specification.channels); + for (ChannelID channelCounter = 0; channelCounter < specification.channels; ++channelCounter) result.data[channelCounter].clear(); const unsigned extraBitsSize = specification.sampleSize - 8; // Number of extra bits @@ -236,12 +245,12 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector // Convert channel data if (isFastRate()) { // Fast rate mode, one channel is using all buffers - unsigned channel = 0; - for (; channel < HANTEK_CHANNELS; ++channel) { + ChannelID channel = 0; + for (; channel < specification.channels; ++channel) { if (controlsettings.voltage[channel].used) break; } - if (channel >= HANTEK_CHANNELS) return; + if (channel >= specification.channels) return; // Resize sample vector result.data[channel].resize(totalSampleCount); @@ -258,8 +267,8 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount; const unsigned short low = rawData[bufferPosition]; - const unsigned extraBitsPosition = bufferPosition % HANTEK_CHANNELS; - const unsigned shift = (8 - (HANTEK_CHANNELS - 1 - extraBitsPosition) * extraBitsSize); + const unsigned extraBitsPosition = bufferPosition % specification.channels; + const unsigned shift = (8 - (specification.channels - 1 - extraBitsPosition) * extraBitsSize); const unsigned short high = ((unsigned short int)rawData[totalSampleCount + bufferPosition - extraBitsPosition] << shift) & extraBitsMask; @@ -276,13 +285,14 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector } } else { // Normal mode, channels are using their separate buffers - for (unsigned channel = 0; channel < HANTEK_CHANNELS; ++channel) { - result.data[channel].resize(totalSampleCount / HANTEK_CHANNELS); + for (ChannelID channel = 0; channel < specification.channels; ++channel) { + result.data[channel].resize(totalSampleCount / specification.channels); const unsigned gainID = controlsettings.voltage[channel].gain; const unsigned short limit = specification.voltageLimit[channel][gainID]; const double offset = controlsettings.voltage[channel].offsetReal; const double gainStep = specification.gain[gainID].gainSteps; + int shiftDataBuf = 0; // Convert data from the oscilloscope and write it into the sample buffer unsigned bufferPosition = controlsettings.trigger.point * 2; @@ -291,10 +301,10 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector unsigned extraBitsIndex = 8 - channel * 2; // Bit position offset for extra bits extraction for (unsigned realPosition = 0; realPosition < result.data[channel].size(); - ++realPosition, bufferPosition += HANTEK_CHANNELS) { + ++realPosition, bufferPosition += specification.channels) { if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount; - const unsigned short low = rawData[bufferPosition + HANTEK_CHANNELS - 1 - channel]; + const unsigned short low = rawData[bufferPosition + specification.channels - 1 - channel]; const unsigned short high = ((unsigned short int)rawData[totalSampleCount + bufferPosition] << extraBitsIndex) & extraBitsMask; @@ -311,18 +321,14 @@ void HantekDsoControl::convertRawDataToSamples(const std::vector bufferPosition += DROP_DSO6022_HEAD * 2; } bufferPosition += channel; - for (unsigned pos = 0; pos < result.data[channel].size(); ++pos, bufferPosition += HANTEK_CHANNELS) { - if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount; - double dataBuf = (double)((int)(rawData[bufferPosition] - 0x83)); - result.data[channel][pos] = (dataBuf / limit) * gainStep; - } + shiftDataBuf = 0x83; } else { - bufferPosition += HANTEK_CHANNELS - 1 - channel; - for (unsigned pos = 0; pos < result.data[channel].size(); ++pos, bufferPosition += HANTEK_CHANNELS) { - if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount; - double dataBuf = (double)((int)(rawData[bufferPosition])); - result.data[channel][pos] = (dataBuf / limit - offset) * gainStep; - } + bufferPosition += specification.channels - 1 - channel; + } + for (unsigned pos = 0; pos < result.data[channel].size(); ++pos, bufferPosition += specification.channels) { + if (bufferPosition >= totalSampleCount) bufferPosition %= totalSampleCount; + double dataBuf = (double)((int)(rawData[bufferPosition] - shiftDataBuf)); + result.data[channel][pos] = (dataBuf / limit - offset) * gainStep; } } } @@ -420,39 +426,30 @@ unsigned HantekDsoControl::getSampleCount() const { if (isFastRate()) return getRecordLength(); else - return getRecordLength() * HANTEK_CHANNELS; + return getRecordLength() * specification.channels; } } -unsigned HantekDsoControl::updateRecordLength(unsigned index) { - if (index >= (unsigned)controlsettings.samplerate.limits->recordLengths.size()) return 0; +unsigned HantekDsoControl::updateRecordLength(RecordLengthID index) { + if (index >= controlsettings.samplerate.limits->recordLengths.size()) return 0; switch (specification.command.bulk.setRecordLength) { case BulkCode::SETTRIGGERANDSAMPLERATE: - // SetTriggerAndSamplerate bulk command for record length - static_cast(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])->setRecordLength(index); - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; - + modifyCommand(BulkCode::SETTRIGGERANDSAMPLERATE)->setRecordLength(index); break; case BulkCode::DSETBUFFER: if (specification.command.bulk.setPretrigger == BulkCode::FSETBUFFER) { - // Pointers to needed commands - BulkSetRecordLength2250 *commandSetRecordLength2250 = - static_cast(command[(uint8_t)BulkCode::DSETBUFFER]); - - commandSetRecordLength2250->setRecordLength(index); + modifyCommand(BulkCode::DSETBUFFER)->setRecordLength(index); } else { // SetBuffer5200 bulk command for record length - BulkSetBuffer5200 *commandSetBuffer5200 = static_cast(command[(uint8_t)BulkCode::DSETBUFFER]); + BulkSetBuffer5200 *commandSetBuffer5200 = modifyCommand(BulkCode::DSETBUFFER); commandSetBuffer5200->setUsedPre(DTriggerPositionUsed::DTRIGGERPOSITION_ON); commandSetBuffer5200->setUsedPost(DTriggerPositionUsed::DTRIGGERPOSITION_ON); commandSetBuffer5200->setRecordLength(index); } - commandPending[(uint8_t)BulkCode::DSETBUFFER] = true; - break; default: @@ -477,8 +474,7 @@ unsigned HantekDsoControl::updateRecordLength(unsigned index) { unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) { // Get samplerate limits - Hantek::ControlSamplerateLimits *limits = - fastRate ? &specification.samplerate.multi : &specification.samplerate.single; + ControlSamplerateLimits *limits = fastRate ? &specification.samplerate.multi : &specification.samplerate.single; // Set the calculated samplerate switch (specification.command.bulk.setSamplerate) { @@ -508,7 +504,7 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) // Pointers to needed commands BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = - static_cast(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE]); + modifyCommand(BulkCode::SETTRIGGERANDSAMPLERATE); // Store if samplerate ID or downsampling factor is used commandSetTriggerAndSamplerate->setDownsamplingMode(downsampling); @@ -519,8 +515,6 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) // Set fast rate when used commandSetTriggerAndSamplerate->setFastRate(false /*fastRate*/); - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; - break; } case BulkCode::CSETTRIGGERORSAMPLERATE: { @@ -531,9 +525,9 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) // Pointers to needed commands BulkSetSamplerate5200 *commandSetSamplerate5200 = - static_cast(command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE]); + modifyCommand(BulkCode::CSETTRIGGERORSAMPLERATE); BulkSetTrigger5200 *commandSetTrigger5200 = - static_cast(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE]); + modifyCommand(BulkCode::ESETTRIGGERORSAMPLERATE); // Store samplerate fast value commandSetSamplerate5200->setSamplerateFast(4 - valueFast); @@ -542,15 +536,12 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) // Set fast rate when used commandSetTrigger5200->setFastRate(fastRate); - commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true; - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; - break; } case BulkCode::ESETTRIGGERORSAMPLERATE: { // Pointers to needed commands BulkSetSamplerate2250 *commandSetSamplerate2250 = - static_cast(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE]); + modifyCommand(BulkCode::ESETTRIGGERORSAMPLERATE); bool downsampling = downsampler >= 1; // Store downsampler state value @@ -560,8 +551,6 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) // Set fast rate when used commandSetSamplerate2250->setFastRate(fastRate); - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; - break; } default: @@ -597,7 +586,7 @@ unsigned HantekDsoControl::updateSamplerate(unsigned downsampler, bool fastRate) } void HantekDsoControl::restoreTargets() { - if (controlsettings.samplerate.target.samplerateSet) + if (controlsettings.samplerate.target.samplerateSet == ControlSettingsSamplerateTarget::Samplerrate) this->setSamplerate(); else this->setRecordTime(); @@ -620,10 +609,10 @@ void HantekDsoControl::updateSamplerateLimits() { Dso::ErrorCode HantekDsoControl::setRecordLength(unsigned index) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (!this->updateRecordLength(index)) return Dso::ErrorCode::PARAMETER; + if (!updateRecordLength(index)) return Dso::ErrorCode::PARAMETER; - this->restoreTargets(); - this->setPretriggerPosition(controlsettings.trigger.position); + restoreTargets(); + setPretriggerPosition(controlsettings.trigger.position); emit recordLengthChanged(getRecordLength()); return Dso::ErrorCode::NONE; @@ -640,7 +629,7 @@ Dso::ErrorCode HantekDsoControl::setSamplerate(double samplerate) { samplerate = controlsettings.samplerate.target.samplerate; } else { controlsettings.samplerate.target.samplerate = samplerate; - controlsettings.samplerate.target.samplerateSet = true; + controlsettings.samplerate.target.samplerateSet = ControlSettingsSamplerateTarget::Samplerrate; } if (!specification.isSoftwareTriggerDevice) { @@ -664,15 +653,14 @@ Dso::ErrorCode HantekDsoControl::setSamplerate(double samplerate) { unsigned sampleId; for (sampleId = 0; sampleId < specification.fixedSampleRates.size() - 1; ++sampleId) if (specification.fixedSampleRates[sampleId].samplerate == samplerate) break; - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV; - static_cast(this->control[CONTROLINDEX_SETTIMEDIV]) + modifyCommand(ControlCode::CONTROL_SETTIMEDIV) ->setDiv(specification.fixedSampleRates[sampleId].id); - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true; controlsettings.samplerate.current = samplerate; // Check for Roll mode if (!isRollMode()) - emit recordTimeChanged((double)(getRecordLength() - controlsettings.swtriggerSampleMargin) / controlsettings.samplerate.current); + emit recordTimeChanged((double)(getRecordLength() - controlsettings.swtriggerSampleMargin) / + controlsettings.samplerate.current); emit samplerateChanged(controlsettings.samplerate.current); return Dso::ErrorCode::NONE; @@ -690,7 +678,7 @@ Dso::ErrorCode HantekDsoControl::setRecordTime(double duration) { duration = controlsettings.samplerate.target.duration; } else { controlsettings.samplerate.target.duration = duration; - controlsettings.samplerate.target.samplerateSet = false; + controlsettings.samplerate.target.samplerateSet = ControlSettingsSamplerateTarget::Duration; } if (!specification.isFixedSamplerateDevice) { @@ -715,21 +703,18 @@ Dso::ErrorCode HantekDsoControl::setRecordTime(double duration) { return Dso::ErrorCode::NONE; } } else { - // For now - we go for the 10240 size sampling - the other seems not to be - // supported - // Find highest samplerate using less than 10240 samples to obtain our - // duration. + // For now - we go for the 10240 size sampling - the other seems not to be supported + // Find highest samplerate using less than 10240 samples to obtain our duration. unsigned sampleCount = 10240; unsigned sampleId; for (sampleId = 0; sampleId < specification.fixedSampleRates.size(); ++sampleId) { if (specification.fixedSampleRates[sampleId].samplerate * duration < - (sampleCount - controlsettings.swtriggerSampleMargin))break; + (sampleCount - controlsettings.swtriggerSampleMargin)) + break; } // Usable sample value - this->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV; - static_cast(this->control[CONTROLINDEX_SETTIMEDIV]) + modifyCommand(ControlCode::CONTROL_SETTIMEDIV) ->setDiv(specification.fixedSampleRates[sampleId].id); - this->controlPending[CONTROLINDEX_SETTIMEDIV] = true; controlsettings.samplerate.current = specification.fixedSampleRates[sampleId].samplerate; emit samplerateChanged(controlsettings.samplerate.current); @@ -741,15 +726,15 @@ Dso::ErrorCode HantekDsoControl::setRecordTime(double duration) { /// \param channel The channel that should be set. /// \param used true if the channel should be sampled. /// \return See ::Dso::ErrorCode. -Dso::ErrorCode HantekDsoControl::setChannelUsed(unsigned channel, bool used) { +Dso::ErrorCode HantekDsoControl::setChannelUsed(ChannelID channel, bool used) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER; + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER; // Update settings controlsettings.voltage[channel].used = used; - unsigned channelCount = 0; - for (unsigned c = 0; c < HANTEK_CHANNELS; ++c) { + ChannelID channelCount = 0; + for (unsigned c = 0; c < specification.channels; ++c) { if (controlsettings.voltage[c].used) ++channelCount; } @@ -771,22 +756,18 @@ Dso::ErrorCode HantekDsoControl::setChannelUsed(unsigned channel, bool used) { switch (specification.command.bulk.setChannels) { case BulkCode::SETTRIGGERANDSAMPLERATE: { // SetTriggerAndSamplerate bulk command for trigger source - static_cast(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE]) + modifyCommand(BulkCode::SETTRIGGERANDSAMPLERATE) ->setUsedChannels((uint8_t)usedChannels); - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; break; } case BulkCode::BSETCHANNELS: { // SetChannels2250 bulk command for active channels - static_cast(command[(uint8_t)BulkCode::BSETCHANNELS])->setUsedChannels((uint8_t)usedChannels); - commandPending[(uint8_t)BulkCode::BSETCHANNELS] = true; - + modifyCommand(BulkCode::BSETCHANNELS)->setUsedChannels((uint8_t)usedChannels); break; } case BulkCode::ESETTRIGGERORSAMPLERATE: { // SetTrigger5200s bulk command for trigger source - static_cast(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE])->setUsedChannels((uint8_t)usedChannels); - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; + modifyCommand(BulkCode::ESETTRIGGERORSAMPLERATE)->setUsedChannels((uint8_t)usedChannels); break; } default: @@ -806,16 +787,15 @@ Dso::ErrorCode HantekDsoControl::setChannelUsed(unsigned channel, bool used) { /// \param channel The channel that should be set. /// \param coupling The new coupling for the channel. /// \return See ::Dso::ErrorCode. -Dso::ErrorCode HantekDsoControl::setCoupling(unsigned channel, Dso::Coupling coupling) { +Dso::ErrorCode HantekDsoControl::setCoupling(ChannelID channel, Dso::Coupling coupling) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER; + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER; // SetRelays control command for coupling relays if (specification.supportsCouplingRelays) { - static_cast(this->control[CONTROLINDEX_SETRELAYS]) - ->setCoupling(channel, coupling != Dso::COUPLING_AC); - this->controlPending[CONTROLINDEX_SETRELAYS] = true; + modifyCommand(ControlCode::CONTROL_SETRELAYS) + ->setCoupling(channel, coupling != Dso::Coupling::AC); } return Dso::ErrorCode::NONE; @@ -826,10 +806,10 @@ Dso::ErrorCode HantekDsoControl::setCoupling(unsigned channel, Dso::Coupling cou /// \param channel The channel that should be set. /// \param gain The gain that should be met (V/div). /// \return The gain that has been set, ::Dso::ErrorCode on error. -Dso::ErrorCode HantekDsoControl::setGain(unsigned channel, double gain) { +Dso::ErrorCode HantekDsoControl::setGain(ChannelID channel, double gain) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER; + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER; // Find lowest gain voltage thats at least as high as the requested unsigned gainID; @@ -838,25 +818,21 @@ Dso::ErrorCode HantekDsoControl::setGain(unsigned channel, double gain) { if (specification.useControlNoBulk) { if (channel == 0) { - static_cast(this->control[CONTROLINDEX_SETVOLTDIV_CH1]) + modifyCommand(ControlCode::CONTROL_SETVOLTDIV_CH1) ->setDiv(specification.gain[gainID].gainIndex); - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true; } else if (channel == 1) { - static_cast(this->control[CONTROLINDEX_SETVOLTDIV_CH2]) + modifyCommand(ControlCode::CONTROL_SETVOLTDIV_CH2) ->setDiv(specification.gain[gainID].gainIndex); - this->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true; } else qDebug("%s: Unsuported channel: %i\n", __func__, channel); } else { // SetGain bulk command for gain - static_cast(command[(uint8_t)BulkCode::SETGAIN])->setGain(channel, specification.gain[gainID].gainIndex); - commandPending[(uint8_t)BulkCode::SETGAIN] = true; + modifyCommand(BulkCode::SETGAIN)->setGain(channel, specification.gain[gainID].gainIndex); // SetRelays control command for gain relays - ControlSetRelays *controlSetRelays = static_cast(this->control[CONTROLINDEX_SETRELAYS]); + ControlSetRelays *controlSetRelays = modifyCommand(ControlCode::CONTROL_SETRELAYS); controlSetRelays->setBelow1V(channel, gainID < 3); controlSetRelays->setBelow100mV(channel, gainID < 6); - this->controlPending[CONTROLINDEX_SETRELAYS] = true; } controlsettings.voltage[channel].gain = gainID; @@ -870,28 +846,27 @@ Dso::ErrorCode HantekDsoControl::setGain(unsigned channel, double gain) { /// Get the actual offset for the channel from controlsettings.voltage[channel].offsetReal /// \param channel The channel that should be set. /// \param offset The new offset value (0.0 - 1.0). -Dso::ErrorCode HantekDsoControl::setOffset(unsigned channel, double offset) { +Dso::ErrorCode HantekDsoControl::setOffset(ChannelID channel, const double offset) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER; - - Offset& channelOffLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain]; - // Calculate the offset value - // The range is given by the calibration data (convert from big endian) - unsigned short int minimum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.start)) << 8) + - *((unsigned char *)&(channelOffLimit.start) + 1); - unsigned short int maximum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.end)) << 8) + - *((unsigned char *)&(channelOffLimit.end) + 1); - unsigned short int offsetValue = offset * (maximum - minimum) + minimum + 0.5; - double offsetReal = (double)(offsetValue - minimum) / (maximum - minimum); + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER; if (specification.supportsOffset) { - static_cast(this->control[CONTROLINDEX_SETOFFSET])->setChannel(channel, offsetValue); - this->controlPending[CONTROLINDEX_SETOFFSET] = true; + Offset &channelOffLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain]; + // Calculate the offset value + // The range is given by the calibration data (convert from big endian) + unsigned short int minimum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.start)) << 8) + + *((unsigned char *)&(channelOffLimit.start) + 1); + unsigned short int maximum = ((unsigned short int)*((unsigned char *)&(channelOffLimit.end)) << 8) + + *((unsigned char *)&(channelOffLimit.end) + 1); + unsigned short int offsetValue = offset * (maximum - minimum) + minimum + 0.5; + double offsetReal = (double)(offsetValue - minimum) / (maximum - minimum); + + modifyCommand(ControlCode::CONTROL_SETOFFSET)->setChannel(channel, offsetValue); + controlsettings.voltage[channel].offsetReal = offsetReal; } controlsettings.voltage[channel].offset = offset; - controlsettings.voltage[channel].offsetReal = offsetReal; this->setTriggerLevel(channel, controlsettings.trigger.level[channel]); @@ -903,8 +878,6 @@ Dso::ErrorCode HantekDsoControl::setOffset(unsigned channel, double offset) { Dso::ErrorCode HantekDsoControl::setTriggerMode(Dso::TriggerMode mode) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (mode < Dso::TRIGGERMODE_AUTO || mode >= Dso::TRIGGERMODE_COUNT) return Dso::ErrorCode::PARAMETER; - controlsettings.trigger.mode = mode; return Dso::ErrorCode::NONE; } @@ -917,34 +890,26 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; if (specification.isSoftwareTriggerDevice) return Dso::ErrorCode::UNSUPPORTED; - if (!special && id >= HANTEK_CHANNELS) - return Dso::ErrorCode::PARAMETER; + if (!special && id >= specification.channels) return Dso::ErrorCode::PARAMETER; - if (special && id >= specification.specialTriggerChannels.size()) - return Dso::ErrorCode::PARAMETER; + if (special && id >= specification.specialTriggerChannels.size()) return Dso::ErrorCode::PARAMETER; - int hardwareID = special ? specification.specialTriggerChannels[id].hardwareID:(int)id; + int hardwareID = special ? specification.specialTriggerChannels[id].hardwareID : (int)id; switch (specification.command.bulk.setTrigger) { case BulkCode::SETTRIGGERANDSAMPLERATE: // SetTriggerAndSamplerate bulk command for trigger source - static_cast(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE]) - ->setTriggerSource(1 - hardwareID); - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; + modifyCommand(BulkCode::SETTRIGGERANDSAMPLERATE)->setTriggerSource(1 - hardwareID); break; case BulkCode::CSETTRIGGERORSAMPLERATE: // SetTrigger2250 bulk command for trigger source - static_cast(command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE]) - ->setTriggerSource(2 + hardwareID); - commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true; + modifyCommand(BulkCode::CSETTRIGGERORSAMPLERATE)->setTriggerSource(2 + hardwareID); break; case BulkCode::ESETTRIGGERORSAMPLERATE: // SetTrigger5200 bulk command for trigger source - static_cast(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE]) - ->setTriggerSource(1 - hardwareID); - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; + modifyCommand(BulkCode::ESETTRIGGERORSAMPLERATE)->setTriggerSource(1 - hardwareID); break; default: @@ -952,8 +917,7 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) { } // SetRelays control command for external trigger relay - static_cast(this->control[CONTROLINDEX_SETRELAYS])->setTrigger(special); - this->controlPending[CONTROLINDEX_SETRELAYS] = true; + modifyCommand(ControlCode::CONTROL_SETRELAYS)->setTrigger(special); controlsettings.trigger.special = special; controlsettings.trigger.source = id; @@ -961,8 +925,7 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) { // Apply trigger level of the new source if (special) { // SetOffset control command for changed trigger level - static_cast(this->control[CONTROLINDEX_SETOFFSET])->setTrigger(0x7f); - this->controlPending[CONTROLINDEX_SETOFFSET] = true; + modifyCommand(ControlCode::CONTROL_SETOFFSET)->setTrigger(0x7f); } else this->setTriggerLevel(id, controlsettings.trigger.level[id]); @@ -973,20 +936,23 @@ Dso::ErrorCode HantekDsoControl::setTriggerSource(bool special, unsigned id) { /// \param channel The channel that should be set. /// \param level The new trigger level (V). /// \return The trigger level that has been set, ::Dso::ErrorCode on error. -Dso::ErrorCode HantekDsoControl::setTriggerLevel(unsigned channel, double level) { +Dso::ErrorCode HantekDsoControl::setTriggerLevel(ChannelID channel, double level) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (channel >= HANTEK_CHANNELS) return Dso::ErrorCode::PARAMETER; + if (channel >= specification.channels) return Dso::ErrorCode::PARAMETER; + + controlsettings.trigger.level[channel] = level; + if (!specification.supportsOffset) return Dso::ErrorCode::UNSUPPORTED; // Calculate the trigger level value unsigned short minimum, maximum; if (specification.sampleSize > 8) { - Offset& offsetLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain]; + Offset &offsetLimit = specification.offsetLimit[channel].step[controlsettings.voltage[channel].gain]; // The range is the same as used for the offsets for 10 bit models minimum = ((unsigned short)*((unsigned char *)&(offsetLimit.start)) << 8) + *((unsigned char *)&(offsetLimit.start) + 1); - maximum = ((unsigned short)*((unsigned char *)&(offsetLimit.end)) << 8) + - *((unsigned char *)&(offsetLimit.end) + 1); + maximum = + ((unsigned short)*((unsigned char *)&(offsetLimit.end)) << 8) + *((unsigned char *)&(offsetLimit.end) + 1); } else { // It's from 0x00 to 0xfd for the 8 bit models minimum = 0x00; @@ -997,19 +963,17 @@ Dso::ErrorCode HantekDsoControl::setTriggerLevel(unsigned channel, double level) const unsigned gainID = controlsettings.voltage[channel].gain; const double offsetReal = controlsettings.voltage[channel].offsetReal; const double gainStep = specification.gain[gainID].gainSteps; - unsigned short levelValue = qBound( + const unsigned short levelValue = qBound( minimum, (unsigned short)(((offsetReal + level / gainStep) * (maximum - minimum) + 0.5) + minimum), maximum); // Check if the set channel is the trigger source - if (!controlsettings.trigger.special && channel == controlsettings.trigger.source && specification.supportsOffset) { + if (!controlsettings.trigger.special && channel == controlsettings.trigger.source) { // SetOffset control command for trigger level - static_cast(this->control[CONTROLINDEX_SETOFFSET])->setTrigger(levelValue); - this->controlPending[CONTROLINDEX_SETOFFSET] = true; + modifyCommand(ControlCode::CONTROL_SETOFFSET)->setTrigger(levelValue); } /// \todo Get alternating trigger in here - controlsettings.trigger.level[channel] = level; return Dso::ErrorCode::NONE; } @@ -1019,25 +983,20 @@ Dso::ErrorCode HantekDsoControl::setTriggerLevel(unsigned channel, double level) Dso::ErrorCode HantekDsoControl::setTriggerSlope(Dso::Slope slope) { if (!device->isConnected()) return Dso::ErrorCode::CONNECTION; - if (slope >= Dso::SLOPE_COUNT) return Dso::ErrorCode::PARAMETER; - switch (specification.command.bulk.setTrigger) { case BulkCode::SETTRIGGERANDSAMPLERATE: { // SetTriggerAndSamplerate bulk command for trigger slope - static_cast(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])->setTriggerSlope(slope); - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; + modifyCommand(BulkCode::SETTRIGGERANDSAMPLERATE)->setTriggerSlope((uint8_t)slope); break; } case BulkCode::CSETTRIGGERORSAMPLERATE: { // SetTrigger2250 bulk command for trigger slope - static_cast(command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE])->setTriggerSlope(slope); - commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true; + modifyCommand(BulkCode::CSETTRIGGERORSAMPLERATE)->setTriggerSlope((uint8_t)slope); break; } case BulkCode::ESETTRIGGERORSAMPLERATE: { // SetTrigger5200 bulk command for trigger slope - static_cast(command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE])->setTriggerSlope(slope); - commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; + modifyCommand(BulkCode::ESETTRIGGERORSAMPLERATE)->setTriggerSlope((uint8_t)slope); break; } default: @@ -1048,7 +1007,7 @@ Dso::ErrorCode HantekDsoControl::setTriggerSlope(Dso::Slope slope) { return Dso::ErrorCode::NONE; } -void HantekDsoControl::forceTrigger() { commandPending[(uint8_t)BulkCode::FORCETRIGGER] = true; } +void HantekDsoControl::forceTrigger() { modifyCommand(BulkCode::FORCETRIGGER); } /// \brief Set the trigger position. /// \param position The new trigger position (in s). @@ -1060,17 +1019,16 @@ Dso::ErrorCode HantekDsoControl::setPretriggerPosition(double position) { double positionSamples = position * controlsettings.samplerate.current; unsigned recordLength = getRecordLength(); // Fast rate mode uses both channels - if (controlsettings.samplerate.limits == &specification.samplerate.multi) positionSamples /= HANTEK_CHANNELS; + if (isFastRate()) positionSamples /= specification.channels; switch (specification.command.bulk.setPretrigger) { case BulkCode::SETTRIGGERANDSAMPLERATE: { // Calculate the position value (Start point depending on record length) - unsigned position = isRollMode() ? 0x1 : 0x7ffff - recordLength + (unsigned)positionSamples; + unsigned triggerPosition = isRollMode() ? 0x1 : 0x7ffff - recordLength + (unsigned)positionSamples; // SetTriggerAndSamplerate bulk command for trigger position - static_cast(command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE])->setTriggerPosition(position); - commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; - + modifyCommand(BulkCode::SETTRIGGERANDSAMPLERATE) + ->setTriggerPosition(triggerPosition); break; } case BulkCode::FSETBUFFER: { @@ -1079,11 +1037,9 @@ Dso::ErrorCode HantekDsoControl::setPretriggerPosition(double position) { unsigned positionPost = 0x7ffff - (unsigned)positionSamples; // SetBuffer2250 bulk command for trigger position - BulkSetBuffer2250 *commandSetBuffer2250 = static_cast(command[(uint8_t)BulkCode::FSETBUFFER]); + BulkSetBuffer2250 *commandSetBuffer2250 = modifyCommand(BulkCode::FSETBUFFER); commandSetBuffer2250->setTriggerPositionPre(positionPre); commandSetBuffer2250->setTriggerPositionPost(positionPost); - commandPending[(uint8_t)BulkCode::FSETBUFFER] = true; - break; } case BulkCode::ESETTRIGGERORSAMPLERATE: { @@ -1092,11 +1048,9 @@ Dso::ErrorCode HantekDsoControl::setPretriggerPosition(double position) { unsigned positionPost = 0xffff - (unsigned)positionSamples; // SetBuffer5200 bulk command for trigger position - BulkSetBuffer5200 *commandSetBuffer5200 = static_cast(command[(uint8_t)BulkCode::DSETBUFFER]); + BulkSetBuffer5200 *commandSetBuffer5200 = modifyCommand(BulkCode::DSETBUFFER); commandSetBuffer5200->setTriggerPositionPre((unsigned short)positionPre); commandSetBuffer5200->setTriggerPositionPost((unsigned short)positionPost); - commandPending[(uint8_t)BulkCode::DSETBUFFER] = true; - break; } default: @@ -1113,83 +1067,90 @@ Dso::ErrorCode HantekDsoControl::stringCommand(const QString &commandString) { QStringList commandParts = commandString.split(' ', QString::SkipEmptyParts); if (commandParts.count() < 1) return Dso::ErrorCode::PARAMETER; - if (commandParts[0] != "send") return Dso::ErrorCode::UNSUPPORTED; - if (commandParts.count() < 2) return Dso::ErrorCode::PARAMETER; - if (commandParts[1] == "bulk") { - QString data = commandString.section(' ', 2, -1, QString::SectionSkipEmpty); - unsigned char commandCode = 0; + uint8_t codeIndex = 0; + hexParse(commandParts[2], &codeIndex, 1); + QString data = commandString.section(' ', 2, -1, QString::SectionSkipEmpty); - // Read command code (First byte) - hexParse(commandParts[2], &commandCode, 1); - if (commandCode > (uint8_t)BulkCode::COUNT) return Dso::ErrorCode::UNSUPPORTED; + if (commandParts[1] == "bulk") { + if (!command[codeIndex]) return Dso::ErrorCode::UNSUPPORTED; - // Update bulk command and mark as pending - hexParse(data, command[commandCode]->data(), command[commandCode]->getSize()); - commandPending[commandCode] = true; + BulkCommand *c = modifyCommand((BulkCode)codeIndex); + hexParse(data, c->data(), c->getSize()); return Dso::ErrorCode::NONE; } else if (commandParts[1] == "control") { - unsigned char controlCode = 0; - - // Read command code (First byte) - hexParse(commandParts[2], &controlCode, 1); - int cIndex; - for (cIndex = 0; cIndex < CONTROLINDEX_COUNT; ++cIndex) { - if (this->controlCode[cIndex] == controlCode) break; - } - if (cIndex >= CONTROLINDEX_COUNT) return Dso::ErrorCode::UNSUPPORTED; + if (!control[codeIndex]) return Dso::ErrorCode::UNSUPPORTED; - QString data = commandString.section(' ', 3, -1, QString::SectionSkipEmpty); - - // Update control command and mark as pending - hexParse(data, this->control[cIndex]->data(), this->control[cIndex]->getSize()); - this->controlPending[cIndex] = true; + ControlCommand *c = modifyCommand((ControlCode)codeIndex); + hexParse(data, c->data(), c->getSize()); return Dso::ErrorCode::NONE; } else return Dso::ErrorCode::UNSUPPORTED; } +void HantekDsoControl::addCommand(BulkCode code, BulkCommand *newCommand, bool pending) { + newCommand->pending = pending; + command[(uint8_t)code] = newCommand; + newCommand->next = firstBulkCommand; + firstBulkCommand = newCommand; +} + +const BulkCommand *HantekDsoControl::getCommand(BulkCode code) const { return command[(uint8_t)code]; } + +void HantekDsoControl::addCommand(ControlCode code, ControlCommand *newCommand, bool pending) { + newCommand->pending = pending; + control[(uint8_t)code] = newCommand; + newCommand->next = firstControlCommand; + firstControlCommand = newCommand; +} + +const ControlCommand *HantekDsoControl::getCommand(ControlCode code) const { return control[(uint8_t)code]; } + void HantekDsoControl::run() { int errorCode = 0; // Send all pending bulk commands - for (int cIndex = 0; cIndex < (uint8_t)BulkCode::COUNT; ++cIndex) { - if (!commandPending[cIndex]) continue; + BulkCommand *bulkCommand = firstBulkCommand; + while (bulkCommand) { + if (bulkCommand->pending) { + timestampDebug( + QString("Sending bulk command:%1").arg(hexDump(bulkCommand->data(), bulkCommand->getSize()))); - timestampDebug( - QString("Sending bulk command:%1").arg(hexDump(command[cIndex]->data(), command[cIndex]->getSize()))); - - errorCode = device->bulkCommand(command[cIndex]); - if (errorCode < 0) { - qWarning("Sending bulk command %02x failed: %s", cIndex, libUsbErrorString(errorCode).toLocal8Bit().data()); - emit communicationError(); - return; - } else - commandPending[cIndex] = false; + errorCode = device->bulkCommand(bulkCommand); + if (errorCode < 0) { + qWarning() << "Sending bulk command failed: " << libUsbErrorString(errorCode); + emit communicationError(); + return; + } else + bulkCommand->pending = false; + } + bulkCommand = bulkCommand->next; } // Send all pending control commands - for (int cIndex = 0; cIndex < CONTROLINDEX_COUNT; ++cIndex) { - if (!this->controlPending[cIndex]) continue; - - timestampDebug(QString("Sending control command %1:%2") - .arg(QString::number(this->controlCode[control], 16), - hexDump(this->control[control]->data(), this->control[control]->getSize()))); - - errorCode = device->controlWrite(this->controlCode[cIndex], this->control[cIndex]->data(), - this->control[cIndex]->getSize()); - if (errorCode < 0) { - qWarning("Sending control command %2x failed: %s", this->controlCode[cIndex], - libUsbErrorString(errorCode).toLocal8Bit().data()); + ControlCommand *controlCommand = firstControlCommand; + while (controlCommand) { + if (controlCommand->pending) { + timestampDebug(QString("Sending control command %1:%2") + .arg(QString::number(control[cIndex], 16), + hexDump(this->control[control]->data(), this->control[control]->getSize()))); + + errorCode = + device->controlWrite((uint8_t)controlCommand->code, controlCommand->data(), controlCommand->getSize()); + if (errorCode < 0) { + qWarning("Sending control command %2x failed: %s", (uint8_t)controlCommand->code, + libUsbErrorString(errorCode).toLocal8Bit().data()); - if (errorCode == LIBUSB_ERROR_NO_DEVICE) { - emit communicationError(); - return; - } - } else - this->controlPending[cIndex] = false; + if (errorCode == LIBUSB_ERROR_NO_DEVICE) { + emit communicationError(); + return; + } + } else + controlCommand->pending = false; + } + controlCommand = controlCommand->next; } // State machine for the device communication @@ -1207,9 +1168,9 @@ void HantekDsoControl::run() { } // Sampling hasn't started, update the expected sample count - this->previousSampleCount = this->getSampleCount(); + expectedSampleCount = this->getSampleCount(); - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::STARTSAMPLING]); + errorCode = device->bulkCommand(getCommand(BulkCode::STARTSAMPLING)); if (errorCode < 0) { if (errorCode == LIBUSB_ERROR_NO_DEVICE) { emit communicationError(); @@ -1225,7 +1186,7 @@ void HantekDsoControl::run() { break; case RollState::ENABLETRIGGER: - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::ENABLETRIGGER]); + errorCode = device->bulkCommand(getCommand(BulkCode::ENABLETRIGGER)); if (errorCode < 0) { if (errorCode == LIBUSB_ERROR_NO_DEVICE) { emit communicationError(); @@ -1239,7 +1200,7 @@ void HantekDsoControl::run() { break; case RollState::FORCETRIGGER: - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::FORCETRIGGER]); + errorCode = device->bulkCommand(getCommand(BulkCode::FORCETRIGGER)); if (errorCode < 0) { if (errorCode == LIBUSB_ERROR_NO_DEVICE) { emit communicationError(); @@ -1253,7 +1214,7 @@ void HantekDsoControl::run() { break; case RollState::GETDATA: { - std::vector rawData = this->getSamples(previousSampleCount); + std::vector rawData = this->getSamples(expectedSampleCount); if (this->_samplingStarted) { convertRawDataToSamples(rawData); emit samplesAvailable(); @@ -1261,7 +1222,8 @@ void HantekDsoControl::run() { } // Check if we're in single trigger mode - if (controlsettings.trigger.mode == Dso::TRIGGERMODE_SINGLE && this->_samplingStarted) this->stopSampling(); + if (controlsettings.trigger.mode == Dso::TriggerMode::SINGLE && this->_samplingStarted) + this->stopSampling(); // Sampling completed, restart it when necessary this->_samplingStarted = false; @@ -1293,7 +1255,7 @@ void HantekDsoControl::run() { case CAPTURE_READY: case CAPTURE_READY2250: case CAPTURE_READY5200: { - std::vector rawData = this->getSamples(previousSampleCount); + std::vector rawData = this->getSamples(expectedSampleCount); if (this->_samplingStarted) { convertRawDataToSamples(rawData); emit samplesAvailable(); @@ -1301,20 +1263,22 @@ void HantekDsoControl::run() { } // Check if we're in single trigger mode - if (controlsettings.trigger.mode == Dso::TRIGGERMODE_SINGLE && this->_samplingStarted) this->stopSampling(); + if (controlsettings.trigger.mode == Dso::TriggerMode::SINGLE && this->_samplingStarted) + this->stopSampling(); // Sampling completed, restart it when necessary this->_samplingStarted = false; // Start next capture if necessary by leaving out the break statement - if (!this->sampling) break; + if (!this->sampling) break; #if __has_cpp_attribute(fallthrough) // Make compiler happy - [[fallthrough]]; + else + [[fallthrough]]; #endif case CAPTURE_WAITING: // Sampling hasn't started, update the expected sample count - this->previousSampleCount = this->getSampleCount(); + expectedSampleCount = this->getSampleCount(); if (this->_samplingStarted && this->lastTriggerMode == controlsettings.trigger.mode) { ++this->cycleCounter; @@ -1322,7 +1286,7 @@ void HantekDsoControl::run() { if (this->cycleCounter == this->startCycle && !isRollMode()) { // Buffer refilled completely since start of sampling, enable the // trigger now - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::ENABLETRIGGER]); + errorCode = device->bulkCommand(getCommand(BulkCode::ENABLETRIGGER)); if (errorCode < 0) { if (errorCode == LIBUSB_ERROR_NO_DEVICE) { emit communicationError(); @@ -1333,9 +1297,9 @@ void HantekDsoControl::run() { timestampDebug("Enabling trigger"); } else if (this->cycleCounter >= 8 + this->startCycle && - controlsettings.trigger.mode == Dso::TRIGGERMODE_AUTO) { + controlsettings.trigger.mode == Dso::TriggerMode::AUTO) { // Force triggering - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::FORCETRIGGER]); + errorCode = device->bulkCommand(getCommand(BulkCode::FORCETRIGGER)); if (errorCode < 0) { if (errorCode == LIBUSB_ERROR_NO_DEVICE) { emit communicationError(); @@ -1351,7 +1315,7 @@ void HantekDsoControl::run() { } // Start capturing - errorCode = device->bulkCommand(command[(uint8_t)BulkCode::STARTSAMPLING]); + errorCode = device->bulkCommand(getCommand(BulkCode::STARTSAMPLING)); if (errorCode < 0) { if (errorCode == LIBUSB_ERROR_NO_DEVICE) { emit communicationError(); diff --git a/openhantek/src/hantekdso/hantekdsocontrol.h b/openhantek/src/hantekdso/hantekdsocontrol.h index eb20caf..54b805e 100644 --- a/openhantek/src/hantekdso/hantekdsocontrol.h +++ b/openhantek/src/hantekdso/hantekdsocontrol.h @@ -2,14 +2,20 @@ #pragma once +#define NOMINMAX // disable windows.h min/max global methods +#include + #include "errorcodes.h" #include "dsosamples.h" #include "states.h" #include "controlspecification.h" #include "controlsettings.h" -#include "controlindexes.h" #include "utils/printutils.h" +#include "hantekprotocol/definitions.h" +#include "hantekprotocol/bulkStructs.h" +#include "hantekprotocol/controlStructs.h" + #include #include @@ -52,6 +58,10 @@ class HantekDsoControl : public QObject { /// \return The number of physical channels. unsigned getChannelCount(); + /// Return the read-only device control settings. Use the set- Methods to change + /// device settings. + const Dso::ControlSettings *getDeviceSettings() const; + /// \brief Get available record lengths for this oscilloscope. /// \return The number of physical channels, empty list for continuous. const std::vector &getAvailableRecordLengths(); @@ -86,6 +96,19 @@ class HantekDsoControl : public QObject { /// \return See ::Dso::ErrorCode. Dso::ErrorCode stringCommand(const QString &commandString); + void addCommand(Hantek::BulkCode code, Hantek::BulkCommand* newCommand, bool pending = true); + template T* modifyCommand(Hantek::BulkCode code) { + command[(uint8_t)code]->pending = true; + return static_cast(command[(uint8_t)code]); + } + const Hantek::BulkCommand* getCommand(Hantek::BulkCode code) const; + + void addCommand(Hantek::ControlCode code, Hantek::ControlCommand* newCommand, bool pending = true); + template T* modifyCommand(Hantek::ControlCode code) { + control[(uint8_t)code]->pending = true; + return static_cast(control[(uint8_t)code]); + } + const Hantek::ControlCommand* getCommand(Hantek::ControlCode code) const; private: bool isRollMode() const; bool isFastRate() const; @@ -122,7 +145,7 @@ class HantekDsoControl : public QObject { std::pair getCaptureState() const; /// \brief Gets sample data from the oscilloscope - std::vector getSamples(unsigned &previousSampleCount) const; + std::vector getSamples(unsigned &expectedSampleCount) const; /// \brief Converts raw oscilloscope data to sample data void convertRawDataToSamples(const std::vector &rawData); @@ -130,7 +153,7 @@ class HantekDsoControl : public QObject { /// \brief Sets the size of the sample buffer without updating dependencies. /// \param index The record length index that should be set. /// \return The record length that has been set, 0 on error. - unsigned updateRecordLength(unsigned size); + unsigned updateRecordLength(RecordLengthID size); /// \brief Sets the samplerate based on the parameters calculated by /// Control::getBestSamplerate. @@ -145,29 +168,24 @@ class HantekDsoControl : public QObject { /// \brief Update the minimum and maximum supported samplerate. void updateSamplerateLimits(); - public: // TODO redo command queues - /// Pointers to bulk commands, ready to be transmitted - Hantek::BulkCommand *command[(uint8_t)Hantek::BulkCode::COUNT] = {0}; - /// true, when the command should be executed - bool commandPending[(uint8_t)Hantek::BulkCode::COUNT] = {false}; - ///< Pointers to control commands - Hantek::ControlCommand *control[Hantek::CONTROLINDEX_COUNT] = {0}; - ///< Request codes for control commands - unsigned char controlCode[Hantek::CONTROLINDEX_COUNT]; - ///< true, when the control command should be executed - bool controlPending[Hantek::CONTROLINDEX_COUNT] = {false}; private: + /// Pointers to bulk/control commands + Hantek::BulkCommand *command[255] = {0}; + Hantek::BulkCommand* firstBulkCommand = nullptr; + Hantek::ControlCommand *control[255] = {0}; + Hantek::ControlCommand* firstControlCommand = nullptr; + // Communication with device USBDevice *device; ///< The USB device for the oscilloscope bool sampling = false; ///< true, if the oscilloscope is taking samples // Device setup - Hantek::ControlSpecification specification; ///< The specifications of the device - Hantek::ControlSettings controlsettings; ///< The current settings of the device + Dso::ControlSpecification specification; ///< The specifications of the device + Dso::ControlSettings controlsettings; ///< The current settings of the device // Results DSOsamples result; - unsigned previousSampleCount = 0; ///< The expected total number of samples at + unsigned expectedSampleCount = 0; ///< The expected total number of samples at /// the last check before sampling started // State of the communication thread @@ -187,14 +205,14 @@ class HantekDsoControl : public QObject { Dso::ErrorCode setSamplerate(double samplerate = 0.0); Dso::ErrorCode setRecordTime(double duration = 0.0); - Dso::ErrorCode setChannelUsed(unsigned channel, bool used); - Dso::ErrorCode setCoupling(unsigned channel, Dso::Coupling coupling); - Dso::ErrorCode setGain(unsigned channel, double gain); - Dso::ErrorCode setOffset(unsigned channel, double offset); + Dso::ErrorCode setChannelUsed(ChannelID channel, bool used); + Dso::ErrorCode setCoupling(ChannelID channel, Dso::Coupling coupling); + Dso::ErrorCode setGain(ChannelID channel, double gain); + Dso::ErrorCode setOffset(ChannelID channel, const double offset); Dso::ErrorCode setTriggerMode(Dso::TriggerMode mode); Dso::ErrorCode setTriggerSource(bool special, unsigned id); - Dso::ErrorCode setTriggerLevel(unsigned channel, double level); + Dso::ErrorCode setTriggerLevel(ChannelID channel, double level); Dso::ErrorCode setTriggerSlope(Dso::Slope slope); Dso::ErrorCode setPretriggerPosition(double position); void forceTrigger(); diff --git a/openhantek/src/hantekdso/models/modelDSO2090.cpp b/openhantek/src/hantekdso/models/modelDSO2090.cpp index 219bc03..07ba3aa 100644 --- a/openhantek/src/hantekdso/models/modelDSO2090.cpp +++ b/openhantek/src/hantekdso/models/modelDSO2090.cpp @@ -1,13 +1,11 @@ #include "modelDSO2090.h" #include "hantekprotocol/bulkStructs.h" +#include "hantekprotocol/controlStructs.h" #include "hantekdsocontrol.h" using namespace Hantek; -ModelDSO2090::ModelDSO2090() : DSOModel(ID, 0x04b5, 0x2090, 0x04b4, 0x2090, "dso2090x86", "DSO-2090", Hantek::ControlSpecification()) { - specification.command.control.setOffset = CONTROL_SETOFFSET; - specification.command.control.setRelays = CONTROL_SETRELAYS; - specification.command.bulk.setGain = BulkCode::SETGAIN; +ModelDSO2090::ModelDSO2090() : DSOModel(ID, 0x04b5, 0x2090, 0x04b4, 0x2090, "dso2090x86", "DSO-2090", Dso::ControlSpecification()) { specification.command.bulk.setRecordLength = BulkCode::SETTRIGGERANDSAMPLERATE; specification.command.bulk.setChannels = BulkCode::SETTRIGGERANDSAMPLERATE; specification.command.bulk.setSamplerate = BulkCode::SETTRIGGERANDSAMPLERATE; @@ -32,11 +30,9 @@ ModelDSO2090::ModelDSO2090() : DSOModel(ID, 0x04b5, 0x2090, 0x04b4, 0x2090, "dso } void ModelDSO2090::applyRequirements(HantekDsoControl *dsoControl) const { - dsoControl->command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = new BulkSetTriggerAndSamplerate(); - dsoControl->commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; - - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true; - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true; + dsoControl->addCommand(BulkCode::SETTRIGGERANDSAMPLERATE, new BulkSetTriggerAndSamplerate()); + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset()); + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays()); } ModelDSO2090A::ModelDSO2090A() { diff --git a/openhantek/src/hantekdso/models/modelDSO2150.cpp b/openhantek/src/hantekdso/models/modelDSO2150.cpp index a60baa6..b56ad5d 100644 --- a/openhantek/src/hantekdso/models/modelDSO2150.cpp +++ b/openhantek/src/hantekdso/models/modelDSO2150.cpp @@ -1,13 +1,11 @@ #include "modelDSO2150.h" #include "hantekprotocol/bulkStructs.h" +#include "hantekprotocol/controlStructs.h" #include "hantekdsocontrol.h" using namespace Hantek; -ModelDSO2150::ModelDSO2150() : DSOModel(ID, 0x04b5, 0x2150, 0x04b4, 0x2150, "dso2150x86", "DSO-2150", Hantek::ControlSpecification()) { - specification.command.control.setOffset = CONTROL_SETOFFSET; - specification.command.control.setRelays = CONTROL_SETRELAYS; - specification.command.bulk.setGain = BulkCode::SETGAIN; +ModelDSO2150::ModelDSO2150() : DSOModel(ID, 0x04b5, 0x2150, 0x04b4, 0x2150, "dso2150x86", "DSO-2150", Dso::ControlSpecification()) { specification.command.bulk.setRecordLength = BulkCode::SETTRIGGERANDSAMPLERATE; specification.command.bulk.setChannels = BulkCode::SETTRIGGERANDSAMPLERATE; specification.command.bulk.setSamplerate = BulkCode::SETTRIGGERANDSAMPLERATE; @@ -32,8 +30,7 @@ ModelDSO2150::ModelDSO2150() : DSOModel(ID, 0x04b5, 0x2150, 0x04b4, 0x2150, "dso } void ModelDSO2150::applyRequirements(HantekDsoControl *dsoControl) const { - dsoControl->command[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = new BulkSetTriggerAndSamplerate(); - dsoControl->commandPending[(uint8_t)BulkCode::SETTRIGGERANDSAMPLERATE] = true; - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true; - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true; + dsoControl->addCommand(BulkCode::SETTRIGGERANDSAMPLERATE, new BulkSetTriggerAndSamplerate()); + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset()); + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays()); } diff --git a/openhantek/src/hantekdso/models/modelDSO2250.cpp b/openhantek/src/hantekdso/models/modelDSO2250.cpp index ee8ef53..da407bb 100644 --- a/openhantek/src/hantekdso/models/modelDSO2250.cpp +++ b/openhantek/src/hantekdso/models/modelDSO2250.cpp @@ -1,13 +1,11 @@ #include "modelDSO2250.h" #include "hantekprotocol/bulkStructs.h" +#include "hantekprotocol/controlStructs.h" #include "hantekdsocontrol.h" using namespace Hantek; -ModelDSO2250::ModelDSO2250() : DSOModel(ID, 0x04b5, 0x2250, 0x04b4, 0x2250, "dso2250x86", "DSO-2250", Hantek::ControlSpecification()) { - specification.command.control.setOffset = CONTROL_SETOFFSET; - specification.command.control.setRelays = CONTROL_SETRELAYS; - specification.command.bulk.setGain = BulkCode::SETGAIN; +ModelDSO2250::ModelDSO2250() : DSOModel(ID, 0x04b5, 0x2250, 0x04b4, 0x2250, "dso2250x86", "DSO-2250", Dso::ControlSpecification()) { specification.command.bulk.setRecordLength = BulkCode::DSETBUFFER; specification.command.bulk.setChannels = BulkCode::BSETCHANNELS; specification.command.bulk.setSamplerate = BulkCode::ESETTRIGGERORSAMPLERATE; @@ -33,17 +31,11 @@ ModelDSO2250::ModelDSO2250() : DSOModel(ID, 0x04b5, 0x2250, 0x04b4, 0x2250, "dso void ModelDSO2250::applyRequirements(HantekDsoControl *dsoControl) const { // Instantiate additional commands for the DSO-2250 - dsoControl->command[(uint8_t)BulkCode::BSETCHANNELS] = new BulkSetChannels2250(); - dsoControl->command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = new BulkSetTrigger2250(); - dsoControl->command[(uint8_t)BulkCode::DSETBUFFER] = new BulkSetRecordLength2250(); - dsoControl->command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = new BulkSetSamplerate2250(); - dsoControl->command[(uint8_t)BulkCode::FSETBUFFER] = new BulkSetBuffer2250(); - dsoControl->commandPending[(uint8_t)BulkCode::BSETCHANNELS] = true; - dsoControl->commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true; - dsoControl->commandPending[(uint8_t)BulkCode::DSETBUFFER] = true; - dsoControl->commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; - dsoControl->commandPending[(uint8_t)BulkCode::FSETBUFFER] = true; - - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true; - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true; + dsoControl->addCommand(BulkCode::BSETCHANNELS, new BulkSetChannels2250()); + dsoControl->addCommand(BulkCode::CSETTRIGGERORSAMPLERATE, new BulkSetTrigger2250()); + dsoControl->addCommand(BulkCode::DSETBUFFER, new BulkSetRecordLength2250()); + dsoControl->addCommand(BulkCode::ESETTRIGGERORSAMPLERATE, new BulkSetSamplerate2250()); + dsoControl->addCommand(BulkCode::FSETBUFFER, new BulkSetBuffer2250()); + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset()); + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays()); } diff --git a/openhantek/src/hantekdso/models/modelDSO5200.cpp b/openhantek/src/hantekdso/models/modelDSO5200.cpp index 6f31197..1e10287 100644 --- a/openhantek/src/hantekdso/models/modelDSO5200.cpp +++ b/openhantek/src/hantekdso/models/modelDSO5200.cpp @@ -1,13 +1,11 @@ #include "modelDSO5200.h" #include "hantekprotocol/bulkStructs.h" +#include "hantekprotocol/controlStructs.h" #include "hantekdsocontrol.h" using namespace Hantek; -ModelDSO5200::ModelDSO5200() : DSOModel(ID, 0x04b5, 0x5200, 0x04b4, 0x5200, "dso5200x86", "DSO-5200", Hantek::ControlSpecification()) { - specification.command.control.setOffset = CONTROL_SETOFFSET; - specification.command.control.setRelays = CONTROL_SETRELAYS; - specification.command.bulk.setGain = BulkCode::SETGAIN; +ModelDSO5200::ModelDSO5200() : DSOModel(ID, 0x04b5, 0x5200, 0x04b4, 0x5200, "dso5200x86", "DSO-5200", Dso::ControlSpecification()) { specification.command.bulk.setRecordLength = BulkCode::DSETBUFFER; specification.command.bulk.setChannels = BulkCode::ESETTRIGGERORSAMPLERATE; specification.command.bulk.setSamplerate = BulkCode::CSETTRIGGERORSAMPLERATE; @@ -35,15 +33,11 @@ ModelDSO5200::ModelDSO5200() : DSOModel(ID, 0x04b5, 0x5200, 0x04b4, 0x5200, "dso void ModelDSO5200::applyRequirements(HantekDsoControl *dsoControl) const { // Instantiate additional commands for the DSO-5200 - dsoControl->command[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = new BulkSetSamplerate5200(); - dsoControl->command[(uint8_t)BulkCode::DSETBUFFER] = new BulkSetBuffer5200(); - dsoControl->command[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = new BulkSetTrigger5200(); - dsoControl->commandPending[(uint8_t)BulkCode::CSETTRIGGERORSAMPLERATE] = true; - dsoControl->commandPending[(uint8_t)BulkCode::DSETBUFFER] = true; - dsoControl->commandPending[(uint8_t)BulkCode::ESETTRIGGERORSAMPLERATE] = true; - - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = true; - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = true; + dsoControl->addCommand(BulkCode::CSETTRIGGERORSAMPLERATE, new BulkSetSamplerate5200()); + dsoControl->addCommand(BulkCode::DSETBUFFER, new BulkSetBuffer5200()); + dsoControl->addCommand(BulkCode::ESETTRIGGERORSAMPLERATE, new BulkSetTrigger5200()); + dsoControl->addCommand(ControlCode::CONTROL_SETOFFSET, new ControlSetOffset()); + dsoControl->addCommand(ControlCode::CONTROL_SETRELAYS, new ControlSetRelays()); } ModelDSO5200A::ModelDSO5200A() { diff --git a/openhantek/src/hantekdso/models/modelDSO6022.cpp b/openhantek/src/hantekdso/models/modelDSO6022.cpp index 02ef84e..89a06e9 100644 --- a/openhantek/src/hantekdso/models/modelDSO6022.cpp +++ b/openhantek/src/hantekdso/models/modelDSO6022.cpp @@ -1,12 +1,11 @@ #include "modelDSO6022.h" #include "usb/usbdevice.h" #include "hantekprotocol/controlStructs.h" -#include "controlindexes.h" #include "hantekdsocontrol.h" using namespace Hantek; -ModelDSO6022BE::ModelDSO6022BE() : DSOModel(ID, 0x04b5, 0x6022, 0x04b4, 0x6022, "dso6022be", "DSO-6022BE", Hantek::ControlSpecification()) { +ModelDSO6022BE::ModelDSO6022BE() : DSOModel(ID, 0x04b5, 0x6022, 0x04b4, 0x6022, "dso6022be", "DSO-6022BE", Dso::ControlSpecification()) { // 6022BE do not support any bulk commands specification.useControlNoBulk = true; specification.isSoftwareTriggerDevice = true; @@ -33,29 +32,17 @@ ModelDSO6022BE::ModelDSO6022BE() : DSOModel(ID, 0x04b5, 0x6022, 0x04b4, 0x6022, specification.fixedSampleRates = { {10,1e5} , {20,2e5} , {50,5e5} , {1,1e6} , {2,2e6} , {4,4e6} , {8,8e6} , {16,16e6} , {24,24e6} , {48,48e6} }; specification.sampleSize = 8; + + specification.couplings = {Dso::Coupling::DC}; } void ModelDSO6022BE::applyRequirements(HantekDsoControl *dsoControl) const { dsoControl->getDevice()->overwriteInPacketLength(16384); - dsoControl->control[CONTROLINDEX_SETVOLTDIV_CH1] = new ControlSetVoltDIV_CH1(); - dsoControl->controlCode[CONTROLINDEX_SETVOLTDIV_CH1] = CONTROL_SETVOLTDIV_CH1; - dsoControl->controlPending[CONTROLINDEX_SETVOLTDIV_CH1] = true; - - dsoControl->control[CONTROLINDEX_SETVOLTDIV_CH2] = new ControlSetVoltDIV_CH2(); - dsoControl->controlCode[CONTROLINDEX_SETVOLTDIV_CH2] = CONTROL_SETVOLTDIV_CH2; - dsoControl->controlPending[CONTROLINDEX_SETVOLTDIV_CH2] = true; - - dsoControl->control[CONTROLINDEX_SETTIMEDIV] = new ControlSetTimeDIV(); - dsoControl->controlCode[CONTROLINDEX_SETTIMEDIV] = CONTROL_SETTIMEDIV; - dsoControl->controlPending[CONTROLINDEX_SETTIMEDIV] = true; - - dsoControl->control[CONTROLINDEX_ACQUIIRE_HARD_DATA] = new ControlAcquireHardData(); - dsoControl->controlCode[CONTROLINDEX_ACQUIIRE_HARD_DATA] = CONTROL_ACQUIIRE_HARD_DATA; - dsoControl->controlPending[CONTROLINDEX_ACQUIIRE_HARD_DATA] = true; - - dsoControl->controlPending[CONTROLINDEX_SETOFFSET] = false; - dsoControl->controlPending[CONTROLINDEX_SETRELAYS] = false; + dsoControl->addCommand(ControlCode::CONTROL_ACQUIIRE_HARD_DATA, new ControlAcquireHardData()); + dsoControl->addCommand(ControlCode::CONTROL_SETTIMEDIV, new ControlSetTimeDIV()); + dsoControl->addCommand(ControlCode::CONTROL_SETVOLTDIV_CH2, new ControlSetVoltDIV_CH2()); + dsoControl->addCommand(ControlCode::CONTROL_SETVOLTDIV_CH1, new ControlSetVoltDIV_CH1()); } ModelDSO6022LE::ModelDSO6022LE() { diff --git a/openhantek/src/hantekdso/softwaretrigger.cpp b/openhantek/src/hantekdso/softwaretrigger.cpp new file mode 100644 index 0000000..6e33908 --- /dev/null +++ b/openhantek/src/hantekdso/softwaretrigger.cpp @@ -0,0 +1,80 @@ +#include "softwaretrigger.h" +#include "analyse/dataanalyzerresult.h" +#include "settings.h" +#include "viewconstants.h" +#include "utils/printutils.h" + +SoftwareTrigger::PrePostStartTriggerSamples SoftwareTrigger::computeTY(const DataAnalyzerResult *result, + const DsoSettingsScope *scope, + unsigned physicalChannels) +{ + unsigned int preTrigSamples = 0; + unsigned int postTrigSamples = 0; + unsigned int swTriggerStart = 0; + unsigned int channel = scope->trigger.source; + + // check trigger point for software trigger + if (scope->trigger.mode != Dso::TriggerMode::SOFTWARE || channel >= physicalChannels) + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); + + // Trigger channel not in use + if (!scope->voltage[channel].used || !result->data(channel) || + result->data(channel)->voltage.sample.empty()) + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); + + const std::vector& samples = result->data(channel)->voltage.sample; + double level = scope->voltage[channel].trigger; + size_t sampleCount = samples.size(); + double timeDisplay = scope->horizontal.timebase * DIVS_TIME; + double samplesDisplay = timeDisplay * scope->horizontal.samplerate; + + if (samplesDisplay >= sampleCount) { + // For sure not enough samples to adjust for jitter. + // Following options exist: + // 1: Decrease sample rate + // 2: Change trigger mode to auto + // 3: Ignore samples + // For now #3 is chosen + timestampDebug(QString("Too few samples to make a steady " + "picture. Decrease sample rate")); + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); + } + preTrigSamples = (unsigned)(scope->trigger.position * samplesDisplay); + postTrigSamples = (unsigned)sampleCount - ((unsigned)samplesDisplay - preTrigSamples); + + const int swTriggerThreshold = 7; + const int swTriggerSampleSet = 11; + double prev; + bool (*opcmp)(double,double,double); + bool (*smplcmp)(double,double); + if (scope->trigger.slope == Dso::Slope::Positive) { + prev = INT_MAX; + opcmp = [](double value, double level, double prev) { return value > level && prev <= level;}; + smplcmp = [](double sampleK, double value) { return sampleK >= value;}; + } else { + prev = INT_MIN; + opcmp = [](double value, double level, double prev) { return value < level && prev >= level;}; + smplcmp = [](double sampleK, double value) { return sampleK < value;}; + } + + for (unsigned int i = preTrigSamples; i < postTrigSamples; i++) { + double value = samples[i]; + if (opcmp(value, level, prev)) { + int rising = 0; + for (unsigned int k = i + 1; k < i + swTriggerSampleSet && k < sampleCount; k++) { + if (smplcmp(samples[k], value)) { rising++; } + } + if (rising > swTriggerThreshold) { + swTriggerStart = i; + break; + } + } + prev = value; + } + if (swTriggerStart == 0) { + timestampDebug(QString("Trigger not asserted. Data ignored")); + preTrigSamples = 0; // preTrigSamples may never be greater than swTriggerStart + postTrigSamples = 0; + } + return PrePostStartTriggerSamples(preTrigSamples, postTrigSamples, swTriggerStart); +} diff --git a/openhantek/src/hantekdso/softwaretrigger.h b/openhantek/src/hantekdso/softwaretrigger.h new file mode 100644 index 0000000..de9db8b --- /dev/null +++ b/openhantek/src/hantekdso/softwaretrigger.h @@ -0,0 +1,13 @@ +#pragma once +#include +struct DsoSettingsScope; +class DataAnalyzerResult; + +class SoftwareTrigger +{ +public: + typedef std::tuple PrePostStartTriggerSamples; + static PrePostStartTriggerSamples computeTY(const DataAnalyzerResult *result, + const DsoSettingsScope *scope, + unsigned physicalChannels); +}; diff --git a/openhantek/src/hantekprotocol/bulkStructs.h b/openhantek/src/hantekprotocol/bulkStructs.h index 65276a6..01dc189 100644 --- a/openhantek/src/hantekprotocol/bulkStructs.h +++ b/openhantek/src/hantekprotocol/bulkStructs.h @@ -16,6 +16,9 @@ namespace Hantek { class BulkCommand : public DataArray { protected: BulkCommand(unsigned size): DataArray(size) {} +public: + bool pending = false; + BulkCommand* next = nullptr; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/openhantek/src/hantekprotocol/bulkcode.h b/openhantek/src/hantekprotocol/bulkcode.h index 3afb047..45aafae 100644 --- a/openhantek/src/hantekprotocol/bulkcode.h +++ b/openhantek/src/hantekprotocol/bulkcode.h @@ -4,482 +4,460 @@ namespace Hantek { -////////////////////////////////////////////////////////////////////////////// -/// \enum BulkCode hantek/types.h /// \brief All supported bulk commands. /// Indicies given in square brackets specify byte numbers in little endian /// format. +/// SETFILTER [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// This command sets channel and trigger filter: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x000x00FilterBits0x000x000x000x000x00
+///

+/// +/// This command is used by the official %Hantek software, but doesn't seem +/// to be used by the device. +/// +/// +/// SETTRIGGERANDSAMPLERATE [::MODEL_DSO2090, ::MODEL_DSO2150] +///

+/// This command sets trigger and timebase: +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x010x00Tsr1BitsTsr2BitsDownsampler[0]Downsampler[1]
+/// +/// +/// +/// +/// +/// +/// +/// +/// +///
TriggerPosition[0]TriggerPosition[1]0x000x00TriggerPosition[2]0x00
+///

+///

+/// The samplerate is set relative to the base samplerate by a divider or to +/// a maximum samplerate.
+/// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to +/// the following values: +/// +/// +/// +/// +/// +/// +/// +///
Tsr1Bits.samplerateId0123
SamplerateMaxBaseBase / +/// 2Base / 5
+/// For higher divider values, the value can be set using the 16-bit value +/// in the two Downsampler bytes. The value of Downsampler is given by:
+/// Downsampler = 1comp((Base / Samplerate / 2) - 2)
+/// The Base samplerate is 50 MS/s for the DSO-2090 and DSO-2150. The Max +/// samplerate is also 50 MS/s for the DSO-2090 and 75 MS/s for the +/// DSO-2150.
+/// When using fast rate mode the Base and Max samplerate is twice as fast. +/// When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided +/// by 1000. +///

+///

+/// The TriggerPosition sets the position of the pretrigger in samples. The +/// left side (0 %) is 0x77660 when using the small buffer and 0x78000 when +/// using the large buffer. +///

+/// +/// FORCETRIGGER [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// This command forces triggering: +/// +/// +/// +/// +/// +///
0x020x00
+///

+/// +/// +/// STARTSAMPLING [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// This command starts to capture data: +/// +/// +/// +/// +/// +///
0x030x00
+///

+/// +/// +/// ENABLETRIGGER [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// This command sets the trigger: +/// +/// +/// +/// +/// +///
0x040x00
+///

+/// +/// +/// GETDATA [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// This command reads data from the hardware: +/// +/// +/// +/// +/// +///
0x050x00
+///

+///

+/// The oscilloscope returns the sample data, that will be split if it's +/// larger than the IN endpoint packet length: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
Sample[0]...Sample[511]
Sample[512]...Sample[1023]
Sample[1024]...
+/// Because of the 10 bit data model, the DSO-5200 transmits the two extra +/// bits for each sample afterwards: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
Extra[0] << 2 | Extra[1]0Extra[2] << 2 | Extra[3]0...Extra[510] << 2 | Extra[511]0
Extra[512] << 2 | Extra[513]...
+///

+/// +/// GETCAPTURESTATE [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A] +///

+/// This command checks the capture state: +/// +/// +/// +/// +/// +///
0x060x00
+///

+///

+/// The oscilloscope returns it's capture state and the trigger point. Not +/// sure about this, looks like 248 16-bit words with nearly constant +/// values. These can be converted to the start address of the data in the +/// buffer (See Hantek::Control::calculateTriggerPoint): +/// +/// +/// +/// +/// +/// +/// +/// +///
::CaptureState0x00TriggerPoint[0]TriggerPoint[1]...
+///

+/// +/// SETGAIN [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A] +///

+/// This command sets the gain: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x070x00GainBits0x000x000x000x000x00
+/// It is usually used in combination with ::CONTROL_SETRELAYS. +///

+/// +/// SETLOGICALDATA [] +///

+/// This command sets the logical data (Not used in official %Hantek software): +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x080x00Data | 0x010x000x000x000x000x00
+///

+/// +/// GETLOGICALDATA [] +///

+/// This command reads the logical data (Not used in official %Hantek +/// software): +/// +/// +/// +/// +/// +///
0x090x00
+///

+///

+/// The oscilloscope returns the logical data, which contains valid data in +/// the first byte although it is 64 or 512 bytes long: +/// +/// +/// +/// +/// +///
Data...
+///

+/// +/// BSETCHANNELS BulkSetChannels2250 [::MODEL_DSO2250] +///

+/// This command sets the activated channels for the DSO-2250: +/// +/// +/// +/// +/// +/// +/// +///
0x0b0x00BUsedChannels0x00
+///

+/// +/// CSETTRIGGERORSAMPLERATE BulkSetTrigger2250 [::MODEL_DSO2250] +///

+/// This command sets the trigger source for the DSO-2250: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0c0x00CTriggerBits0x000x000x000x000x00
+///

+/// +/// BulkSetSamplerate5200 [::MODEL_DSO5200, ::MODEL_DSO5200A] +///

+/// This command sets the sampling rate for the DSO-5200: +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0c0x00SamplerateSlow[0]SamplerateSlow[1]SamplerateFast0x00
+///

+///

+/// The samplerate is set relative to the maximum sample rate by a divider +/// that is set in SamplerateFast and the 16-bit value in the two +/// SamplerateSlow bytes.
+/// Without using fast rate mode, the samplerate is:
+/// Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 - +/// SamplerateFast)
+/// SamplerateBase is 100 MS/s for the DSO-5200 in normal mode and 200 MS/s +/// in fast rate mode, the modifications regarding record length are the the +/// same that apply for the DSO-2090. The maximum samplerate is 125 MS/s in +/// normal mode and 250 MS/s in fast rate mode, and is reached by setting +/// SamplerateSlow = 0 and SamplerateFast = 4. +///

+/// +/// DSETBUFFER BulkSetRecordLength2250 [::MODEL_DSO2250] +///

+/// This command sets the record length for the DSO-2250: +/// +/// +/// +/// +/// +/// +/// +///
0x0d0x00::RecordLengthId0x00
+///

+/// +/// BulkSetBuffer5200 [::MODEL_DSO5200, ::MODEL_DSO5200A] +///

+/// This command sets the trigger position and record length for the +/// DSO-5200: +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0d0x00TriggerPositionPre[0]TriggerPositionPre[1]::DTriggerPositionUsed
+/// +/// +/// +/// +/// +/// +/// +/// +///
0xffTriggerPositionPost[0]TriggerPositionPost[1]DBufferBits0xff
+///

+///

+/// The TriggerPositionPre and TriggerPositionPost values set the pretrigger +/// position. Both values have a range from 0xd7ff (0xc7ff for 14 kiS +/// buffer) to 0xfffe. On the left side (0 %) the TriggerPositionPre value +/// is minimal, on the right side (100 %) it is maximal. The +/// TriggerPositionPost value is maximal for 0 % and minimal for 100%. +///

+/// +/// ESETTRIGGERORSAMPLERATE BulkSetSamplerate2250 [::MODEL_DSO2250] +///

+/// This command sets the samplerate: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0e0x00ESamplerateBits0x00Samplerate[0]Samplerate[1]0x000x00
+///

+///

+/// The downsampler can be activated by setting ESamplerateBits.downsampling +/// = 1. If this is the case, the value of Downsampler is given by:
+/// Downsampler = 1comp((Base / Samplerate) - 2)
+/// Base is 100 MS/s for the DSO-2250 in standard mode and 200 MS/s in fast +/// rate mode, the modifications regarding record length are the the same +/// that apply for the DSO-2090. The maximum samplerate is 125 MS/s in +/// standard mode and 250 MS/s in fast rate mode and is achieved by setting +/// ESamplerateBits.downsampling = 0. +///

+/// +/// ESETTRIGGERORSAMPLERATE BulkSetTrigger5200 [::MODEL_DSO5200, ::MODEL_DSO5200A] +///

+/// This command sets the channel and trigger settings: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0e0x00ETsrBits0x000x000x000x000x00
+///

+/// +/// FSETBUFFER BulkSetBuffer2250 [::MODEL_DSO2250] +///

+/// This command sets the trigger position and buffer configuration for the +/// DSO-2250: +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0f0x00TriggerPositionPost[0]TriggerPositionPost[1]TriggerPositionPost[2]0x00
+/// +/// +/// +/// +/// +/// +/// +/// +/// +///
TriggerPositionPre[0]TriggerPositionPre[1]TriggerPositionPre[2]0x000x000x00
+///

+///

+/// The TriggerPositionPre and TriggerPositionPost values set the pretrigger +/// position. Both values have a range from 0x7d800 (0x00000 for 512 kiS +/// buffer) to 0x7ffff. On the left side (0 %) the TriggerPositionPre value +/// is minimal, on the right side (100 %) it is maximal. The +/// TriggerPositionPost value is maximal for 0 % and minimal for 100%. +///

+/// +/// AUNKNOWN [] +///

+/// This command isn't used for any supported model: +/// +/// +/// +/// +/// +///
0x0a...
+///

+///


enum class BulkCode : uint8_t { - /// BulkSetFilter [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A] - ///

- /// This command sets channel and trigger filter: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x000x00FilterBits0x000x000x000x000x00
- ///

- ///

- /// This command is used by the official %Hantek software, but doesn't seem - /// to be used by the device. - ///


- SETFILTER, - - /// BulkSetTriggerAndSamplerate [::MODEL_DSO2090, ::MODEL_DSO2150] - ///

- /// This command sets trigger and timebase: - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x010x00Tsr1BitsTsr2BitsDownsampler[0]Downsampler[1]
- /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
TriggerPosition[0]TriggerPosition[1]0x000x00TriggerPosition[2]0x00
- ///

- ///

- /// The samplerate is set relative to the base samplerate by a divider or to - /// a maximum samplerate.
- /// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to - /// the following values: - /// - /// - /// - /// - /// - /// - /// - ///
Tsr1Bits.samplerateId0123
SamplerateMaxBaseBase / - /// 2Base / 5
- /// For higher divider values, the value can be set using the 16-bit value - /// in the two Downsampler bytes. The value of Downsampler is given by:
- /// Downsampler = 1comp((Base / Samplerate / 2) - 2)
- /// The Base samplerate is 50 MS/s for the DSO-2090 and DSO-2150. The Max - /// samplerate is also 50 MS/s for the DSO-2090 and 75 MS/s for the - /// DSO-2150.
- /// When using fast rate mode the Base and Max samplerate is twice as fast. - /// When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided - /// by 1000. - ///

- ///

- /// The TriggerPosition sets the position of the pretrigger in samples. The - /// left side (0 %) is 0x77660 when using the small buffer and 0x78000 when - /// using the large buffer. - ///

- ///


- SETTRIGGERANDSAMPLERATE, - - /// BulkForceTrigger [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, - /// ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command forces triggering: - /// - /// - /// - /// - /// - ///
0x020x00
- ///

- ///


- FORCETRIGGER, - - /// BulkCaptureStart [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, - /// ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command starts to capture data: - /// - /// - /// - /// - /// - ///
0x030x00
- ///

- ///


- STARTSAMPLING, - - /// BulkTriggerEnabled [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, - /// ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command sets the trigger: - /// - /// - /// - /// - /// - ///
0x040x00
- ///

- ///


- ENABLETRIGGER, - - /// BulkGetData [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, - /// ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command reads data from the hardware: - /// - /// - /// - /// - /// - ///
0x050x00
- ///

- ///

- /// The oscilloscope returns the sample data, that will be split if it's - /// larger than the IN endpoint packet length: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
Sample[0]...Sample[511]
Sample[512]...Sample[1023]
Sample[1024]...
- /// Because of the 10 bit data model, the DSO-5200 transmits the two extra - /// bits for each sample afterwards: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
Extra[0] << 2 | Extra[1]0Extra[2] << 2 | Extra[3]0...Extra[510] << 2 | Extra[511]0
Extra[512] << 2 | Extra[513]...
- ///

- ///


- GETDATA, - - /// BulkGetCaptureState [::MODEL_DSO2090, ::MODEL_DSO2150, - /// ::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command checks the capture state: - /// - /// - /// - /// - /// - ///
0x060x00
- ///

- ///

- /// The oscilloscope returns it's capture state and the trigger point. Not - /// sure about this, looks like 248 16-bit words with nearly constant - /// values. These can be converted to the start address of the data in the - /// buffer (See Hantek::Control::calculateTriggerPoint): - /// - /// - /// - /// - /// - /// - /// - /// - ///
::CaptureState0x00TriggerPoint[0]TriggerPoint[1]...
- ///

- ///


- GETCAPTURESTATE, - - /// BulkSetGain [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, - /// ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command sets the gain: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x070x00GainBits0x000x000x000x000x00
- /// It is usually used in combination with ::CONTROL_SETRELAYS. - ///

- ///


- SETGAIN, - - /// BulkSetLogicalData [] - ///

- /// This command sets the logical data (Not used in official %Hantek - /// software): - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x080x00Data | 0x010x000x000x000x000x00
- ///

- ///


- SETLOGICALDATA, - - /// BulkGetLogicalData [] - ///

- /// This command reads the logical data (Not used in official %Hantek - /// software): - /// - /// - /// - /// - /// - ///
0x090x00
- ///

- ///

- /// The oscilloscope returns the logical data, which contains valid data in - /// the first byte although it is 64 or 512 bytes long: - /// - /// - /// - /// - /// - ///
Data...
- ///

- ///


- GETLOGICALDATA, - - /// [] - ///

- /// This command isn't used for any supported model: - /// - /// - /// - /// - /// - ///
0x0a...
- ///

- ///


- AUNKNOWN, - - /// BulkSetChannels2250 [::MODEL_DSO2250] - ///

- /// This command sets the activated channels for the DSO-2250: - /// - /// - /// - /// - /// - /// - /// - ///
0x0b0x00BUsedChannels0x00
- ///

- ///


- BSETCHANNELS, - - /// BulkSetTrigger2250 [::MODEL_DSO2250] - ///

- /// This command sets the trigger source for the DSO-2250: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0c0x00CTriggerBits0x000x000x000x000x00
- ///

- ///


- /// BulkSetSamplerate5200 [::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command sets the sampling rate for the DSO-5200: - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0c0x00SamplerateSlow[0]SamplerateSlow[1]SamplerateFast0x00
- ///

- ///

- /// The samplerate is set relative to the maximum sample rate by a divider - /// that is set in SamplerateFast and the 16-bit value in the two - /// SamplerateSlow bytes.
- /// Without using fast rate mode, the samplerate is:
- /// Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 - - /// SamplerateFast)
- /// SamplerateBase is 100 MS/s for the DSO-5200 in normal mode and 200 MS/s - /// in fast rate mode, the modifications regarding record length are the the - /// same that apply for the DSO-2090. The maximum samplerate is 125 MS/s in - /// normal mode and 250 MS/s in fast rate mode, and is reached by setting - /// SamplerateSlow = 0 and SamplerateFast = 4. - ///

- ///


- CSETTRIGGERORSAMPLERATE, - - /// BulkSetRecordLength2250 [::MODEL_DSO2250] - ///

- /// This command sets the record length for the DSO-2250: - /// - /// - /// - /// - /// - /// - /// - ///
0x0d0x00::RecordLengthId0x00
- ///

- ///


- /// BulkSetBuffer5200 [::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command sets the trigger position and record length for the - /// DSO-5200: - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0d0x00TriggerPositionPre[0]TriggerPositionPre[1]::DTriggerPositionUsed
- /// - /// - /// - /// - /// - /// - /// - /// - ///
0xffTriggerPositionPost[0]TriggerPositionPost[1]DBufferBits0xff
- ///

- ///

- /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger - /// position. Both values have a range from 0xd7ff (0xc7ff for 14 kiS - /// buffer) to 0xfffe. On the left side (0 %) the TriggerPositionPre value - /// is minimal, on the right side (100 %) it is maximal. The - /// TriggerPositionPost value is maximal for 0 % and minimal for 100%. - ///

- ///


- DSETBUFFER, - - /// BulkSetSamplerate2250 [::MODEL_DSO2250] - ///

- /// This command sets the samplerate: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0e0x00ESamplerateBits0x00Samplerate[0]Samplerate[1]0x000x00
- ///

- ///

- /// The downsampler can be activated by setting ESamplerateBits.downsampling - /// = 1. If this is the case, the value of Downsampler is given by:
- /// Downsampler = 1comp((Base / Samplerate) - 2)
- /// Base is 100 MS/s for the DSO-2250 in standard mode and 200 MS/s in fast - /// rate mode, the modifications regarding record length are the the same - /// that apply for the DSO-2090. The maximum samplerate is 125 MS/s in - /// standard mode and 250 MS/s in fast rate mode and is achieved by setting - /// ESamplerateBits.downsampling = 0. - ///

- ///


- /// BulkSetTrigger5200 [::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// This command sets the channel and trigger settings: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0e0x00ETsrBits0x000x000x000x000x00
- ///

- ///


- ESETTRIGGERORSAMPLERATE, - - /// BulkSetBuffer2250 [::MODEL_DSO2250] - ///

- /// This command sets the trigger position and buffer configuration for the - /// DSO-2250: - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0f0x00TriggerPositionPost[0]TriggerPositionPost[1]TriggerPositionPost[2]0x00
- /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
TriggerPositionPre[0]TriggerPositionPre[1]TriggerPositionPre[2]0x000x000x00
- ///

- ///

- /// The TriggerPositionPre and TriggerPositionPost values set the pretrigger - /// position. Both values have a range from 0x7d800 (0x00000 for 512 kiS - /// buffer) to 0x7ffff. On the left side (0 %) the TriggerPositionPre value - /// is minimal, on the right side (100 %) it is maximal. The - /// TriggerPositionPost value is maximal for 0 % and minimal for 100%. - ///

- ///


- FSETBUFFER, - - COUNT + SETFILTER = 0x00, + SETTRIGGERANDSAMPLERATE = 0x01, + FORCETRIGGER = 0x02, + STARTSAMPLING = 0x03, + ENABLETRIGGER = 0x04, + GETDATA = 0x05, + GETCAPTURESTATE = 0x06, + SETGAIN = 0x07, + SETLOGICALDATA = 0x08, + GETLOGICALDATA = 0x09, + AUNKNOWN = 0x0a, + BSETCHANNELS = 0x0b, + CSETTRIGGERORSAMPLERATE = 0x0c, + DSETBUFFER = 0x0d, + ESETTRIGGERORSAMPLERATE = 0x0e, + FSETBUFFER = 0x0f, + INVALID=0xff }; } diff --git a/openhantek/src/hantekprotocol/controlStructs.cpp b/openhantek/src/hantekprotocol/controlStructs.cpp index c5fdf13..5ca20ce 100644 --- a/openhantek/src/hantekprotocol/controlStructs.cpp +++ b/openhantek/src/hantekprotocol/controlStructs.cpp @@ -6,9 +6,9 @@ namespace Hantek { -ControlSetOffset::ControlSetOffset() : ControlCommand(17) {} +ControlSetOffset::ControlSetOffset() : ControlCommand(ControlCode::CONTROL_SETOFFSET, 17) {} -ControlSetOffset::ControlSetOffset(uint16_t channel1, uint16_t channel2, uint16_t trigger) : ControlCommand(17) { +ControlSetOffset::ControlSetOffset(uint16_t channel1, uint16_t channel2, uint16_t trigger) : ControlCommand(ControlCode::CONTROL_SETOFFSET, 17) { this->setChannel(0, channel1); this->setChannel(1, channel2); this->setTrigger(trigger); @@ -40,7 +40,7 @@ void ControlSetOffset::setTrigger(uint16_t level) { ControlSetRelays::ControlSetRelays(bool ch1Below1V, bool ch1Below100mV, bool ch1CouplingDC, bool ch2Below1V, bool ch2Below100mV, bool ch2CouplingDC, bool triggerExt) - : ControlCommand(17) { + : ControlCommand(ControlCode::CONTROL_SETRELAYS,17) { this->setBelow1V(0, ch1Below1V); this->setBelow100mV(0, ch1Below100mV); this->setCoupling(0, ch1CouplingDC); @@ -96,17 +96,17 @@ bool ControlSetRelays::getTrigger() { return (this->array[7] & 0x01) == 0x00; } void ControlSetRelays::setTrigger(bool ext) { this->array[7] = ext ? 0xfe : 0x01; } -ControlSetVoltDIV_CH1::ControlSetVoltDIV_CH1() : ControlCommand(1) { this->setDiv(5); } +ControlSetVoltDIV_CH1::ControlSetVoltDIV_CH1() : ControlCommand(ControlCode::CONTROL_SETVOLTDIV_CH1,1) { this->setDiv(5); } void ControlSetVoltDIV_CH1::setDiv(uint8_t val) { this->array[0] = val; } -ControlSetVoltDIV_CH2::ControlSetVoltDIV_CH2() : ControlCommand(1) { this->setDiv(5); } +ControlSetVoltDIV_CH2::ControlSetVoltDIV_CH2() : ControlCommand(ControlCode::CONTROL_SETVOLTDIV_CH2,1) { this->setDiv(5); } void ControlSetVoltDIV_CH2::setDiv(uint8_t val) { this->array[0] = val; } -ControlSetTimeDIV::ControlSetTimeDIV() : ControlCommand(1) { this->setDiv(1); } +ControlSetTimeDIV::ControlSetTimeDIV() : ControlCommand(ControlCode::CONTROL_SETTIMEDIV,1) { this->setDiv(1); } void ControlSetTimeDIV::setDiv(uint8_t val) { this->array[0] = val; } -ControlAcquireHardData::ControlAcquireHardData() : ControlCommand(1) { this->array[0] = 0x01; } +ControlAcquireHardData::ControlAcquireHardData() : ControlCommand(ControlCode::CONTROL_ACQUIIRE_HARD_DATA,1) { this->array[0] = 0x01; } } diff --git a/openhantek/src/hantekprotocol/controlStructs.h b/openhantek/src/hantekprotocol/controlStructs.h index 3ebe515..30cbf63 100644 --- a/openhantek/src/hantekprotocol/controlStructs.h +++ b/openhantek/src/hantekprotocol/controlStructs.h @@ -3,11 +3,16 @@ #include "definitions.h" #include "usb/usbdevicedefinitions.h" #include "utils/dataarray.h" +#include "controlcode.h" namespace Hantek { class ControlCommand : public DataArray { protected: - ControlCommand(unsigned size): DataArray(size) {} + ControlCommand(ControlCode code, unsigned size): DataArray(size), code(code) {} +public: + bool pending = false; + ControlCode code; + ControlCommand* next = nullptr; }; struct ControlSetOffset : public ControlCommand { diff --git a/openhantek/src/hantekprotocol/controlcode.h b/openhantek/src/hantekprotocol/controlcode.h index fa26910..3653f9c 100644 --- a/openhantek/src/hantekprotocol/controlcode.h +++ b/openhantek/src/hantekprotocol/controlcode.h @@ -1,144 +1,140 @@ #pragma once +#include + +namespace Hantek { -////////////////////////////////////////////////////////////////////////////// -/// \enum ControlCode hantek/types.h /// \brief All supported control commands. -enum ControlCode { - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A, MODEL_DSO6022] - ///

- /// The 0xa2 control read/write command gives access to a ::ControlValue. - ///

- ///


- CONTROL_VALUE = 0xa2, - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A, MODEL_DSO6022] - ///

- /// The 0xb2 control read command gets the speed level of the USB - /// connection: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
::ConnectionSpeed0x000x000x000x000x000x000x000x000x00
- ///

- ///


+/// CONTROL_VALUE [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A, MODEL_DSO6022] +///

+/// The 0xa2 control read/write command gives access to a ControlValue. +///

+/// +/// CONTROL_GETSPEED [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A, MODEL_DSO6022] +///

+/// The 0xb2 control read command gets the speed level of the USB +/// connection: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
ConnectionSpeed0x000x000x000x000x000x000x000x000x00
+///

+/// +/// CONTROL_BEGINCOMMAND [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// The 0xb3 control write command is sent before any bulk command: +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x0fBulkIndexBulkIndexBulkIndex0x000x000x000x000x000x00
+///

+/// +/// CONTROL_SETOFFSET [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// The 0xb4 control write command sets the channel offsets: +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
Ch1Offset[1]Ch1Offset[0]Ch2Offset[1]Ch2Offset[0]TriggerOffset[1]TriggerOffset[0]
+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x000x000x000x000x000x000x000x000x000x000x00
+///

+/// +/// CONTROL_SETRELAYS [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// The 0xb5 control write command sets the internal relays: +/// +/// +/// +/// +/// +/// +/// +///
0x000x04 ^ (Ch1Gain < 1 V)0x08 ^ (Ch1Gain < 100 mV)0x02 ^ (Ch1Coupling == DC)
+/// +/// +/// +/// +/// +/// +/// +///
0x20 ^ (Ch2Gain < 1 V)0x40 ^ (Ch2Gain < 100 mV)0x10 ^ (Ch2Coupling == DC)0x01 ^ (Trigger == EXT)
+/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +///
0x000x000x000x000x000x000x000x000x00
+///

+///

+/// The limits are <= instead of < for the 10 bit models, since those +/// support voltages up to 10 V. +///

+/// +/// CONTROL_SETVOLTDIV_CH1 CH1 voltage div setting (6022BE/BL) +/// +/// CONTROL_SETVOLTDIV_CH2 CH2 voltage div setting (6022BE/BL) +/// +/// CONTROL_SETTIMEDIV Time divisor setting (6022BE/BL) +/// +/// CONTROL_ACQUIIRE_HARD_DATA Request sample data (6022BE/BL) +enum class ControlCode : uint8_t { + CONTROL_VALUE = 0xa2, CONTROL_GETSPEED = 0xb2, - - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A] - ///

- /// The 0xb3 control write command is sent before any bulk command: - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x0f::BulkIndex::BulkIndex::BulkIndex0x000x000x000x000x000x00
- ///

- ///


CONTROL_BEGINCOMMAND = 0xb3, - - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A] - ///

- /// The 0xb4 control write command sets the channel offsets: - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
Ch1Offset[1]Ch1Offset[0]Ch2Offset[1]Ch2Offset[0]TriggerOffset[1]TriggerOffset[0]
- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x000x000x000x000x000x000x000x000x000x000x00
- ///

- ///


CONTROL_SETOFFSET = 0xb4, - - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A] - ///

- /// The 0xb5 control write command sets the internal relays: - /// - /// - /// - /// - /// - /// - /// - ///
0x000x04 ^ (Ch1Gain < 1 V)0x08 ^ (Ch1Gain < 100 mV)0x02 ^ (Ch1Coupling == DC)
- /// - /// - /// - /// - /// - /// - /// - ///
0x20 ^ (Ch2Gain < 1 V)0x40 ^ (Ch2Gain < 100 mV)0x10 ^ (Ch2Coupling == DC)0x01 ^ (Trigger == EXT)
- /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - /// - ///
0x000x000x000x000x000x000x000x000x00
- ///

- ///

- /// The limits are <= instead of < for the 10 bit models, since those - /// support voltages up to 10 V. - ///

- ///


CONTROL_SETRELAYS = 0xb5, - - /// CH1 voltage div setting (6022BE/BL) CONTROL_SETVOLTDIV_CH1 = 0xe0, - /// CH2 voltage div setting (6022BE/BL) CONTROL_SETVOLTDIV_CH2 = 0xe1, - /// Time divisor setting (6022BE/BL) CONTROL_SETTIMEDIV = 0xe2, - /// Request sample data (6022BE/BL) CONTROL_ACQUIIRE_HARD_DATA = 0xe3 }; +} diff --git a/openhantek/src/hantekprotocol/controlvalue.h b/openhantek/src/hantekprotocol/controlvalue.h index 7b6b9c0..5b3699e 100644 --- a/openhantek/src/hantekprotocol/controlvalue.h +++ b/openhantek/src/hantekprotocol/controlvalue.h @@ -1,47 +1,44 @@ #pragma once -namespace Hantek { +#include +namespace Hantek { -////////////////////////////////////////////////////////////////////////////// -/// \enum ControlValue hantek/types.h /// \brief All supported values for control commands. -enum ControlValue { - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A] - ///

- /// Value 0x08 is the calibration data for the channels offsets. It holds the - /// offset value for the top and bottom of the scope screen for every gain - /// step on every channel. The data is stored as a three-dimensional array:
- /// channelLevels[channel][GainId][::LevelOffset] - ///

- ///


+/// VALUE_OFFSETLIMITS [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// Value 0x08 is the calibration data for the channels offsets. It holds the +/// offset value for the top and bottom of the scope screen for every gain +/// step on every channel. The data is stored as a three-dimensional array:
+/// channelLevels[channel][GainId][LevelOffset] +///

+///


+/// +/// VALUE_DEVICEADDRESS [MODEL_DSO2090, MODEL_DSO2150, MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// Value 0x0a is the address of the device. It has a length of one byte. +///

+///


+/// +/// VALUE_FASTRATECALIBRATION [MODEL_DSO2250, MODEL_DSO5200, MODEL_DSO5200A] +///

+/// Value 0x60 is the calibration data for the fast rate mode on the DSO-2250, +/// DSO-5200 and DSO-5200A. It's used to correct the level differences between +/// the two merged channels to avoid deterministic noise. +///

+///


+/// +/// VALUE_ETSCORRECTION [MODEL_DSO5200, MODEL_DSO5200A] +///

+/// Value 0x70 contains correction values for the ETS functionality of the +/// DSO-5200 and DSO-5200A. +///

+///


+enum class ControlValue : uint8_t { VALUE_OFFSETLIMITS = 0x08, - - /// [::MODEL_DSO2090, ::MODEL_DSO2150, ::MODEL_DSO2250, ::MODEL_DSO5200, - /// ::MODEL_DSO5200A] - ///

- /// Value 0x0a is the address of the device. It has a length of one byte. - ///

- ///


VALUE_DEVICEADDRESS = 0x0a, - - /// [::MODEL_DSO2250, ::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// Value 0x60 is the calibration data for the fast rate mode on the DSO-2250, - /// DSO-5200 and DSO-5200A. It's used to correct the level differences between - /// the two merged channels to avoid deterministic noise. - ///

- ///


VALUE_FASTRATECALIBRATION = 0x60, - - /// [::MODEL_DSO5200, ::MODEL_DSO5200A] - ///

- /// Value 0x70 contains correction values for the ETS functionality of the - /// DSO-5200 and DSO-5200A. - ///

- ///


VALUE_ETSCORRECTION = 0x70 }; diff --git a/openhantek/src/hantekprotocol/definitions.h b/openhantek/src/hantekprotocol/definitions.h index 55e630b..2b70b7c 100644 --- a/openhantek/src/hantekprotocol/definitions.h +++ b/openhantek/src/hantekprotocol/definitions.h @@ -9,6 +9,9 @@ #define HANTEK_GAIN_STEPS 9 #define HANTEK_CHANNELS 2 ///< Number of physical channels +typedef unsigned RecordLengthID; +typedef unsigned ChannelID; + namespace Hantek { /// \enum UsedChannels /// \brief The enabled channels. diff --git a/openhantek/src/main.cpp b/openhantek/src/main.cpp index 68699fc..6fd2475 100644 --- a/openhantek/src/main.cpp +++ b/openhantek/src/main.cpp @@ -16,7 +16,7 @@ #include "settings.h" #include "usb/usbdevice.h" #include "dsomodel.h" -#include "selectdevice/selectdevice.h" +#include "selectdevice/selectsupporteddevice.h" using namespace Hantek; @@ -45,10 +45,10 @@ int main(int argc, char *argv[]) { libusb_context *context = nullptr; int error = libusb_init(&context); if (error) { - SelectDevice().showLibUSBFailedDialogModel(error); + SelectSupportedDevice().showLibUSBFailedDialogModel(error); return -1; } - std::unique_ptr device = SelectDevice().showSelectDeviceModal(context); + std::unique_ptr device = SelectSupportedDevice().showSelectDeviceModal(context); QString errorMessage; if (device == nullptr || !device->connectDevice(errorMessage)) { @@ -76,8 +76,8 @@ int main(int argc, char *argv[]) { QObject::connect(&dsoControl, &HantekDsoControl::samplesAvailable, &dataAnalyser, &DataAnalyzer::samplesAvailable); //////// Create settings object //////// - DsoSettings settings(dsoControl.getChannelCount()); - dataAnalyser.applySettings(&settings.scope); + DsoSettings settings(dsoControl.getDeviceSettings(), &device->getModel()->specification); + dataAnalyser.applySettings(&settings); //////// Create main window //////// OpenHantekMainWindow *openHantekMainWindow = new OpenHantekMainWindow(&dsoControl, &dataAnalyser, &settings); diff --git a/openhantek/src/mainwindow.cpp b/openhantek/src/mainwindow.cpp index 3e6d72c..554ae8c 100644 --- a/openhantek/src/mainwindow.cpp +++ b/openhantek/src/mainwindow.cpp @@ -291,8 +291,6 @@ void OpenHantekMainWindow::connectSignals() { connect(horizontalDock, &HorizontalDock::timebaseChanged, this, &OpenHantekMainWindow::timebaseSelected); connect(horizontalDock, &HorizontalDock::frequencybaseChanged, dsoWidget, &DsoWidget::updateFrequencybase); connect(horizontalDock, &HorizontalDock::recordLengthChanged, this, &OpenHantekMainWindow::recordLengthSelected); - // connect(horizontalDock, SIGNAL(formatChanged(HorizontalFormat)), - // dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat))); connect(triggerDock, &TriggerDock::modeChanged, dsoControl, &HantekDsoControl::setTriggerMode); connect(triggerDock, &TriggerDock::modeChanged, dsoWidget, &DsoWidget::updateTriggerMode); @@ -332,13 +330,13 @@ void OpenHantekMainWindow::connectSignals() { /// \brief Initialize the device with the current settings. void OpenHantekMainWindow::applySettingsToDevice() { - for (unsigned int channel = 0; channel < settings->scope.physicalChannels; ++channel) { - dsoControl->setCoupling(channel, settings->scope.voltage[channel].coupling); + for (unsigned int channel = 0; channel < settings->deviceSpecification->channels; ++channel) { + dsoControl->setCoupling(channel, settings->coupling(channel)); updateVoltageGain(channel); updateOffset(channel); dsoControl->setTriggerLevel(channel, settings->scope.voltage[channel].trigger); } - updateUsed(settings->scope.physicalChannels); + updateUsed(settings->deviceSpecification->channels); if (settings->scope.horizontal.samplerateSet) samplerateSelected(); else @@ -468,7 +466,7 @@ void OpenHantekMainWindow::timebaseSelected() { /// \brief Sets the offset of the oscilloscope for the given channel. /// \param channel The channel that got a new offset. void OpenHantekMainWindow::updateOffset(unsigned int channel) { - if (channel >= settings->scope.physicalChannels) return; + if (channel >= settings->deviceSpecification->channels) return; dsoControl->setOffset(channel, (settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5); } @@ -478,16 +476,16 @@ void OpenHantekMainWindow::updateOffset(unsigned int channel) { void OpenHantekMainWindow::updateUsed(unsigned int channel) { if (channel >= (unsigned int)settings->scope.voltage.size()) return; - bool mathUsed = settings->scope.voltage[settings->scope.physicalChannels].used | - settings->scope.spectrum[settings->scope.physicalChannels].used; + bool mathUsed = settings->scope.voltage[settings->deviceSpecification->channels].used | + settings->scope.spectrum[settings->deviceSpecification->channels].used; // Normal channel, check if voltage/spectrum or math channel is used - if (channel < settings->scope.physicalChannels) + if (channel < settings->deviceSpecification->channels) dsoControl->setChannelUsed( channel, mathUsed | settings->scope.voltage[channel].used | settings->scope.spectrum[channel].used); // Math channel, update all channels - else if (channel == settings->scope.physicalChannels) { - for (unsigned int channelCounter = 0; channelCounter < settings->scope.physicalChannels; ++channelCounter) + else if (channel == settings->deviceSpecification->channels) { + for (unsigned int channelCounter = 0; channelCounter < settings->deviceSpecification->channels; ++channelCounter) dsoControl->setChannelUsed(channelCounter, mathUsed | settings->scope.voltage[channelCounter].used | settings->scope.spectrum[channelCounter].used); @@ -497,7 +495,7 @@ void OpenHantekMainWindow::updateUsed(unsigned int channel) { /// \brief Sets the gain of the oscilloscope for the given channel. /// \param channel The channel that got a new gain value. void OpenHantekMainWindow::updateVoltageGain(unsigned int channel) { - if (channel >= settings->scope.physicalChannels) return; + if (channel >= settings->deviceSpecification->channels) return; - dsoControl->setGain(channel, settings->scope.voltage[channel].gain * DIVS_VOLTAGE); + dsoControl->setGain(channel, settings->scope.gain(channel) * DIVS_VOLTAGE); } diff --git a/openhantek/src/scopesettings.h b/openhantek/src/scopesettings.h index 3e519b6..57bebca 100644 --- a/openhantek/src/scopesettings.h +++ b/openhantek/src/scopesettings.h @@ -1,16 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ + #pragma once -#include +#include + #include "analyse/enums.h" #include "hantekdso/enums.h" +#include "hantekprotocol/definitions.h" +#include #define MARKER_COUNT 2 ///< Number of markers -//////////////////////////////////////////////////////////////////////////////// -/// \struct DsoSettingsScopeHorizontal settings.h /// \brief Holds the settings for the horizontal axis. struct DsoSettingsScopeHorizontal { - Dso::GraphFormat format = Dso::GRAPHFORMAT_TY; ///< Graph drawing mode of the scope + Dso::GraphFormat format = Dso::GraphFormat::TY; ///< Graph drawing mode of the scope double frequencybase = 1e3; ///< Frequencybase in Hz/div double marker[MARKER_COUNT] = {-1.0, 1.0}; ///< Marker positions in div bool marker_visible[MARKER_COUNT]; @@ -20,57 +23,53 @@ struct DsoSettingsScopeHorizontal { bool samplerateSet = false; ///< The samplerate was set by the user, not the timebase }; -//////////////////////////////////////////////////////////////////////////////// -/// \struct DsoSettingsScopeTrigger settings.h /// \brief Holds the settings for the trigger. struct DsoSettingsScopeTrigger { bool filter = true; ///< Not sure what this is good for... - Dso::TriggerMode mode = Dso::TRIGGERMODE_NORMAL; ///< Automatic, normal or single trigger + Dso::TriggerMode mode = Dso::TriggerMode::NORMAL; ///< Automatic, normal or single trigger double position = 0.0; ///< Horizontal position for pretrigger - Dso::Slope slope = Dso::SLOPE_POSITIVE; ///< Rising or falling edge causes trigger + Dso::Slope slope = Dso::Slope::Positive; ///< Rising or falling edge causes trigger unsigned int source = 0; ///< Channel that is used as trigger source bool special = false; ///< true if the trigger source is not a standard channel }; -//////////////////////////////////////////////////////////////////////////////// -/// \struct DsoSettingsScopeSpectrum settings.h /// \brief Holds the settings for the spectrum analysis. struct DsoSettingsScopeSpectrum { - unsigned channel; - double magnitude = 20.0; ///< The vertical resolution in dB/div - QString name; ///< Name of this channel - double offset = 0.0; ///< Vertical offset in divs - bool used = false; ///< true if the spectrum is turned on + ChannelID channel; + double magnitude = 20.0; ///< The vertical resolution in dB/div + QString name; ///< Name of this channel + double offset = 0.0; ///< Vertical offset in divs + bool used = false; ///< true if the spectrum is turned on }; -//////////////////////////////////////////////////////////////////////////////// -/// \struct DsoSettingsScopeVoltage settings.h /// \brief Holds the settings for the normal voltage graphs. struct DsoSettingsScopeVoltage { - double gain = 1.0; ///< The vertical resolution in V/div - bool inverted = false; ///< true if the channel is inverted (mirrored on cross-axis) - union { ///< Different enums, coupling for real- and mode for math-channels + unsigned gainStepIndex = 6; ///< The vertical resolution in V/div (default = 1.0) + bool inverted = false; ///< true if the channel is inverted (mirrored on cross-axis) + union { ///< Different enums, coupling for real- and mode for math-channels Dso::MathMode math; - Dso::Coupling coupling; + unsigned couplingIndex = 0; int rawValue; }; - QString name; ///< Name of this channel - double offset = 0.0; ///< Vertical offset in divs - double trigger = 0.0; ///< Trigger level in V - bool used = false; ///< true if this channel is enabled + QString name; ///< Name of this channel + double offset = 0.0; ///< Vertical offset in divs + double trigger = 0.0; ///< Trigger level in V + bool used = false; ///< true if this channel is enabled }; -//////////////////////////////////////////////////////////////////////////////// -/// \struct DsoSettingsScope settings.h /// \brief Holds the settings for the oscilloscope. struct DsoSettingsScope { - DsoSettingsScopeHorizontal horizontal; ///< Settings for the horizontal axis - DsoSettingsScopeTrigger trigger; ///< Settings for the trigger - std::vector spectrum; ///< Spectrum analysis settings - std::vector voltage; ///< Settings for the normal graphs - - unsigned int physicalChannels = 0; ///< Number of real channels (No math etc.) + std::vector gainSteps = {1e-2, 2e-2, 5e-2, 1e-1, 2e-1, + 5e-1, 1e0, 2e0, 5e0}; ///< The selectable voltage gain steps in V/div Dso::WindowFunction spectrumWindow = Dso::WindowFunction::HANN; ///< Window function for DFT - double spectrumReference = 0.0; ///< Reference level for spectrum in dBm - double spectrumLimit = -20.0; ///< Minimum magnitude of the spectrum (Avoids peaks) + std::vector spectrum; ///< Spectrum analysis settings + std::vector voltage; ///< Settings for the normal graphs + DsoSettingsScopeHorizontal horizontal; ///< Settings for the horizontal axis + DsoSettingsScopeTrigger trigger; ///< Settings for the trigger + double spectrumReference = 0.0; ///< Reference level for spectrum in dBm + double spectrumLimit = -20.0; ///< Minimum magnitude of the spectrum (Avoids peaks) + + double gain(unsigned channel) const { + return gainSteps[voltage[channel].gainStepIndex]; + } }; diff --git a/openhantek/src/selectdevice/devicelistentry.h b/openhantek/src/selectdevice/devicelistentry.h index 262eeef..a544919 100644 --- a/openhantek/src/selectdevice/devicelistentry.h +++ b/openhantek/src/selectdevice/devicelistentry.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ #pragma once #include diff --git a/openhantek/src/selectdevice/deviceslistmodel.cpp b/openhantek/src/selectdevice/deviceslistmodel.cpp index e93ba01..3ae3438 100644 --- a/openhantek/src/selectdevice/deviceslistmodel.cpp +++ b/openhantek/src/selectdevice/deviceslistmodel.cpp @@ -8,10 +8,10 @@ DevicesListModel::DevicesListModel(FindDevices *findDevices) :findDevices(findDe int DevicesListModel::rowCount(const QModelIndex &) const { - return entries.size(); + return (int)entries.size(); } -int DevicesListModel::columnCount(const QModelIndex &parent) const +int DevicesListModel::columnCount(const QModelIndex &) const { return 2; } @@ -33,21 +33,22 @@ QVariant DevicesListModel::headerData(int section, Qt::Orientation orientation, QVariant DevicesListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); - if (role==Qt::UserRole) return QVariant::fromValue(entries[index.row()].id); - else if (role==Qt::UserRole+1) return QVariant::fromValue(entries[index.row()].canConnect); - else if (role==Qt::UserRole+2) return QVariant::fromValue(entries[index.row()].needFirmware); + const unsigned row = (unsigned)index.row(); + if (role==Qt::UserRole) return QVariant::fromValue(entries[row].id); + else if (role==Qt::UserRole+1) return QVariant::fromValue(entries[row].canConnect); + else if (role==Qt::UserRole+2) return QVariant::fromValue(entries[row].needFirmware); if (role == Qt::DisplayRole) { if (index.column() == 0) { - return entries[index.row()].name; + return entries[row].name; } else if (index.column() == 1) { - return entries[index.row()].getStatus(); + return entries[row].getStatus(); } } if (role == Qt::BackgroundRole) { - if (entries[index.row()].canConnect) return QColor(Qt::darkGreen).lighter(); - else if (entries[index.row()].needFirmware) return QColor(Qt::yellow).lighter(); + if (entries[row].canConnect) return QColor(Qt::darkGreen).lighter(); + else if (entries[row].needFirmware) return QColor(Qt::yellow).lighter(); } return QVariant(); @@ -59,7 +60,7 @@ void DevicesListModel::updateDeviceList() entries.clear(); endResetModel(); const FindDevices::DeviceList* devices = findDevices->getDevices(); - beginInsertRows(QModelIndex(),0,devices->size()); + beginInsertRows(QModelIndex(),0,(int)devices->size()); for (auto &i : *devices) { DeviceListEntry entry; entry.name= QString::fromStdString(i.second->getModel()->name); diff --git a/openhantek/src/selectdevice/deviceslistmodel.h b/openhantek/src/selectdevice/deviceslistmodel.h index 73fbcfe..764512d 100644 --- a/openhantek/src/selectdevice/deviceslistmodel.h +++ b/openhantek/src/selectdevice/deviceslistmodel.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ #pragma once #include diff --git a/openhantek/src/selectdevice/newdevicemodelfromexisting.cpp b/openhantek/src/selectdevice/newdevicemodelfromexisting.cpp new file mode 100644 index 0000000..76f1e47 --- /dev/null +++ b/openhantek/src/selectdevice/newdevicemodelfromexisting.cpp @@ -0,0 +1,78 @@ +#include "newdevicemodelfromexisting.h" + +#include "dsomodel.h" +#include "models.h" +#include "rawdeviceslistmodel.h" + +#include +#include +#include +#include + +NewDeviceModelFromExisting::NewDeviceModelFromExisting(QWidget *parent) : + QDialog(parent), + ui(new Ui::NewDeviceModelFromExisting) +{ + ui->setupUi(this); + connect(ui->checkBox, &QCheckBox::stateChanged,[this](int state) { + ui->stackedWidget->setCurrentIndex(state==Qt::Checked ? 0: 1); + }); + ui->checkBox->setCheckState(Qt::Checked); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + + QStringList supportedModelsList; + for (const DSOModel* model: supportedModels) { + supportedModelsList.append(QString::fromStdString(model->name)); + } + + QStringListModel* model = new QStringListModel(this); + model->setStringList(supportedModelsList); + ui->cmbTemplateModel->setModel(model); + + RawDevicesListModel* deviceListModel = new RawDevicesListModel(context, this); + ui->cmbUSBdevices->setModel(deviceListModel); + deviceListModel->updateDeviceList(); + + connect(ui->btnRefresh, &QPushButton::clicked, [this,deviceListModel] { + deviceListModel->updateDeviceList(); + }); + + connect(ui->cmbUSBdevices, static_cast(&QComboBox::currentIndexChanged), [this](int index) { + if (index == -1) { + ui->stackedWidget->setCurrentIndex(2); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->checkBox->setEnabled(false); + return; + } + if (ui->cmbUSBdevices->currentData(RawDevicesListModel::AccessRole).toBool()) { + ui->checkBox->setEnabled(true); + ui->modelname->setText(ui->cmbUSBdevices->currentData(RawDevicesListModel::DeviceNameRole).toString()); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ui->modelname->text().size()); + ui->stackedWidget->setCurrentIndex(ui->checkBox->isChecked() ? 0: 1); + } else { + ui->checkBox->setEnabled(false); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->stackedWidget->setCurrentIndex(3); + } + }); + + if (deviceListModel->rowCount(QModelIndex())) { + ui->cmbUSBdevices->setCurrentIndex(0); + } +} + +void NewDeviceModelFromExisting::setUSBcontext(libusb_context *context) +{ + this->context = context; +} + +RawDeviceListEntry *NewDeviceModelFromExisting::getSelectedEntry() +{ + return (RawDeviceListEntry*) ui->cmbUSBdevices->currentData(RawDevicesListModel::EntryPointerRole).value(); +} + +void NewDeviceModelFromExisting::accept() +{ + QMessageBox::information(this,tr("Sorry"),tr("This is not yet implemented!")); + QDialog::accept(); +} diff --git a/openhantek/src/selectdevice/newdevicemodelfromexisting.h b/openhantek/src/selectdevice/newdevicemodelfromexisting.h new file mode 100644 index 0000000..1ab128d --- /dev/null +++ b/openhantek/src/selectdevice/newdevicemodelfromexisting.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +#pragma once + +#include +#include +#include "ui_newdevicemodelfromexisting.h" +#include "rawdevicelistentry.h" + +namespace Ui { +class NewDeviceModelFromExisting; +} + +struct libusb_context; + +class NewDeviceModelFromExisting : public QDialog +{ + Q_OBJECT + +public: + explicit NewDeviceModelFromExisting(QWidget *parent = 0); + void setUSBcontext(libusb_context* context); + RawDeviceListEntry* getSelectedEntry(); +private: + std::unique_ptr ui; + libusb_context* context = nullptr; + + // QDialog interface +public slots: + virtual void accept() override; +}; diff --git a/openhantek/src/selectdevice/newdevicemodelfromexisting.ui b/openhantek/src/selectdevice/newdevicemodelfromexisting.ui new file mode 100644 index 0000000..eb90c6e --- /dev/null +++ b/openhantek/src/selectdevice/newdevicemodelfromexisting.ui @@ -0,0 +1,274 @@ + + + NewDeviceModelFromExisting + + + + 0 + 0 + 442 + 437 + + + + New device from template + + + + + + Select USB device + + + + QLayout::SetMinimumSize + + + + + + + + Refresh + + + + + + + This is usually indicated by a light (red flashing) + + + This is usually indicated by a light (red flashing) + + + Firmware is uploaded already* + + + + + + + + + + 0 + + + 1 + + + + + + + + 0 + 0 + + + + Template selection + + + + + + + 0 + 0 + + + + Select the existing model that should be used as template for your device. You may need to restart OpenHantek and try different models until it works for you. + + + true + + + + + + + + + + Please enter a model name + + + + + + + + + + + + + + Firmware files + + + + + + Please select the firmware files in hex format, extracted from the windows driver for example. You need to open this dialog again after the firmware has been uploaded. + + + true + + + + + + + QLayout::SetMinimumSize + + + + + Firmware + + + + + + + Loader + + + + + + + + + + + + + + 0 + 0 + + + + ... + + + false + + + + + + + + 0 + 0 + + + + ... + + + + + + + + + + + + + + + + No USB devices found or your operating system prohibited enumerating devices. + + + true + + + + + + + + + + + No access granted for the selected USB device. Your operating system may prohibit access. On Windows you might need to install a generic driver first. On Linux you need to install an udev rule to grant access to your currently logged in user. + + + true + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + NewDeviceModelFromExisting + accept() + + + 227 + 324 + + + 157 + 274 + + + + + buttonBox + rejected() + NewDeviceModelFromExisting + reject() + + + 260 + 337 + + + 286 + 274 + + + + + diff --git a/openhantek/src/selectdevice/rawdevicelistentry.h b/openhantek/src/selectdevice/rawdevicelistentry.h new file mode 100644 index 0000000..46c8a31 --- /dev/null +++ b/openhantek/src/selectdevice/rawdevicelistentry.h @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +#pragma once + +#include +#include "usb/usbdevice.h" +#include "dsomodel.h" +/** + * Represents an entry in the {@link DevicesListModel}. + */ +struct RawDeviceListEntry { + long productId; + long vendorId; + bool access; + DSOModel* baseModel=nullptr; + QString devicename; + QString deviceinfo; +}; diff --git a/openhantek/src/selectdevice/rawdeviceslistmodel.cpp b/openhantek/src/selectdevice/rawdeviceslistmodel.cpp new file mode 100644 index 0000000..8b30aa0 --- /dev/null +++ b/openhantek/src/selectdevice/rawdeviceslistmodel.cpp @@ -0,0 +1,80 @@ +#include "rawdeviceslistmodel.h" +#include "usb/finddevices.h" +#include "usb/uploadFirmware.h" +#include "dsomodel.h" +#include + +RawDevicesListModel::RawDevicesListModel(libusb_context *context, QObject *parent) : QAbstractTableModel(parent), context(context) {} + +int RawDevicesListModel::rowCount(const QModelIndex &) const +{ + return (int)entries.size(); +} + +int RawDevicesListModel::columnCount(const QModelIndex &) const +{ + return 1; +} + +QVariant RawDevicesListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) return QVariant(); + const unsigned row = (unsigned)index.row(); + if (role==ProductIDRole) return QVariant::fromValue(entries[row].productId); + else if (role==VendorIDRole) return QVariant::fromValue(entries[row].vendorId); + else if (role==AccessRole) return QVariant::fromValue(entries[row].access); + else if (role==DeviceNameRole) return QVariant::fromValue(entries[row].devicename); + else if (role==EntryPointerRole) return QVariant::fromValue((void*)&entries[row]); + else if (role==Qt::DisplayRole) return QVariant::fromValue(entries[row].deviceinfo); + + return QVariant(); +} + +QString readUSBdescriptor(libusb_device_handle *handle, uint8_t index) { + unsigned char string[255]; + int ret = libusb_get_string_descriptor_ascii(handle, index, string, sizeof(string)); + if (ret > 0) + return QString::fromLatin1((char*)string, ret).trimmed(); + else + return QString(); +} + +void RawDevicesListModel::updateDeviceList() +{ + beginResetModel(); + entries.clear(); + endResetModel(); + + libusb_device **deviceList; + ssize_t deviceCount = libusb_get_device_list(context, &deviceList); + beginInsertRows(QModelIndex(),0,(int)deviceCount); + + for (ssize_t deviceIterator = 0; deviceIterator < deviceCount; ++deviceIterator) { + libusb_device *device = deviceList[deviceIterator]; + RawDeviceListEntry entry; + // Get device descriptor + struct libusb_device_descriptor descriptor; + libusb_get_device_descriptor(device, &descriptor); + + entry.productId = descriptor.idProduct; + entry.vendorId = descriptor.idVendor; + libusb_device_handle *handle = NULL; + int ret = libusb_open(device, &handle); + if (ret != LIBUSB_SUCCESS) { + entry.access = false; + entry.deviceinfo = tr("%1:%2 - No access").arg(entry.vendorId,0,16).arg(entry.productId,0,16); + } else { + entry.access = true; + entry.devicename = readUSBdescriptor(handle, descriptor.iProduct); + entry.deviceinfo = tr("%1:%2 (%3 - %4)").arg(entry.vendorId,0,16).arg(entry.productId,0,16) + .arg(entry.devicename).arg(readUSBdescriptor(handle, descriptor.iManufacturer)); + libusb_close(handle); + } + + entries.push_back(entry); + } + + libusb_free_device_list(deviceList, true); + + endInsertRows(); +} diff --git a/openhantek/src/selectdevice/rawdeviceslistmodel.h b/openhantek/src/selectdevice/rawdeviceslistmodel.h new file mode 100644 index 0000000..b2ccd3b --- /dev/null +++ b/openhantek/src/selectdevice/rawdeviceslistmodel.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0+ +#pragma once + +#include +#include "rawdevicelistentry.h" +#include "usb/usbdevice.h" + +/** + * Provides a Model for the Qt Model/View concept. The {@see FindDevices} is required + * to update the list of available devices. + */ +class RawDevicesListModel: public QAbstractTableModel { +public: + RawDevicesListModel(libusb_context *context, QObject *parent = 0); + // QAbstractItemModel interface + virtual int rowCount(const QModelIndex &parent) const override; + virtual int columnCount(const QModelIndex &parent) const override; + virtual QVariant data(const QModelIndex &index, int role) const override; + void updateDeviceList(); + + enum Roles { + ProductIDRole = Qt::UserRole+0, + VendorIDRole = Qt::UserRole+1, + AccessRole = Qt::UserRole+2, + DeviceNameRole = Qt::UserRole+3, + EntryPointerRole = Qt::UserRole+4 + }; +private: + std::vector entries; + libusb_context *context; +}; diff --git a/openhantek/src/selectdevice/selectdevice.cpp b/openhantek/src/selectdevice/selectdevice.cpp deleted file mode 100644 index 7d0288f..0000000 --- a/openhantek/src/selectdevice/selectdevice.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include - -#include "utils/printutils.h" -#include "selectdevice.h" -#include "usb/uploadFirmware.h" -#include "usb/finddevices.h" -#include "dsomodel.h" -#include -#include -#include -#include -#include - -#include "devicelistentry.h" -#include "deviceslistmodel.h" - -SelectDevice::SelectDevice() { - btn = new QPushButton(this); - w = new QTableView(this); - label = new QLabel(); - label->setWordWrap(true); - move(QApplication::desktop()->screen()->rect().center() - w->rect().center()); - setWindowTitle(tr("Select device")); - setLayout(new QVBoxLayout()); - layout()->addWidget(w); - layout()->addWidget(label); - layout()->addWidget(btn); - qRegisterMetaType(); - connect(btn, &QPushButton::clicked, [this]() { - if (w->currentIndex().isValid()) { - selectedDevice = w->currentIndex().data(Qt::UserRole).value(); - } - QCoreApplication::instance()->quit(); - }); -} - -std::unique_ptr SelectDevice::showSelectDeviceModal(libusb_context *&context) -{ - - std::unique_ptr findDevices = std::unique_ptr(new FindDevices(context)); - std::unique_ptr model = std::unique_ptr(new DevicesListModel(findDevices.get())); - w->setModel(model.get()); - w->verticalHeader()->hide(); - w->horizontalHeader()->hide(); - w->setSelectionBehavior(QAbstractItemView::SelectRows); - // w->setColumnWidth(1,60); - w->horizontalHeader()->setStretchLastSection(true); - connect(w->selectionModel(), &QItemSelectionModel::currentChanged, this, &SelectDevice::currentChanged); - - QTimer timer; - timer.setInterval(1000); - connect(&timer, &QTimer::timeout, [this, &model, &findDevices]() { - if (findDevices->updateDeviceList()) - model->updateDeviceList(); - if (model->rowCount(QModelIndex())) { - w->setVisible(true); - label->setVisible(false); - currentChanged(w->currentIndex(),QModelIndex()); - } else { - QString generalMessage = tr("

OpenHantek did not find any compatible devices.

" - "

" - "Don't forget to switch your device into oscilloscope mode if it has multiple modes.

" - ); -#if defined(Q_OS_WIN) - generalMessage = generalMessage.arg("Please make sure you have installed the windows usb driver correctly"); -#elif defined(Q_OS_LINUX) - QFile file("/lib/udev/rules.d/60-hantek.rules"); - if (!file.exists()) { - generalMessage += tr("

Please make sure you have copied the udev rules file to %1 for correct USB access permissions.

").arg(file.fileName()); - } -#else -#endif - generalMessage += tr("

Visit the build and run instruction " - "website for help.

"); - makeErrorDialog(generalMessage); - } - if (!w->currentIndex().isValid()) { - currentChanged(QModelIndex(),QModelIndex()); - } - }); - timer.start(); - QCoreApplication::sendEvent(&timer, new QTimerEvent(timer.timerId())); // immediate timer event - - show(); - QCoreApplication::instance()->exec(); - timer.stop(); - close(); - - return findDevices->takeDevice(selectedDevice); -} - -void SelectDevice::showLibUSBFailedDialogModel(int error) -{ - makeErrorDialog(tr("Can't initalize USB: %1").arg(libUsbErrorString(error))); - show(); - QCoreApplication::instance()->exec(); - close(); -} - -void SelectDevice::makeErrorDialog(const QString &message) -{ - w->setVisible(false); - label->setText(message); - label->setVisible(true); -} - -void SelectDevice::currentChanged(const QModelIndex ¤t, const QModelIndex &) -{ - if (!current.isValid()) { - btn->setText(tr("Quit application")); - btn->setEnabled(true); - return; - } - if (current.data(Qt::UserRole+1).toBool()) { - btn->setText(tr("Use device %1").arg(current.sibling(current.row(),0).data(Qt::DisplayRole).toString())); - btn->setEnabled(true); - } else { - btn->setEnabled(false); - if (current.data(Qt::UserRole+2).toBool()) { - btn->setText(tr("Upload in progress...")); - } else { - btn->setText(tr("Connection failed!")); - } - } -} diff --git a/openhantek/src/selectdevice/selectsupporteddevice.cpp b/openhantek/src/selectdevice/selectsupporteddevice.cpp new file mode 100644 index 0000000..19e5a10 --- /dev/null +++ b/openhantek/src/selectdevice/selectsupporteddevice.cpp @@ -0,0 +1,121 @@ +#include "selectsupporteddevice.h" + +#include +#include +#include +#include + +#include "utils/printutils.h" +#include "usb/uploadFirmware.h" +#include "usb/finddevices.h" +#include "dsomodel.h" +#include "devicelistentry.h" +#include "deviceslistmodel.h" +#include "newdevicemodelfromexisting.h" +#include "models.h" + +SelectSupportedDevice::SelectSupportedDevice(QWidget *parent) : + QDialog(parent), + ui(new Ui::SelectSupportedDevice) +{ + ui->setupUi(this); + newDeviceFromExistingDialog = new NewDeviceModelFromExisting(this); + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + qRegisterMetaType(); + connect(ui->buttonBox, &QDialogButtonBox::accepted, [this]() { + if (ui->cmbDevices->currentIndex()!=-1) { + selectedDevice = ui->cmbDevices->currentData(Qt::UserRole).value(); + } + QCoreApplication::instance()->quit(); + }); + connect(ui->buttonBox, &QDialogButtonBox::helpRequested, [this]() { + QDesktopServices::openUrl(QUrl("https://github.com/OpenHantek/openhantek#openhantek--")); + }); + connect(ui->btnAddDevice, &QPushButton::clicked, [this]() { + newDeviceFromExistingDialog->setModal(true); + newDeviceFromExistingDialog->show(); + }); +} + +std::unique_ptr SelectSupportedDevice::showSelectDeviceModal(libusb_context *context) +{ + newDeviceFromExistingDialog->setUSBcontext(context); + std::unique_ptr findDevices = std::unique_ptr(new FindDevices(context)); + std::unique_ptr model = std::unique_ptr(new DevicesListModel(findDevices.get())); + ui->cmbDevices->setModel(model.get()); + connect(ui->cmbDevices, static_cast(&QComboBox::currentIndexChanged), [this](int index) { + if (index == -1) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + return; + } + if (ui->cmbDevices->currentData(Qt::UserRole+1).toBool()) { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + ui->labelReadyState->setText(tr("Device ready to use")); + } else { + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + if (ui->cmbDevices->currentData(Qt::UserRole+2).toBool()) { + ui->labelReadyState->setText(tr("Upload in progress...")); + } else { + ui->labelReadyState->setText(tr("Connection failed!")); + } + } + }); + + QString messageNoDevices = tr("

OpenHantek did not find any compatible devices.

" + "

" + "Don't forget to switch your device into oscilloscope mode if it has multiple modes.

" + ); + #if defined(Q_OS_WIN) + messageNoDevices += tr("

Please make sure you have installed the windows usb driver correctly

"); + #elif defined(Q_OS_LINUX) + QFile file("/lib/udev/rules.d/60-hantek.rules"); + if (!file.exists()) { + messageNoDevices += tr("

Please make sure you have copied the udev rules file to %1 for correct USB access permissions.

").arg(file.fileName()); + } + #else + #endif + messageNoDevices += tr("

Visit the build and run instruction " + "website for help.

"); + + updateSupportedDevices(); + + QTimer timer; + timer.setInterval(1000); + connect(&timer, &QTimer::timeout, [this, &model, &findDevices, &messageNoDevices]() { + if (findDevices->updateDeviceList()) + model->updateDeviceList(); + if (model->rowCount(QModelIndex())) { + ui->cmbDevices->setCurrentIndex(0); + } else { + ui->labelReadyState->setText(messageNoDevices); + } + }); + timer.start(); + QCoreApplication::sendEvent(&timer, new QTimerEvent(timer.timerId())); // immediate timer event + + show(); + QCoreApplication::instance()->exec(); + timer.stop(); + close(); + + return findDevices->takeDevice(selectedDevice); +} + +void SelectSupportedDevice::showLibUSBFailedDialogModel(int error) +{ + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); + ui->btnAddDevice->setEnabled(false); + ui->labelReadyState->setText(tr("Can't initalize USB: %1").arg(libUsbErrorString(error))); + show(); + QCoreApplication::instance()->exec(); + close(); +} + +void SelectSupportedDevice::updateSupportedDevices() +{ + QString devices; + for (const DSOModel* model: supportedModels) { + devices.append(QString::fromStdString(model->name)).append(" "); + } + ui->labelSupportedDevices->setText(devices); +} diff --git a/openhantek/src/selectdevice/selectdevice.h b/openhantek/src/selectdevice/selectsupporteddevice.h index 84acb50..eb24869 100644 --- a/openhantek/src/selectdevice/selectdevice.h +++ b/openhantek/src/selectdevice/selectsupporteddevice.h @@ -1,35 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0+ #pragma once -#include -#include -#include -#include +#include "ui_selectsupporteddevice.h" + #include -#include + #include #include "usb/usbdevice.h" struct libusb_context; +class NewDeviceModelFromExisting; /** - * Offers the user a selection dialog. If you call any of the -Modal methods, + * Offers the user a device selection dialog. If you call any of the -Modal methods, * the method will block and show a dialog for selection or for a usb error * message. The method returns as soon as the user closes the dialog. * - * An example to get a device: + * An example to get a user selected device: * std::unique_ptr device = SelectDevice().showSelectDeviceModal(context); */ -class SelectDevice: public QDialog { +class SelectSupportedDevice : public QDialog +{ + Q_OBJECT + public: - SelectDevice(); - std::unique_ptr showSelectDeviceModal(libusb_context *&context); + explicit SelectSupportedDevice(QWidget *parent = 0); + std::unique_ptr showSelectDeviceModal(libusb_context *context); void showLibUSBFailedDialogModel(int error); private: - void makeErrorDialog(const QString& message); void updateDeviceList(); - void currentChanged(const QModelIndex ¤t, const QModelIndex &previous); - QTableView *w; - QLabel *label; - QPushButton *btn; + void updateSupportedDevices(); + std::unique_ptr ui; UniqueUSBid selectedDevice = 0; + NewDeviceModelFromExisting* newDeviceFromExistingDialog; }; diff --git a/openhantek/src/selectdevice/selectsupporteddevice.ui b/openhantek/src/selectdevice/selectsupporteddevice.ui new file mode 100644 index 0000000..ae48514 --- /dev/null +++ b/openhantek/src/selectdevice/selectsupporteddevice.ui @@ -0,0 +1,160 @@ + + + SelectSupportedDevice + + + + 0 + 0 + 381 + 266 + + + + Select device + + + + + + QTabWidget::Rounded + + + 0 + + + + Supported device + + + + + + + 0 + 0 + + + + Devices: + + + + + + + ... + + + true + + + + + + + + + + ... + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Try unsupported + + + + + + <html><head/><body><p>Your device might not directly be supported by OpenHantek. But it might be compatible to one of the existing devices. Help us to identify those devices and report back on our <a href="https://github.com/OpenHantek/openhantek/issues"><span style=" text-decoration: underline; color:#0000ff;">issue tracker</span></a>.</p></body></html> + + + Qt::AutoText + + + true + + + true + + + + + + + Add new device from template + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SelectSupportedDevice + accept() + + + 257 + 302 + + + 157 + 274 + + + + + buttonBox + rejected() + SelectSupportedDevice + reject() + + + 312 + 302 + + + 286 + 274 + + + + + diff --git a/openhantek/src/settings.cpp b/openhantek/src/settings.cpp index 21c8c81..0eff064 100644 --- a/openhantek/src/settings.cpp +++ b/openhantek/src/settings.cpp @@ -1,25 +1,4 @@ -//////////////////////////////////////////////////////////////////////////////// -// -// OpenHantek -// settings.cpp -// -// Copyright (C) 2010, 2011 Oliver Haag -// oliver.haag@gmail.com -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU General Public License as published by the Free -// Software Foundation, either version 3 of the License, or (at your option) -// any later version. -// -// This program is distributed in the hope that it will be useful, but WITHOUT -// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for -// more details. -// -// You should have received a copy of the GNU General Public License along with -// this program. If not, see . -// -//////////////////////////////////////////////////////////////////////////////// +// SPDX-License-Identifier: GPL-2.0+ #include #include @@ -32,8 +11,26 @@ /// \brief Set the number of channels. /// \param channels The new channel count, that will be applied to lists. -DsoSettings::DsoSettings(unsigned int channels) { - scope.physicalChannels = channels; +DsoSettings::DsoSettings(const Dso::ControlSettings* deviceSettings, const Dso::ControlSpecification* deviceSpecification) + : deviceSettings(deviceSettings), deviceSpecification(deviceSpecification) { + + // Add new channels to the list + while (scope.spectrum.size() < deviceSpecification->channels) { + // Spectrum + DsoSettingsScopeSpectrum newSpectrum; + newSpectrum.name = QApplication::tr("SP%1").arg(scope.spectrum.size()+1); + scope.spectrum.push_back(newSpectrum); + + // Voltage + DsoSettingsScopeVoltage newVoltage; + newVoltage.name = QApplication::tr("CH%1").arg(scope.voltage.size()+1); + scope.voltage.push_back(newVoltage); + + view.screen.voltage.push_back(QColor::fromHsv((int)(scope.spectrum.size()-1) * 60, 0xff, 0xff)); + view.screen.spectrum.push_back(view.screen.voltage.back().lighter()); + view.print.voltage.push_back(view.screen.voltage.back().darker(120)); + view.print.spectrum.push_back(view.screen.voltage.back().darker()); + } DsoSettingsScopeSpectrum newSpectrum; newSpectrum.name = QApplication::tr("SPM"); @@ -49,24 +46,6 @@ DsoSettings::DsoSettings(unsigned int channels) { view.print.voltage.push_back(view.screen.voltage.back()); view.print.spectrum.push_back(view.print.voltage.back().darker()); - // Add new channels to the list - while (scope.spectrum.size() <= channels) { - // Spectrum - DsoSettingsScopeSpectrum newSpectrum; - newSpectrum.name = QApplication::tr("SP%1").arg(scope.spectrum.size()); - scope.spectrum.insert(scope.spectrum.end()-1, newSpectrum); - - // Voltage - DsoSettingsScopeVoltage newVoltage; - newVoltage.coupling = Dso::COUPLING_DC; - newVoltage.name = QApplication::tr("CH%1").arg(scope.voltage.size()); - scope.voltage.insert(scope.voltage.end()-1, newVoltage); - - view.screen.voltage.insert(view.screen.voltage.end()-1, QColor::fromHsv((int)(view.screen.voltage.size()-1) * 60, 0xff, 0xff)); - view.screen.spectrum.insert(view.screen.spectrum.end()-1, view.screen.voltage.back().lighter()); - view.print.voltage.insert(view.print.voltage.end()-1, view.screen.voltage.back().darker(120)); - view.print.spectrum.insert(view.print.spectrum.end()-1, view.screen.voltage.back().darker()); - } load(); } @@ -110,14 +89,14 @@ void DsoSettings::load() { // Trigger store->beginGroup("trigger"); if (store->contains("filter")) scope.trigger.filter = store->value("filter").toBool(); - if (store->contains("mode")) scope.trigger.mode = (Dso::TriggerMode)store->value("mode").toInt(); + if (store->contains("mode")) scope.trigger.mode = (Dso::TriggerMode)store->value("mode").toUInt(); if (store->contains("position")) scope.trigger.position = store->value("position").toDouble(); - if (store->contains("slope")) scope.trigger.slope = (Dso::Slope)store->value("slope").toInt(); - if (store->contains("source")) scope.trigger.source = store->value("source").toInt(); + if (store->contains("slope")) scope.trigger.slope = (Dso::Slope)store->value("slope").toUInt(); + if (store->contains("source")) scope.trigger.source = store->value("source").toUInt(); if (store->contains("special")) scope.trigger.special = store->value("special").toInt(); store->endGroup(); // Spectrum - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) { + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) { store->beginGroup(QString("spectrum%1").arg(channel)); if (store->contains("magnitude")) scope.spectrum[channel].magnitude = store->value("magnitude").toDouble(); @@ -126,9 +105,10 @@ void DsoSettings::load() { store->endGroup(); } // Vertical axis - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) { store->beginGroup(QString("vertical%1").arg(channel)); - if (store->contains("gain")) scope.voltage[channel].gain = store->value("gain").toDouble(); + if (store->contains("gainStepIndex")) scope.voltage[channel].gainStepIndex = store->value("gainStepIndex").toUInt(); + if (store->contains("couplingIndex")) scope.voltage[channel].couplingIndex = store->value("couplingIndex").toUInt(); if (store->contains("inverted")) scope.voltage[channel].inverted = store->value("inverted").toBool(); if (store->contains("misc")) scope.voltage[channel].rawValue = store->value("misc").toInt(); if (store->contains("offset")) scope.voltage[channel].offset = store->value("offset").toDouble(); @@ -162,12 +142,12 @@ void DsoSettings::load() { if (store->contains("border")) colors->border = store->value("border").value(); if (store->contains("grid")) colors->grid = store->value("grid").value(); if (store->contains("markers")) colors->markers = store->value("markers").value(); - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) { + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) { QString key = QString("spectrum%1").arg(channel); if (store->contains(key)) colors->spectrum[channel] = store->value(key).value(); } if (store->contains("text")) colors->text = store->value("text").value(); - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) { QString key = QString("voltage%1").arg(channel); if (store->contains(key)) colors->voltage[channel] = store->value(key).value(); } @@ -211,14 +191,14 @@ void DsoSettings::save() { // Trigger store->beginGroup("trigger"); store->setValue("filter", scope.trigger.filter); - store->setValue("mode", scope.trigger.mode); + store->setValue("mode", (unsigned)scope.trigger.mode); store->setValue("position", scope.trigger.position); - store->setValue("slope", scope.trigger.slope); + store->setValue("slope", (unsigned)scope.trigger.slope); store->setValue("source", scope.trigger.source); store->setValue("special", scope.trigger.special); store->endGroup(); // Spectrum - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) { + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) { store->beginGroup(QString("spectrum%1").arg(channel)); store->setValue("magnitude", scope.spectrum[channel].magnitude); store->setValue("offset", scope.spectrum[channel].offset); @@ -226,9 +206,10 @@ void DsoSettings::save() { store->endGroup(); } // Vertical axis - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) { + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) { store->beginGroup(QString("vertical%1").arg(channel)); - store->setValue("gain", scope.voltage[channel].gain); + store->setValue("gainStepIndex", scope.voltage[channel].gainStepIndex); + store->setValue("couplingIndex", scope.voltage[channel].couplingIndex); store->setValue("inverted", scope.voltage[channel].inverted); store->setValue("misc", scope.voltage[channel].rawValue); store->setValue("offset", scope.voltage[channel].offset); @@ -261,10 +242,10 @@ void DsoSettings::save() { store->setValue("border", colors->border.name(QColor::HexArgb)); store->setValue("grid", colors->grid.name(QColor::HexArgb)); store->setValue("markers", colors->markers.name(QColor::HexArgb)); - for (unsigned channel = 0; channel < scope.spectrum.size(); ++channel) + for (ChannelID channel = 0; channel < scope.spectrum.size(); ++channel) store->setValue(QString("spectrum%1").arg(channel), colors->spectrum[channel].name(QColor::HexArgb)); store->setValue("text", colors->text.name(QColor::HexArgb)); - for (unsigned channel = 0; channel < scope.voltage.size(); ++channel) + for (ChannelID channel = 0; channel < scope.voltage.size(); ++channel) store->setValue(QString("voltage%1").arg(channel), colors->voltage[channel].name(QColor::HexArgb)); store->endGroup(); } diff --git a/openhantek/src/settings.h b/openhantek/src/settings.h index f78a24d..4e48404 100644 --- a/openhantek/src/settings.h +++ b/openhantek/src/settings.h @@ -9,6 +9,8 @@ #include "scopesettings.h" #include "viewsettings.h" +#include "hantekdso/controlspecification.h" +#include "hantekdso/controlsettings.h" //////////////////////////////////////////////////////////////////////////////// /// \struct DsoSettingsOptions @@ -23,13 +25,21 @@ struct DsoSettingsOptions { /// \brief Holds the settings of the program. class DsoSettings { public: - explicit DsoSettings(unsigned int channels); + explicit DsoSettings(const Dso::ControlSettings* deviceSettings, const Dso::ControlSpecification* deviceSpecification); bool setFilename(const QString &filename); DsoSettingsOptions options; ///< General options of the program DsoSettingsScope scope; ///< All oscilloscope related settings DsoSettingsView view; ///< All view related settings + // Read only access to device settings and device specification + const Dso::ControlSettings* deviceSettings; + const Dso::ControlSpecification* deviceSpecification; + + Dso::Coupling coupling(ChannelID channel) { + return deviceSpecification->couplings[scope.voltage[channel].couplingIndex]; + } + QByteArray mainWindowGeometry; ///< Geometry of the main window QByteArray mainWindowState; ///< State of docking windows and toolbars diff --git a/openhantek/src/usb/ezusb.cpp b/openhantek/src/usb/ezusb.cpp index fa42e04..1d8c641 100644 --- a/openhantek/src/usb/ezusb.cpp +++ b/openhantek/src/usb/ezusb.cpp @@ -333,104 +333,6 @@ static int parse_ihex(FILE *image, void *context, bool (*is_external)(uint32_t a } /* - * Parse a binary image file and write it as is to the target. - * Applies to Cypress BIX images for RAM or Cypress IIC images - * for EEPROM. - * - * image - the BIX image file - * context - for use by poke() - * is_external - if non-null, used to check which segments go into - * external memory (writable only by software loader) - * poke - called with each memory segment; errors indicated - * by returning negative values. - * - * Caller is responsible for halting CPU as needed, such as when - * overwriting a second stage loader. - */ -static int parse_bin(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len), - int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) { - unsigned char data[4096]; - uint32_t data_addr = 0; - size_t data_len = 0; - int rc; - bool external = false; - - for (;;) { - data_len = fread(data, 1, 4096, image); - if (data_len == 0) break; - if (is_external) external = is_external(data_addr, data_len); - rc = poke(context, data_addr, external, data, data_len); - if (rc < 0) return -1; - data_addr += (uint32_t)data_len; - } - return feof(image) ? 0 : -1; -} - -/* - * Parse a Cypress IIC image file and invoke the poke() function on the - * various segments for writing to RAM - * - * image - the IIC image file - * context - for use by poke() - * is_external - if non-null, used to check which segments go into - * external memory (writable only by software loader) - * poke - called with each memory segment; errors indicated - * by returning negative values. - * - * Caller is responsible for halting CPU as needed, such as when - * overwriting a second stage loader. - */ -static int parse_iic(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len), - int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, size_t len)) { - unsigned char data[4096]; - uint32_t data_addr = 0; - size_t data_len = 0, read_len; - uint8_t block_header[4]; - int rc; - bool external = false; - long file_size, initial_pos; - - initial_pos = ftell(image); - if (initial_pos < 0) return -1; - - if (fseek(image, 0L, SEEK_END) != 0) return -1; - file_size = ftell(image); - if (fseek(image, initial_pos, SEEK_SET) != 0) return -1; - for (;;) { - /* Ignore the trailing reset IIC data (5 bytes) */ - if (ftell(image) >= (file_size - 5)) break; - if (fread(&block_header, 1, sizeof(block_header), image) != 4) { - logerror("unable to read IIC block header\n"); - return -1; - } - data_len = (block_header[0] << 8) + block_header[1]; - data_addr = (block_header[2] << 8) + block_header[3]; - if (data_len > sizeof(data)) { - /* If this is ever reported as an error, switch to using malloc/realloc */ - logerror("IIC data block too small - please report this error to " - "libusb.info\n"); - return -1; - } - read_len = fread(data, 1, data_len, image); - if (read_len != data_len) { - logerror("read error\n"); - return -1; - } - if (is_external) external = is_external(data_addr, data_len); - rc = poke(context, data_addr, external, data, data_len); - if (rc < 0) return -1; - } - return 0; -} - -/* the parse call will be selected according to the image type */ -static int (*parse[IMG_TYPE_MAX])(FILE *image, void *context, bool (*is_external)(uint32_t addr, size_t len), - int (*poke)(void *context, uint32_t addr, bool external, const unsigned char *data, - size_t len)) = {parse_ihex, parse_iic, parse_bin}; - -/*****************************************************************************/ - -/* * For writing to RAM using a first (hardware) or second (software) * stage loader and 0xA0 or 0xA3 vendor requests */ @@ -641,13 +543,12 @@ exit: * memory is written, expecting a second stage loader to have already * been loaded. Then file is re-parsed and on-chip memory is written. */ -int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage) { +int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int stage) { FILE *image; uint32_t cpucs_addr; bool (*is_external)(uint32_t off, size_t len); struct ram_poke_context ctx; int status; - uint8_t iic_header[8] = {0}; int ret = 0; if (fx_type == FX_TYPE_FX3) return fx3_load_ram(device, path); @@ -659,16 +560,6 @@ int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, } else if (verbose > 1) logerror("open firmware image %s for RAM upload\n", path); - if (img_type == IMG_TYPE_IIC) { - if ((fread(iic_header, 1, sizeof(iic_header), image) != sizeof(iic_header)) || - (((fx_type == FX_TYPE_FX2LP) || (fx_type == FX_TYPE_FX2)) && (iic_header[0] != 0xC2)) || - ((fx_type == FX_TYPE_AN21) && (iic_header[0] != 0xB2)) || - ((fx_type == FX_TYPE_FX1) && (iic_header[0] != 0xB6))) { - logerror("IIC image does not contain executable code - cannot load to RAM.\n"); - ret = -1; - goto exit; - } - } /* EZ-USB original/FX and FX2 devices differ, apart from the 8051 core */ switch (fx_type) { @@ -707,7 +598,7 @@ int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, /* scan the image, first (maybe only) time */ ctx.device = device; ctx.total = ctx.count = 0; - status = parse[img_type](image, &ctx, is_external, ram_poke); + status = parse_ihex(image, &ctx, is_external, ram_poke); if (status < 0) { logerror("unable to upload %s\n", path); ret = status; diff --git a/openhantek/src/usb/ezusb.h b/openhantek/src/usb/ezusb.h index c954cd2..de46005 100644 --- a/openhantek/src/usb/ezusb.h +++ b/openhantek/src/usb/ezusb.h @@ -23,51 +23,9 @@ #include struct libusb_device_handle; - -#define FX_TYPE_UNDEFINED -1 -#define FX_TYPE_AN21 0 /* Original AnchorChips parts */ -#define FX_TYPE_FX1 1 /* Updated Cypress versions */ #define FX_TYPE_FX2 2 /* USB 2.0 versions */ #define FX_TYPE_FX2LP 3 /* Updated FX2 */ #define FX_TYPE_FX3 4 /* USB 3.0 versions */ -#define FX_TYPE_MAX 5 -#define FX_TYPE_NAMES \ - { "an21", "fx", "fx2", "fx2lp", "fx3" } - -#define IMG_TYPE_UNDEFINED -1 -#define IMG_TYPE_HEX 0 /* Intel HEX */ -#define IMG_TYPE_IIC 1 /* Cypress 8051 IIC */ -#define IMG_TYPE_BIX 2 /* Cypress 8051 BIX */ -#define IMG_TYPE_IMG 3 /* Cypress IMG format */ -#define IMG_TYPE_MAX 4 -#define IMG_TYPE_NAMES \ - { "Intel HEX", "Cypress 8051 IIC", "Cypress 8051 BIX", "Cypress IMG format" } - -/* - * Automatically identified devices (VID, PID, type, designation). - */ -typedef struct { - uint16_t vid; - uint16_t pid; - int type; - const char *designation; -} fx_known_device; - -#define FX_KNOWN_DEVICES \ - { \ - {0x0547, 0x2122, FX_TYPE_AN21, "Cypress EZ-USB (2122S)"}, \ - {0x0547, 0x2125, FX_TYPE_AN21, "Cypress EZ-USB (2121S/2125S)"}, \ - {0x0547, 0x2126, FX_TYPE_AN21, "Cypress EZ-USB (2126S)"}, \ - {0x0547, 0x2131, FX_TYPE_AN21, "Cypress EZ-USB (2131Q/2131S/2135S)"}, \ - {0x0547, 0x2136, FX_TYPE_AN21, "Cypress EZ-USB (2136S)"}, \ - {0x0547, 0x2225, FX_TYPE_AN21, "Cypress EZ-USB (2225)"}, \ - {0x0547, 0x2226, FX_TYPE_AN21, "Cypress EZ-USB (2226)"}, \ - {0x0547, 0x2235, FX_TYPE_AN21, "Cypress EZ-USB (2235)"}, \ - {0x0547, 0x2236, FX_TYPE_AN21, "Cypress EZ-USB (2236)"}, \ - {0x04b4, 0x6473, FX_TYPE_FX1, "Cypress EZ-USB FX1"}, \ - {0x04b4, 0x8613, FX_TYPE_FX2LP, "Cypress EZ-USB FX2LP (68013A/68014A/68015A/68016A)"}, \ - {0x04b4, 0x00f3, FX_TYPE_FX3, "Cypress FX3"}, \ - } /* * This function uploads the firmware from the given file into RAM. @@ -77,20 +35,7 @@ typedef struct { * * The target processor is reset at the end of this upload. */ -extern int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int img_type, int stage); - -/* - * This function uploads the firmware from the given file into EEPROM. - * This uses the right CPUCS address to terminate the EEPROM load with - * a reset command where FX parts behave differently than FX2 ones. - * The configuration byte is as provided here (zero for an21xx parts) - * and the EEPROM type is set so that the microcontroller will boot - * from it. - * - * The caller must have preloaded a second stage loader that knows - * how to respond to the EEPROM write request. - */ -extern int ezusb_load_eeprom(libusb_device_handle *device, const char *path, int fx_type, int img_type, int config); +extern int ezusb_load_ram(libusb_device_handle *device, const char *path, int fx_type, int stage); /* Verbosity level (default 1). Can be increased or decreased with options v/q */ diff --git a/openhantek/src/usb/uploadFirmware.cpp b/openhantek/src/usb/uploadFirmware.cpp index 564f0d7..0e3fc02 100644 --- a/openhantek/src/usb/uploadFirmware.cpp +++ b/openhantek/src/usb/uploadFirmware.cpp @@ -49,7 +49,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { } // Write loader - status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 0); + status = ezusb_load_ram(handle, temp_loader_path->fileName().toUtf8().constData(), FX_TYPE_FX2, 0); if (status != LIBUSB_SUCCESS) { errorMessage = TR("Writing the loader firmware failed: %1").arg(libusb_error_name(status)); @@ -59,7 +59,7 @@ bool UploadFirmware::startUpload(USBDevice *device) { } // Write firmware - status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, IMG_TYPE_HEX, 1); + status = ezusb_load_ram(handle, temp_firmware_path->fileName().toUtf8().constData(), FX_TYPE_FX2, 1); if (status != LIBUSB_SUCCESS) { errorMessage = TR("Writing the main firmware failed: %1").arg(libusb_error_name(status)); diff --git a/openhantek/src/usb/usbdevice.cpp b/openhantek/src/usb/usbdevice.cpp index f0d8a61..78cd76c 100644 --- a/openhantek/src/usb/usbdevice.cpp +++ b/openhantek/src/usb/usbdevice.cpp @@ -177,7 +177,7 @@ int USBDevice::bulkCommand(const DataArray *command, int attempts if (!allowBulkTransfer) return LIBUSB_SUCCESS; // Send BeginCommand control command - int errorCode = this->controlWrite(CONTROL_BEGINCOMMAND, beginCommandControl.data(), + int errorCode = this->controlWrite((uint8_t)Hantek::ControlCode::CONTROL_BEGINCOMMAND, beginCommandControl.data(), beginCommandControl.getSize()); if (errorCode < 0) return errorCode; @@ -242,10 +242,10 @@ int USBDevice::controlTransfer(unsigned char type, unsigned char request, unsign /// \param index The index field of the packet. /// \param attempts The number of attempts, that are done on timeouts. /// \return Number of sent bytes on success, libusb error code on error. -int USBDevice::controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value, int index, +int USBDevice::controlWrite(uint8_t request, unsigned char *data, unsigned int length, int value, int index, int attempts) { if (!this->handle) return LIBUSB_ERROR_NO_DEVICE; - + // std::cout << "control" << (int)request << " l:"<controlTransfer(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT, request, data, length, value, index, attempts); } @@ -272,7 +272,7 @@ int USBDevice::getConnectionSpeed() { int errorCode; ControlGetSpeed response; - errorCode = this->controlRead(CONTROL_GETSPEED, response.data(), response.getSize()); + errorCode = this->controlRead((uint8_t)Hantek::ControlCode::CONTROL_GETSPEED, response.data(), response.getSize()); if (errorCode < 0) return errorCode; return response.getSpeed(); diff --git a/openhantek/src/usb/usbdevice.h b/openhantek/src/usb/usbdevice.h index b4c73b7..97aa4d4 100644 --- a/openhantek/src/usb/usbdevice.h +++ b/openhantek/src/usb/usbdevice.h @@ -57,7 +57,7 @@ class USBDevice : public QObject { int controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts = HANTEK_ATTEMPTS); - int controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, + int controlWrite(uint8_t request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS); int controlRead(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS); diff --git a/openhantek/src/utils/dsoStrings.cpp b/openhantek/src/utils/dsoStrings.cpp index 135211a..59c2c0b 100644 --- a/openhantek/src/utils/dsoStrings.cpp +++ b/openhantek/src/utils/dsoStrings.cpp @@ -31,13 +31,12 @@ namespace Dso { /// \return The string that should be used in labels etc., empty when invalid. QString channelModeString(ChannelMode mode) { switch (mode) { - case CHANNELMODE_VOLTAGE: + case ChannelMode::Voltage: return QApplication::tr("Voltage"); - case CHANNELMODE_SPECTRUM: + case ChannelMode::Spectrum: return QApplication::tr("Spectrum"); - default: - return QString(); } + return QString(); } /// \brief Return string representation of the given graph format. @@ -45,13 +44,12 @@ QString channelModeString(ChannelMode mode) { /// \return The string that should be used in labels etc. QString graphFormatString(GraphFormat format) { switch (format) { - case GRAPHFORMAT_TY: + case GraphFormat::TY: return QApplication::tr("T - Y"); - case GRAPHFORMAT_XY: + case GraphFormat::XY: return QApplication::tr("X - Y"); - default: - return QString(); } + return QString(); } /// \brief Return string representation of the given channel coupling. @@ -59,15 +57,14 @@ QString graphFormatString(GraphFormat format) { /// \return The string that should be used in labels etc. QString couplingString(Coupling coupling) { switch (coupling) { - case COUPLING_AC: + case Coupling::AC: return QApplication::tr("AC"); - case COUPLING_DC: + case Coupling::DC: return QApplication::tr("DC"); - case COUPLING_GND: + case Coupling::GND: return QApplication::tr("GND"); - default: - return QString(); } + return QString(); } /// \brief Return string representation of the given math mode. @@ -81,9 +78,8 @@ QString mathModeString(MathMode mode) { return QApplication::tr("CH1 - CH2"); case MathMode::SUB_CH1_FROM_CH2: return QApplication::tr("CH2 - CH1"); - default: - return QString(); } + return QString(); } /// \brief Return string representation of the given trigger mode. @@ -91,17 +87,16 @@ QString mathModeString(MathMode mode) { /// \return The string that should be used in labels etc. QString triggerModeString(TriggerMode mode) { switch (mode) { - case TRIGGERMODE_AUTO: + case TriggerMode::AUTO: return QApplication::tr("Auto"); - case TRIGGERMODE_NORMAL: + case TriggerMode::NORMAL: return QApplication::tr("Normal"); - case TRIGGERMODE_SINGLE: + case TriggerMode::SINGLE: return QApplication::tr("Single"); - case TRIGGERMODE_SOFTWARE: + case TriggerMode::SOFTWARE: return QApplication::tr("Software"); - default: - return QString(); } + return QString(); } /// \brief Return string representation of the given trigger slope. @@ -109,9 +104,9 @@ QString triggerModeString(TriggerMode mode) { /// \return The string that should be used in labels etc. QString slopeString(Slope slope) { switch (slope) { - case SLOPE_POSITIVE: + case Slope::Positive: return QString::fromUtf8("\u2197"); - case SLOPE_NEGATIVE: + case Slope::Negative: return QString::fromUtf8("\u2198"); default: return QString(); diff --git a/openhantek/src/utils/enumclass.h b/openhantek/src/utils/enumclass.h index de54aee..7ba33a5 100644 --- a/openhantek/src/utils/enumclass.h +++ b/openhantek/src/utils/enumclass.h @@ -2,7 +2,7 @@ #pragma once -template< typename T > +template< typename T, T first, T last > class Enum { public: @@ -34,14 +34,14 @@ public: }; -template< typename T > -typename Enum::Iterator begin( Enum ) +template< typename T, T first, T last > +typename Enum::Iterator begin( Enum ) { - return typename Enum::Iterator( (int)T::First ); + return typename Enum::Iterator( (int)first ); } -template< typename T > -typename Enum::Iterator end( Enum ) +template< typename T, T first, T last > +typename Enum::Iterator end( Enum ) { - return typename Enum::Iterator( ((int)T::Last) + 1 ); + return typename Enum::Iterator( ((int)last) + 1 ); } diff --git a/openhantek/src/viewconstants.h b/openhantek/src/viewconstants.h index 973ec74..d26ee75 100644 --- a/openhantek/src/viewconstants.h +++ b/openhantek/src/viewconstants.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0+ + #pragma once #define DIVS_TIME 10.0f ///< Number of horizontal screen divs diff --git a/openhantek/src/viewsettings.h b/openhantek/src/viewsettings.h index 1a66d14..20e7179 100644 --- a/openhantek/src/viewsettings.h +++ b/openhantek/src/viewsettings.h @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0+ + #pragma once #include @@ -6,16 +8,18 @@ #include #include +#include "hantekdso/enums.h" + //////////////////////////////////////////////////////////////////////////////// /// \struct DsoSettingsColorValues /// \brief Holds the color values for the oscilloscope screen. struct DsoSettingsColorValues { - QColor axes; ///< X- and Y-axis and subdiv lines on them - QColor background; ///< The scope background - QColor border; ///< The border of the scope screen - QColor grid; ///< The color of the grid - QColor markers; ///< The color of the markers - QColor text; ///< The default text color + QColor axes; ///< X- and Y-axis and subdiv lines on them + QColor background; ///< The scope background + QColor border; ///< The border of the scope screen + QColor grid; ///< The color of the grid + QColor markers; ///< The color of the markers + QColor text; ///< The default text color std::vector spectrum; ///< The colors of the spectrum graphs std::vector voltage; ///< The colors of the voltage graphs }; @@ -24,26 +28,22 @@ struct DsoSettingsColorValues { /// \struct DsoSettingsView /// \brief Holds all view settings. struct DsoSettingsView { - DsoSettingsColorValues screen = {QColor(0xff, 0xff, 0xff, 0x7f), - QColor(0x00, 0x00, 0x00, 0xff), - QColor(0xff, 0xff, 0xff, 0xff), - QColor(0xff, 0xff, 0xff, 0x3f), - QColor(0xff, 0xff, 0xff, 0xbf), - QColor(0xff, 0xff, 0xff, 0xff), - std::vector(), - std::vector()}; - DsoSettingsColorValues print = {QColor(0x00, 0x00, 0x00, 0xbf), - QColor(0x00, 0x00, 0x00, 0x00), - QColor(0x00, 0x00, 0x00, 0xff), - QColor(0x00, 0x00, 0x00, 0x7f), - QColor(0x00, 0x00, 0x00, 0xef), - QColor(0x00, 0x00, 0x00, 0xff), - std::vector(), - std::vector()}; + DsoSettingsColorValues screen = {QColor(0xff, 0xff, 0xff, 0x7f), QColor(0x00, 0x00, 0x00, 0xff), + QColor(0xff, 0xff, 0xff, 0xff), QColor(0xff, 0xff, 0xff, 0x3f), + QColor(0xff, 0xff, 0xff, 0xbf), QColor(0xff, 0xff, 0xff, 0xff), + std::vector(), std::vector()}; + DsoSettingsColorValues print = {QColor(0x00, 0x00, 0x00, 0xbf), QColor(0x00, 0x00, 0x00, 0x00), + QColor(0x00, 0x00, 0x00, 0xff), QColor(0x00, 0x00, 0x00, 0x7f), + QColor(0x00, 0x00, 0x00, 0xef), QColor(0x00, 0x00, 0x00, 0xff), + std::vector(), std::vector()}; bool antialiasing = true; ///< Antialiasing for the graphs bool digitalPhosphor = false; ///< true slowly fades out the previous graphs - unsigned digitalPhosphorDepth = 8; ///< Number of channels shown at one time + unsigned digitalPhosphorDepth = 8; ///< Number of channels shown at one time Dso::InterpolationMode interpolation = Dso::INTERPOLATION_LINEAR; ///< Interpolation mode for the graph bool screenColorImages = false; ///< true exports images with screen colors bool zoom = false; ///< true if the magnified scope is enabled + + unsigned digitalPhosphorDraws() const { + return digitalPhosphor ? digitalPhosphorDepth : 1; + } }; diff --git a/openhantek/src/widgets/colorbox.cpp b/openhantek/src/widgets/colorbox.cpp index e75395f..faacf3e 100644 --- a/openhantek/src/widgets/colorbox.cpp +++ b/openhantek/src/widgets/colorbox.cpp @@ -35,7 +35,7 @@ ColorBox::ColorBox(QColor color, QWidget *parent) : QPushButton(parent) { this->setColor(color); - connect(this, SIGNAL(clicked()), this, SLOT(waitForColor())); + connect(this, &QAbstractButton::clicked, this, &ColorBox::waitForColor); } /// \brief Cleans up the widget. diff --git a/openhantek/src/widgets/sispinbox.cpp b/openhantek/src/widgets/sispinbox.cpp index 99e64ef..f1a2da5 100644 --- a/openhantek/src/widgets/sispinbox.cpp +++ b/openhantek/src/widgets/sispinbox.cpp @@ -170,7 +170,7 @@ void SiSpinBox::init() { this->stepId = 0; this->mode = 0; - connect(this, SIGNAL(valueChanged(double)), this, SLOT(resetSteppedTo())); + connect(this, static_cast(&QDoubleSpinBox::valueChanged), this, &SiSpinBox::resetSteppedTo); } /// \brief Resets the ::steppedTo flag after the value has been changed.