From d52c9b8280c05d6b0add84dd2005024eb25db356 Mon Sep 17 00:00:00 2001
From: oliverhaag
Date: Sun, 25 Nov 2012 19:04:55 +0000
Subject: [PATCH] Record length and samplerate can be set
---
openhantek/ChangeLog | 9 +++++++++
openhantek/roadmap.dox | 11 +++++++++--
openhantek/src/dataanalyzer.cpp | 54 +++++++++++++++++++++++++++---------------------------
openhantek/src/dataanalyzer.h | 6 +++---
openhantek/src/dockwindows.cpp | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
openhantek/src/dockwindows.h | 20 ++++++++++++++++++--
openhantek/src/dsocontrol.h | 16 +++++++++++++---
openhantek/src/dsowidget.cpp | 36 ++++++++++++++++++++----------------
openhantek/src/dsowidget.h | 8 ++++----
openhantek/src/glgenerator.cpp | 2 +-
openhantek/src/hantek/control.cpp | 677 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
openhantek/src/hantek/control.h | 33 ++++++++++++++++++++++++++-------
openhantek/src/hantek/device.cpp | 27 ++++++++++++++-------------
openhantek/src/hantek/device.h | 22 ++++++++++------------
openhantek/src/hantek/types.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------
openhantek/src/hantek/types.h | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------
openhantek/src/openhantek.cpp | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------
openhantek/src/openhantek.h | 15 ++++++++++-----
openhantek/src/settings.cpp | 13 ++++++++++++-
openhantek/src/settings.h | 7 ++++---
openhantek/translations/openhantek_de.ts | 334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
21 files changed, 1150 insertions(+), 724 deletions(-)
diff --git a/openhantek/ChangeLog b/openhantek/ChangeLog
index fdc001a..83b741b 100644
--- a/openhantek/ChangeLog
+++ b/openhantek/ChangeLog
@@ -183,3 +183,12 @@
2012-11-21 Oliver Haag
* Bugfix: DSO-2250 detection failed
+
+2012-11-25 Oliver Haag
+* Added samplerate spinbox to horizontal dock
+* Moved record length selection from menu into horizontal dock
+* Large rework to allow setting either samplerate or timebase
+* Calculate the samplerate depending on the set parameter and the record length
+* Added signals to DsoControl to update horizontal dock automatically
+* Reworks in signal connections to make this work properly
+* Bugfix: DSO-2250 used channels wasn't set
diff --git a/openhantek/roadmap.dox b/openhantek/roadmap.dox
index 1ac93ed..cfc180a 100644
--- a/openhantek/roadmap.dox
+++ b/openhantek/roadmap.dox
@@ -17,11 +17,18 @@ Released February 9, 2011
\section sec_0_3 OpenHantek 0.3.0
-Planned Q2/Q3, 2011
+Planned Q1, 2013
%Hantek DSO-2250 support
- USB hotplugging
+ Proper support for different record lengths
+ Arbitrary samplerate support
+
+
+\section sec_0_4 OpenHantek 0.4.0
+
Improved zoom functionality
+ Self alignment routines
+ USB hotplugging
**/
diff --git a/openhantek/src/dataanalyzer.cpp b/openhantek/src/dataanalyzer.cpp
index c510f75..8ded032 100644
--- a/openhantek/src/dataanalyzer.cpp
+++ b/openhantek/src/dataanalyzer.cpp
@@ -139,7 +139,7 @@ void DataAnalyzer::run() {
// Set sampling interval
channelData->samples.voltage.interval = 1.0 / this->waitingDataSamplerate;
- unsigned int size;
+ unsigned long int size;
if(channel < this->settings->scope.physicalChannels) {
size = this->waitingDataSize[channel];
if(size > maxSamples)
@@ -159,7 +159,7 @@ void DataAnalyzer::run() {
if(channel < this->settings->scope.physicalChannels) {
// Copy the buffer of the oscilloscope into the sample buffer
if(channel < (unsigned int) this->waitingData.count())
- for(unsigned int position = 0; position < this->waitingDataSize[channel]; ++position)
+ for(unsigned long int position = 0; position < this->waitingDataSize[channel]; ++position)
channelData->samples.voltage.sample[position] = this->waitingData[channel][position];
}
// Math channel
@@ -176,7 +176,7 @@ void DataAnalyzer::run() {
}
// Calculate values and write them into the sample buffer
- for(unsigned int realPosition = 0; realPosition < this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count; ++realPosition) {
+ for(unsigned long int realPosition = 0; realPosition < this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count; ++realPosition) {
switch(this->settings->scope.voltage[this->settings->scope.physicalChannels].misc) {
case Dso::MATHMODE_1ADD2:
this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample[realPosition] = this->analyzedData[0]->samples.voltage.sample[realPosition] + this->analyzedData[1]->samples.voltage.sample[realPosition];
@@ -223,24 +223,24 @@ void DataAnalyzer::run() {
this->window = (double *) fftw_malloc(sizeof(double) * this->lastRecordLength);
}
- unsigned int windowEnd = this->lastRecordLength - 1;
+ unsigned long int windowEnd = this->lastRecordLength - 1;
this->lastWindow = this->settings->scope.spectrumWindow;
switch(this->settings->scope.spectrumWindow) {
case Dso::WINDOW_HAMMING:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 0.54 - 0.46 * cos(2.0 * M_PI * windowPosition / windowEnd);
break;
case Dso::WINDOW_HANN:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 0.5 * (1.0 - cos(2.0 * M_PI * windowPosition / windowEnd));
break;
case Dso::WINDOW_COSINE:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = sin(M_PI * windowPosition / windowEnd);
break;
case Dso::WINDOW_LANCZOS:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition) {
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition) {
double sincParameter = (2.0 * windowPosition / windowEnd - 1.0) * M_PI;
if(sincParameter == 0)
*(this->window + windowPosition) = 1;
@@ -249,55 +249,55 @@ void DataAnalyzer::run() {
}
break;
case Dso::WINDOW_BARTLETT:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 2.0 / windowEnd * (windowEnd / 2 - abs(windowPosition - windowEnd / 2));
break;
case Dso::WINDOW_TRIANGULAR:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 2.0 / this->lastRecordLength * (this->lastRecordLength / 2 - abs(windowPosition - windowEnd / 2));
break;
case Dso::WINDOW_GAUSS:
{
double sigma = 0.4;
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = exp(-0.5 * pow(((windowPosition - windowEnd / 2) / (sigma * windowEnd / 2)), 2));
}
break;
case Dso::WINDOW_BARTLETTHANN:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 0.62 - 0.48 * abs(windowPosition / windowEnd - 0.5) - 0.38 * cos(2.0 * M_PI * windowPosition / windowEnd);
break;
case Dso::WINDOW_BLACKMAN:
{
double alpha = 0.16;
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = (1 - alpha) / 2 - 0.5 * cos(2.0 * M_PI * windowPosition / windowEnd) + alpha / 2 * cos(4.0 * M_PI * windowPosition / windowEnd);
}
break;
//case WINDOW_KAISER:
// TODO
//double alpha = 3.0;
- //for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ //for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
//*(this->window + windowPosition) = ;
//break;
case Dso::WINDOW_NUTTALL:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 0.355768 - 0.487396 * cos(2 * M_PI * windowPosition / windowEnd) + 0.144232 * cos(4 * M_PI * windowPosition / windowEnd) - 0.012604 * cos(6 * M_PI * windowPosition / windowEnd);
break;
case Dso::WINDOW_BLACKMANHARRIS:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 0.35875 - 0.48829 * cos(2 * M_PI * windowPosition / windowEnd) + 0.14128 * cos(4 * M_PI * windowPosition / windowEnd) - 0.01168 * cos(6 * M_PI * windowPosition / windowEnd);
break;
case Dso::WINDOW_BLACKMANNUTTALL:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 0.3635819 - 0.4891775 * cos(2 * M_PI * windowPosition / windowEnd) + 0.1365995 * cos(4 * M_PI * windowPosition / windowEnd) - 0.0106411 * cos(6 * M_PI * windowPosition / windowEnd);
break;
case Dso::WINDOW_FLATTOP:
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 1.0 - 1.93 * cos(2 * M_PI * windowPosition / windowEnd) + 1.29 * cos(4 * M_PI * windowPosition / windowEnd) - 0.388 * cos(6 * M_PI * windowPosition / windowEnd) + 0.032 * cos(8 * M_PI * windowPosition / windowEnd);
break;
default: // Dso::WINDOW_RECTANGULAR
- for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
+ for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
*(this->window + windowPosition) = 1.0;
}
}
@@ -306,7 +306,7 @@ void DataAnalyzer::run() {
channelData->samples.spectrum.interval = 1.0 / channelData->samples.voltage.interval / channelData->samples.voltage.count;
// Number of real/complex samples
- unsigned int dftLength = channelData->samples.voltage.count / 2;
+ unsigned long int dftLength = channelData->samples.voltage.count / 2;
// Reallocate memory for samples if the sample count has changed
if(channelData->samples.spectrum.count != dftLength) {
@@ -318,7 +318,7 @@ void DataAnalyzer::run() {
// Create sample buffer and apply window
double *windowedValues = new double[channelData->samples.voltage.count];
- for(unsigned int position = 0; position < channelData->samples.voltage.count; ++position)
+ for(unsigned long int position = 0; position < channelData->samples.voltage.count; ++position)
windowedValues[position] = this->window[position] * channelData->samples.voltage.sample[position];
// Do discrete real to half-complex transformation
@@ -332,7 +332,7 @@ void DataAnalyzer::run() {
double *conjugateComplex = windowedValues; // Reuse the windowedValues buffer
// Real values
- unsigned int position;
+ unsigned long int position;
double correctionFactor = 1.0 / dftLength / dftLength;
conjugateComplex[0] = (channelData->samples.spectrum.sample[0] * channelData->samples.spectrum.sample[0]) * correctionFactor;
for(position = 1; position < dftLength; ++position)
@@ -353,7 +353,7 @@ void DataAnalyzer::run() {
double minimalVoltage, maximalVoltage;
minimalVoltage = maximalVoltage = channelData->samples.voltage.sample[0];
- for(unsigned int position = 1; position < channelData->samples.voltage.count; ++position) {
+ for(unsigned long int position = 1; position < channelData->samples.voltage.count; ++position) {
if(channelData->samples.voltage.sample[position] < minimalVoltage)
minimalVoltage = channelData->samples.voltage.sample[position];
else if(channelData->samples.voltage.sample[position] > maximalVoltage)
@@ -365,9 +365,9 @@ void DataAnalyzer::run() {
// Get the frequency from the correlation results
double minimumCorrelation = correlation[0];
double peakCorrelation = 0;
- unsigned int peakPosition = 0;
+ unsigned long int peakPosition = 0;
- for(unsigned int position = 1; position < channelData->samples.voltage.count / 2; ++position) {
+ for(unsigned long int position = 1; position < channelData->samples.voltage.count / 2; ++position) {
if(correlation[position] > peakCorrelation && correlation[position] > minimumCorrelation * 2) {
peakCorrelation = correlation[position];
peakPosition = position;
@@ -388,7 +388,7 @@ void DataAnalyzer::run() {
// Convert values into dB (Relative to the reference level)
double offset = 60 - this->settings->scope.spectrumReference - 20 * log10(dftLength);
double offsetLimit = this->settings->scope.spectrumLimit - this->settings->scope.spectrumReference;
- for(unsigned int position = 0; position < channelData->samples.spectrum.count; ++position) {
+ for(unsigned long int position = 0; position < channelData->samples.spectrum.count; ++position) {
channelData->samples.spectrum.sample[position] = 20 * log10(fabs(channelData->samples.spectrum.sample[position])) + offset;
// Check if this value has to be limited
@@ -417,7 +417,7 @@ void DataAnalyzer::run() {
/// \param size The sizes of the data arrays.
/// \param samplerate The samplerate for all input data.
/// \param mutex The mutex for all input data.
-void DataAnalyzer::analyze(const QList *data, const QList *size, double samplerate, QMutex *mutex) {
+void DataAnalyzer::analyze(const QList *data, const QList *size, double samplerate, QMutex *mutex) {
// Previous analysis still running, drop the new data
if(this->isRunning())
return;
diff --git a/openhantek/src/dataanalyzer.h b/openhantek/src/dataanalyzer.h
index 70eb83d..f7d2f0c 100644
--- a/openhantek/src/dataanalyzer.h
+++ b/openhantek/src/dataanalyzer.h
@@ -95,15 +95,15 @@ class DataAnalyzer : public QThread {
double *window; ///< The array for the dft window factors
QList waitingData; ///< Pointer to input data from device
- QList waitingDataSize; ///< Number of input data samples
+ QList waitingDataSize; ///< Number of input data samples
double waitingDataSamplerate; ///< The samplerate of the input data
QMutex *waitingDataMutex; ///< A mutex for the input data
public slots:
- void analyze(const QList *data, const QList *size, double samplerate, QMutex *mutex);
+ void analyze(const QList *data, const QList *size, double samplerate, QMutex *mutex);
signals:
- void analyzed(unsigned int samples); ///< The data with that much samples has been analyzed
+ void analyzed(unsigned long samples); ///< The data with that much samples has been analyzed
};
#endif
diff --git a/openhantek/src/dockwindows.cpp b/openhantek/src/dockwindows.cpp
index 5fc27ba..7aebe63 100644
--- a/openhantek/src/dockwindows.cpp
+++ b/openhantek/src/dockwindows.cpp
@@ -46,20 +46,29 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
this->settings = settings;
// Initialize elements
+ this->samplerateLabel = new QLabel(tr("Samplerate"));
+ this->samplerateSiSpinBox = new SiSpinBox(Helper::UNIT_SAMPLES);
+ this->samplerateSiSpinBox->setMinimum(1);
+ this->samplerateSiSpinBox->setMaximum(1e8);
+ this->samplerateSiSpinBox->setUnitPostfix("/s");
+
+ QList timebaseSteps;
+ timebaseSteps << 1.0 << 2.0 << 4.0 << 10.0;
+
this->timebaseLabel = new QLabel(tr("Timebase"));
this->timebaseSiSpinBox = new SiSpinBox(Helper::UNIT_SECONDS);
+ this->timebaseSiSpinBox->setSteps(timebaseSteps);
this->timebaseSiSpinBox->setMinimum(1e-9);
this->timebaseSiSpinBox->setMaximum(3.6e3);
- QList frequencybaseSteps;
- frequencybaseSteps << 1.0 << 2.0 << 5.0 << 10.0;
-
this->frequencybaseLabel = new QLabel(tr("Frequencybase"));
this->frequencybaseSiSpinBox = new SiSpinBox(Helper::UNIT_HERTZ);
- this->frequencybaseSiSpinBox->setSteps(frequencybaseSteps);
this->frequencybaseSiSpinBox->setMinimum(1.0);
this->frequencybaseSiSpinBox->setMaximum(100e6);
+ this->recordLengthLabel = new QLabel(tr("Record length"));
+ this->recordLengthComboBox = new QComboBox();
+
this->formatLabel = new QLabel(tr("Format"));
this->formatComboBox = new QComboBox();
for(int format = Dso::GRAPHFORMAT_TY; format < Dso::GRAPHFORMAT_COUNT; ++format)
@@ -68,12 +77,16 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
this->dockLayout = new QGridLayout();
this->dockLayout->setColumnMinimumWidth(0, 64);
this->dockLayout->setColumnStretch(1, 1);
- this->dockLayout->addWidget(this->timebaseLabel, 0, 0);
- this->dockLayout->addWidget(this->timebaseSiSpinBox, 0, 1);
- this->dockLayout->addWidget(this->frequencybaseLabel, 1, 0);
- this->dockLayout->addWidget(this->frequencybaseSiSpinBox, 1, 1);
- this->dockLayout->addWidget(this->formatLabel, 2, 0);
- this->dockLayout->addWidget(this->formatComboBox, 2, 1);
+ this->dockLayout->addWidget(this->samplerateLabel, 0, 0);
+ this->dockLayout->addWidget(this->samplerateSiSpinBox, 0, 1);
+ this->dockLayout->addWidget(this->timebaseLabel, 1, 0);
+ this->dockLayout->addWidget(this->timebaseSiSpinBox, 1, 1);
+ this->dockLayout->addWidget(this->frequencybaseLabel, 2, 0);
+ this->dockLayout->addWidget(this->frequencybaseSiSpinBox, 2, 1);
+ this->dockLayout->addWidget(this->recordLengthLabel, 3, 0);
+ this->dockLayout->addWidget(this->recordLengthComboBox, 3, 1);
+ this->dockLayout->addWidget(this->formatLabel, 4, 0);
+ this->dockLayout->addWidget(this->formatComboBox, 4, 1);
this->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
@@ -82,13 +95,17 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
this->setWidget(this->dockWidget);
// Connect signals and slots
- connect(this->frequencybaseSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(frequencybaseSelected(double)));
+ connect(this->samplerateSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(samplerateSelected(double)));
connect(this->timebaseSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(timebaseSelected(double)));
+ connect(this->frequencybaseSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(frequencybaseSelected(double)));
+ connect(this->recordLengthComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(recordLengthSelected(int)));
connect(this->formatComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(formatSelected(int)));
// Set values
+ this->setSamplerate(this->settings->scope.horizontal.samplerate);
this->setTimebase(this->settings->scope.horizontal.timebase);
this->setFrequencybase(this->settings->scope.horizontal.frequencybase);
+ this->setRecordLength(this->settings->scope.horizontal.recordLength);
this->setFormat(this->settings->scope.horizontal.format);
}
@@ -104,16 +121,40 @@ void HorizontalDock::closeEvent(QCloseEvent *event) {
event->accept();
}
-/// \brief Changes the frequencybase if the new value is supported.
+/// \brief Changes the frequencybase.
/// \param frequencybase The frequencybase in hertz.
void HorizontalDock::setFrequencybase(double frequencybase) {
+ this->suppressSignals = true;
this->frequencybaseSiSpinBox->setValue(frequencybase);
+ this->suppressSignals = false;
}
-/// \brief Changes the timebase if the new value is supported.
+/// \brief Changes the samplerate.
+/// \param samplerate The samplerate in seconds.
+void HorizontalDock::setSamplerate(double samplerate) {
+ this->suppressSignals = true;
+ this->samplerateSiSpinBox->setValue(samplerate);
+ this->suppressSignals = false;
+}
+
+/// \brief Changes the timebase.
/// \param timebase The timebase in seconds.
void HorizontalDock::setTimebase(double timebase) {
+ this->suppressSignals = true;
this->timebaseSiSpinBox->setValue(timebase);
+ this->suppressSignals = false;
+}
+
+/// \brief Changes the record length if the new value is supported.
+/// \param recordLength The record length in samples.
+void HorizontalDock::setRecordLength(unsigned long int recordLength) {
+ int index = this->recordLengthComboBox->findData((uint) recordLength); // QVariant doesn't take unsigned long int, doesn't matter for 32 bit platforms at least
+
+ if(index != -1) {
+ this->suppressSignals = true;
+ this->recordLengthComboBox->setCurrentIndex(index);
+ this->suppressSignals = false;
+ }
}
/// \brief Changes the format if the new value is supported.
@@ -121,32 +162,96 @@ void HorizontalDock::setTimebase(double timebase) {
/// \return Index of format-value, -1 on error.
int HorizontalDock::setFormat(Dso::GraphFormat format) {
if(format >= Dso::GRAPHFORMAT_TY && format <= Dso::GRAPHFORMAT_XY) {
+ this->suppressSignals = true;
this->formatComboBox->setCurrentIndex(format);
+ this->suppressSignals = false;
return format;
}
return -1;
}
-/// \brief Called when the frequencybase combo box changes it's value.
+/// \brief Updates the available record lengths in the combo box.
+/// \param recordLengths The available record lengths for the combo box.
+void HorizontalDock::availableRecordLengthsChanged(const QList &recordLengths) {
+ /// \todo Empty lists should be interpreted as scope supporting continuous record length values.
+ this->recordLengthComboBox->blockSignals(true); // Avoid messing up the settings
+ this->recordLengthComboBox->setUpdatesEnabled(false);
+
+ // Update existing elements to avoid unnecessary index updates
+ int index = 0;
+ for(; index < recordLengths.size(); ++index) {
+ unsigned long int recordLengthItem = recordLengths[index];
+ if(index < this->recordLengthComboBox->count()) {
+ this->recordLengthComboBox->setItemData(index, (unsigned int) recordLengthItem);
+ this->recordLengthComboBox->setItemText(index, recordLengthItem == ULONG_MAX ? tr("Roll") : Helper::valueToString(recordLengthItem, Helper::UNIT_SAMPLES, 3));
+ }
+ else {
+ this->recordLengthComboBox->addItem(recordLengthItem == ULONG_MAX ? tr("Roll") : Helper::valueToString(recordLengthItem, Helper::UNIT_SAMPLES, 3), (uint) recordLengthItem);
+ }
+ }
+ // Remove extra elements
+ for(int extraIndex = this->recordLengthComboBox->count() - 1; extraIndex > index; --extraIndex) {
+ this->recordLengthComboBox->removeItem(extraIndex);
+ }
+
+ this->setRecordLength(this->settings->scope.horizontal.recordLength);
+ this->recordLengthComboBox->setUpdatesEnabled(true);
+ this->recordLengthComboBox->blockSignals(false);
+}
+
+/// \brief Updates the minimum and maximum of the samplerate spin box.
+/// \param minimum The minimum value the spin box should accept.
+/// \param maximum The minimum value the spin box should accept.
+void HorizontalDock::samplerateLimitsChanged(double minimum, double maximum) {
+ this->suppressSignals = true;
+ this->samplerateSiSpinBox->setMinimum(minimum);
+ this->samplerateSiSpinBox->setMaximum(maximum);
+ this->suppressSignals = false;
+}
+
+/// \brief Called when the frequencybase spinbox changes its value.
/// \param frequencybase The frequencybase in hertz.
void HorizontalDock::frequencybaseSelected(double frequencybase) {
this->settings->scope.horizontal.frequencybase = frequencybase;
- emit frequencybaseChanged(frequencybase);
+ if(!this->suppressSignals)
+ emit frequencybaseChanged(frequencybase);
}
-/// \brief Called when the timebase combo box changes it's value.
+/// \brief Called when the samplerate spinbox changes its value.
+/// \param samplerate The samplerate in samples/second.
+void HorizontalDock::samplerateSelected(double samplerate) {
+ this->settings->scope.horizontal.samplerate = samplerate;
+ if(!this->suppressSignals) {
+ this->settings->scope.horizontal.samplerateSet = true;
+ emit samplerateChanged(samplerate);
+ }
+}
+
+/// \brief Called when the timebase spinbox changes its value.
/// \param timebase The timebase in seconds.
void HorizontalDock::timebaseSelected(double timebase) {
this->settings->scope.horizontal.timebase = timebase;
- emit timebaseChanged(timebase);
+ if(!this->suppressSignals) {
+ this->settings->scope.horizontal.samplerateSet = false;
+ emit timebaseChanged(timebase);
+ }
+}
+
+/// \brief Called when the record length combo box changes its value.
+/// \param index The index of the combo box item.
+void HorizontalDock::recordLengthSelected(int index) {
+ this->settings->scope.horizontal.recordLength = this->recordLengthComboBox->itemData(index).toUInt();
+ if(!this->suppressSignals)
+ emit recordLengthChanged(index);
}
-/// \brief Called when the format combo box changes it's value.
+/// \brief Called when the format combo box changes its value.
/// \param index The index of the combo box item.
void HorizontalDock::formatSelected(int index) {
this->settings->scope.horizontal.format = (Dso::GraphFormat) index;
- emit formatChanged(this->settings->scope.horizontal.format);
+ if(!this->suppressSignals)
+ emit formatChanged(this->settings->scope.horizontal.format);
}
diff --git a/openhantek/src/dockwindows.h b/openhantek/src/dockwindows.h
index 5620de2..99ba13b 100644
--- a/openhantek/src/dockwindows.h
+++ b/openhantek/src/dockwindows.h
@@ -54,7 +54,9 @@ class HorizontalDock : public QDockWidget {
~HorizontalDock();
void setFrequencybase(double timebase);
+ void setSamplerate(double samplerate);
void setTimebase(double timebase);
+ void setRecordLength(unsigned long int recordLength);
int setFormat(Dso::GraphFormat format);
protected:
@@ -62,25 +64,39 @@ class HorizontalDock : public QDockWidget {
QGridLayout *dockLayout; ///< The main layout for the dock window
QWidget *dockWidget; ///< The main widget for the dock window
- QLabel *timebaseLabel; ///< The label for the timebase combobox
- QLabel *frequencybaseLabel; ///< The label for the frequencybase combobox
+ QLabel *samplerateLabel; ///< The label for the samplerate spinbox
+ QLabel *timebaseLabel; ///< The label for the timebase spinbox
+ QLabel *frequencybaseLabel; ///< The label for the frequencybase spinbox
+ QLabel *recordLengthLabel; ///< The label for the record length combobox
QLabel *formatLabel; ///< The label for the format combobox
+ SiSpinBox *samplerateSiSpinBox; ///< Selects the samplerate for aquisitions
SiSpinBox *timebaseSiSpinBox; ///< Selects the timebase for voltage graphs
SiSpinBox *frequencybaseSiSpinBox; ///< Selects the frequencybase for spectrum graphs
+ QComboBox *recordLengthComboBox; ///< Selects the record length for aquisitions
QComboBox *formatComboBox; ///< Selects the way the sampled data is interpreted and shown
DsoSettings *settings; ///< The settings provided by the parent class
QStringList formatStrings; ///< Strings for the formats
+
+ bool suppressSignals; ///< Disable changed-signals temporarily
+ public slots:
+ void availableRecordLengthsChanged(const QList &recordLengths);
+ void samplerateLimitsChanged(double minimum, double maximum);
+
protected slots:
void frequencybaseSelected(double frequencybase);
+ void samplerateSelected(double samplerate);
void timebaseSelected(double timebase);
+ void recordLengthSelected(int index);
void formatSelected(int index);
signals:
void frequencybaseChanged(double frequencybase); ///< The frequencybase has been changed
+ void samplerateChanged(double samplerate); ///< The samplerate has been changed
void timebaseChanged(double timebase); ///< The timebase has been changed
+ void recordLengthChanged(unsigned long recordLength); ///< The recordd length has been changed
void formatChanged(Dso::GraphFormat format); ///< The viewing format has been changed
};
diff --git a/openhantek/src/dsocontrol.h b/openhantek/src/dsocontrol.h
index d6ba2b1..13484d5 100644
--- a/openhantek/src/dsocontrol.h
+++ b/openhantek/src/dsocontrol.h
@@ -47,6 +47,9 @@ class DsoControl : public QThread {
DsoControl(QObject *parent = 0);
virtual unsigned int getChannelCount() = 0; ///< Get the number of channels for this oscilloscope
+ virtual QList *getAvailableRecordLengths() = 0; ///< Get available record lengths, empty list for continuous
+ virtual double getMinSamplerate() = 0; ///< The minimum samplerate supported
+ virtual double getMaxSamplerate() = 0; ///< The maximum samplerate supported
const QStringList *getSpecialTriggerSources();
@@ -62,7 +65,13 @@ class DsoControl : public QThread {
void samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger
void samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger
void statusMessage(const QString &message, int timeout); ///< Status message about the oscilloscope
- void samplesAvailable(const QList *data, const QList *size, double samplerate, QMutex *mutex); ///< New sample data is available
+ void samplesAvailable(const QList *data, const QList *size, double samplerate, QMutex *mutex); ///< New sample data is available
+
+ void recordLengthChanged(unsigned long duration); ///< The record length has changed
+ void recordTimeChanged(double duration); ///< The record time duration has changed
+ void samplerateChanged(double samplerate); ///< The samplerate has changed
+ void availableRecordLengthsChanged(const QList &recordLengths); ///< The available record lengths, empty list for continuous
+ void samplerateLimitsChanged(double minimum, double maximum); ///< The minimum or maximum samplerate has changed
public slots:
virtual void connectDevice();
@@ -71,8 +80,9 @@ class DsoControl : public QThread {
virtual void startSampling();
virtual void stopSampling();
- virtual unsigned long int setSamplerate(unsigned long int samplerate) = 0; ///< Set the samplerate that should be met
- virtual unsigned long int setRecordLength(unsigned long int size) = 0; ///< Set the required record length
+ virtual unsigned long int setRecordLength(unsigned long int size) = 0; ///< Set record length id, minimum for continuous
+ virtual double setSamplerate(double samplerate) = 0; ///< Set the samplerate that should be met
+ virtual double setRecordTime(double duration) = 0; ///< Set the record time duration that should be met
virtual int setTriggerMode(Dso::TriggerMode mode) = 0; ///< Set the trigger mode
virtual int setTriggerSource(bool special, unsigned int id) = 0; ///< Set the trigger source
diff --git a/openhantek/src/dsowidget.cpp b/openhantek/src/dsowidget.cpp
index 46d7dcf..7552bb9 100644
--- a/openhantek/src/dsowidget.cpp
+++ b/openhantek/src/dsowidget.cpp
@@ -225,9 +225,10 @@ DsoWidget::DsoWidget(DsoSettings *settings, DataAnalyzer *dataAnalyzer, QWidget
// Apply settings and update measured values
this->updateTriggerDetails();
- this->updateRecordLength(this->settings->scope.horizontal.samples);
- this->updateFrequencybase();
- this->updateTimebase();
+ this->updateRecordLength(this->settings->scope.horizontal.recordLength);
+ this->updateFrequencybase(this->settings->scope.horizontal.frequencybase);
+ this->updateSamplerate(this->settings->scope.horizontal.samplerate);
+ this->updateTimebase(this->settings->scope.horizontal.timebase);
this->updateZoom(this->settings->view.zoom);
// The widget itself
@@ -245,8 +246,8 @@ DsoWidget::DsoWidget(DsoSettings *settings, DataAnalyzer *dataAnalyzer, QWidget
this->connect(this->markerSlider, SIGNAL(valueChanged(int, double)), this->zoomScope, SLOT(updateGL()));
// Connect other signals
- this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned int)), this, SLOT(dataAnalyzed()));
- this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned int)), this, SLOT(updateRecordLength(unsigned int)));
+ this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned long)), this, SLOT(dataAnalyzed()));
+ this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned long)), this, SLOT(updateRecordLength(unsigned long)));
}
/// \brief Stops the oscilloscope thread and the timer.
@@ -283,7 +284,7 @@ void DsoWidget::updateMarkerDetails() {
if(this->settings->view.zoom) {
this->markerInfoLabel->setText(tr("Zoom x%L1").arg(DIVS_TIME / divs, -1, 'g', 3));
this->markerTimebaseLabel->setText(Helper::valueToString(time / DIVS_TIME, Helper::UNIT_SECONDS, 3) + tr("/div"));
- this->markerFrequencybaseLabel->setText(Helper::valueToString(divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME, Helper::UNIT_HERTZ, 3) + tr("/div"));
+ this->markerFrequencybaseLabel->setText(Helper::valueToString(divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME, Helper::UNIT_HERTZ, 4) + tr("/div"));
}
this->markerTimeLabel->setText(Helper::valueToString(time, Helper::UNIT_SECONDS, 4));
this->markerFrequencyLabel->setText(Helper::valueToString(1.0 / time, Helper::UNIT_HERTZ, 4));
@@ -294,7 +295,7 @@ void DsoWidget::updateSpectrumDetails(unsigned int channel) {
this->setMeasurementVisible(channel, this->settings->scope.voltage[channel].used || this->settings->scope.spectrum[channel].used);
if(this->settings->scope.spectrum[channel].used)
- this->measurementMagnitudeLabel[channel]->setText(Helper::valueToString(this->settings->scope.spectrum[channel].magnitude, Helper::UNIT_DECIBEL, 0) + tr("/div"));
+ this->measurementMagnitudeLabel[channel]->setText(Helper::valueToString(this->settings->scope.spectrum[channel].magnitude, Helper::UNIT_DECIBEL, 3) + tr("/div"));
else
this->measurementMagnitudeLabel[channel]->setText(QString());
}
@@ -320,24 +321,27 @@ void DsoWidget::updateVoltageDetails(unsigned int channel) {
this->setMeasurementVisible(channel, this->settings->scope.voltage[channel].used || this->settings->scope.spectrum[channel].used);
if(this->settings->scope.voltage[channel].used)
- this->measurementGainLabel[channel]->setText(Helper::valueToString(this->settings->scope.voltage[channel].gain, Helper::UNIT_VOLTS, 0) + tr("/div"));
+ this->measurementGainLabel[channel]->setText(Helper::valueToString(this->settings->scope.voltage[channel].gain, Helper::UNIT_VOLTS, 3) + tr("/div"));
else
this->measurementGainLabel[channel]->setText(QString());
}
/// \brief Handles frequencybaseChanged signal from the horizontal dock.
-void DsoWidget::updateFrequencybase() {
- this->settingsFrequencybaseLabel->setText(Helper::valueToString(this->settings->scope.horizontal.frequencybase, Helper::UNIT_HERTZ, 0) + tr("/div"));
+/// \param frequencybase The frequencybase used for displaying the trace.
+void DsoWidget::updateFrequencybase(double frequencybase) {
+ this->settingsFrequencybaseLabel->setText(Helper::valueToString(frequencybase, Helper::UNIT_HERTZ, 4) + tr("/div"));
}
/// \brief Updates the samplerate field after changing the samplerate.
-void DsoWidget::updateSamplerate() {
- this->settingsSamplerateLabel->setText(Helper::valueToString(this->settings->scope.horizontal.samplerate, Helper::UNIT_SAMPLES) + tr("/s"));
+/// \param samplerate The samplerate set in the oscilloscope.
+void DsoWidget::updateSamplerate(double samplerate) {
+ this->settingsSamplerateLabel->setText(Helper::valueToString(samplerate, Helper::UNIT_SAMPLES, 4) + tr("/s"));
}
/// \brief Handles timebaseChanged signal from the horizontal dock.
-void DsoWidget::updateTimebase() {
- this->settingsTimebaseLabel->setText(Helper::valueToString(this->settings->scope.horizontal.timebase, Helper::UNIT_SECONDS, 0) + tr("/div"));
+/// \param timebase The timebase used for displaying the trace.
+void DsoWidget::updateTimebase(double timebase) {
+ this->settingsTimebaseLabel->setText(Helper::valueToString(timebase, Helper::UNIT_SECONDS, 4) + tr("/div"));
this->updateMarkerDetails();
}
@@ -425,8 +429,8 @@ void DsoWidget::updateVoltageUsed(unsigned int channel, bool used) {
}
/// \brief Change the record length.
-void DsoWidget::updateRecordLength(unsigned int size) {
- this->settingsRecordLengthLabel->setText(tr("%1 S").arg(size));
+void DsoWidget::updateRecordLength(unsigned long size) {
+ this->settingsRecordLengthLabel->setText(Helper::valueToString(size, Helper::UNIT_SAMPLES, 4));
}
/// \brief Export the oscilloscope screen to a file.
diff --git a/openhantek/src/dsowidget.h b/openhantek/src/dsowidget.h
index 97dfefc..629ee4b 100644
--- a/openhantek/src/dsowidget.h
+++ b/openhantek/src/dsowidget.h
@@ -96,9 +96,9 @@ class DsoWidget : public QWidget {
public slots:
// Horizontal axis
//void horizontalFormatChanged(HorizontalFormat format);
- void updateFrequencybase();
- void updateSamplerate();
- void updateTimebase();
+ void updateFrequencybase(double frequencybase);
+ void updateSamplerate(double samplerate);
+ void updateTimebase(double timebase);
// Trigger
void updateTriggerMode();
@@ -116,7 +116,7 @@ class DsoWidget : public QWidget {
void updateVoltageUsed(unsigned int channel, bool used);
// Menus
- void updateRecordLength(unsigned int size);
+ void updateRecordLength(unsigned long size);
// Export
bool exportAs();
diff --git a/openhantek/src/glgenerator.cpp b/openhantek/src/glgenerator.cpp
index f02af00..d8bb911 100644
--- a/openhantek/src/glgenerator.cpp
+++ b/openhantek/src/glgenerator.cpp
@@ -86,7 +86,7 @@ GlGenerator::GlGenerator(DsoSettings *settings, QObject *parent) : QObject(paren
/// \brief Deletes OpenGL objects.
GlGenerator::~GlGenerator() {
- // todo: Clean up vaChannel
+ /// \todo Clean up vaChannel
}
/// \brief Set the data analyzer whose data will be drawn.
diff --git a/openhantek/src/hantek/control.cpp b/openhantek/src/hantek/control.cpp
index 887cbeb..1d2cd32 100644
--- a/openhantek/src/hantek/control.cpp
+++ b/openhantek/src/hantek/control.cpp
@@ -5,7 +5,7 @@
//
// Copyright (C) 2008, 2009 Oleg Khudyakov
// prcoder@potrebitel.ru
-// Copyright (C) 2010, 2011 Oliver Haag
+// Copyright (C) 2010 - 2012 Oliver Haag
// oliver.haag@gmail.com
//
// This program is free software: you can redistribute it and/or modify it
@@ -24,6 +24,7 @@
////////////////////////////////////////////////////////////////////////////////
+#include
#include
#include
@@ -43,7 +44,7 @@ namespace Hantek {
Control::Control(QObject *parent) : DsoControl(parent) {
// Use DSO-2090 specification as default
this->specification.command.bulk.setRecordLength = (BulkCode) -1;
- this->specification.command.bulk.setFilter = (BulkCode) -1;
+ this->specification.command.bulk.setChannels = (BulkCode) -1;
this->specification.command.bulk.setGain = (BulkCode) -1;
this->specification.command.bulk.setSamplerate = (BulkCode) -1;
this->specification.command.bulk.setTrigger = (BulkCode) -1;
@@ -53,12 +54,12 @@ namespace Hantek {
this->specification.command.values.offsetLimits = (ControlValue) -1;
this->specification.command.values.voltageLimits = (ControlValue) -1;
- this->specification.recordLengths << 0;
-
this->specification.samplerate.single.base = 50e6;
this->specification.samplerate.single.max = 50e6;
+ this->specification.samplerate.single.recordLengths << 0;
this->specification.samplerate.multi.base = 100e6;
this->specification.samplerate.multi.max = 100e6;
+ this->specification.samplerate.multi.recordLengths << 0;
for(unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
for(unsigned int gainId = 0; gainId < 9; ++gainId) {
@@ -69,8 +70,8 @@ namespace Hantek {
// Set settings to default values
this->settings.samplerate.limits = &(this->specification.samplerate.single);
- this->settings.samplerate.downsampling = 1;
- this->settings.samplerate.current = 0.0;
+ this->settings.samplerate.downsampler = 1;
+ this->settings.samplerate.current = 1e8;
this->settings.trigger.position = 0;
this->settings.trigger.point = 0;
this->settings.trigger.mode = Dso::TRIGGERMODE_NORMAL;
@@ -114,6 +115,8 @@ namespace Hantek {
this->samplesSize.append(0);
}
+ this->previousSampleCount = 0;
+
connect(this->device, SIGNAL(disconnected()), this, SLOT(disconnectDevice()));
}
@@ -134,6 +137,25 @@ namespace Hantek {
return HANTEK_CHANNELS;
}
+ /// \brief Get available record lengths for this oscilloscope.
+ /// \return The number of physical channels, empty list for continuous.
+ QList *Control::getAvailableRecordLengths() {
+ return &this->settings.samplerate.limits->recordLengths;
+ }
+
+ /// \brief Get minimum samplerate for this oscilloscope.
+ /// \return The minimum samplerate for the current configuration in S/s.
+ double Control::getMinSamplerate() {
+ return (double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler;
+ }
+
+ /// \brief Get maximum samplerate for this oscilloscope.
+ /// \return The maximum samplerate for the current configuration in S/s.
+ double Control::getMaxSamplerate() {
+ ControlSamplerateLimits *limits = (this->settings.usedChannels <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single;
+ return limits->max;
+ }
+
/// \brief Handles all USB things until the device gets disconnected.
void Control::run() {
int errorCode, cycleCounter = 0, startCycle = 0;
@@ -194,7 +216,7 @@ namespace Hantek {
// Check the current oscilloscope state everytime 25% of the time the buffer should be refilled
// Not more often than every 10 ms though
- int cycleTime = qMax((unsigned long int) (this->specification.recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10lu);
+ int cycleTime = qMax((unsigned long int) (this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10lu);
this->msleep(cycleTime);
if(!this->sampling) {
@@ -237,6 +259,12 @@ namespace Hantek {
break;
case CAPTURE_WAITING:
+ // Sampling hasn't started, update the expected sample count
+ if(this->settings.samplerate.limits == &this->specification.samplerate.multi)
+ this->previousSampleCount = this->specification.samplerate.multi.recordLengths[this->settings.recordLengthId];
+ else
+ this->previousSampleCount = this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] * HANTEK_CHANNELS;
+
if(samplingStarted && lastTriggerMode == this->settings.trigger.mode) {
++cycleCounter;
@@ -338,8 +366,24 @@ namespace Hantek {
return errorCode;
// Save raw data to temporary buffer
- unsigned int dataCount = this->specification.recordLengths[this->settings.recordLengthId] * HANTEK_CHANNELS;
- unsigned int dataLength = dataCount;
+ bool fastRate = this->settings.samplerate.limits == &this->specification.samplerate.multi;
+
+ unsigned long int totalSampleCount = fastRate ? this->specification.samplerate.multi.recordLengths[this->settings.recordLengthId] : this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] * HANTEK_CHANNELS;
+
+ // To make sure no samples will remain in the scope buffer, also check the sample count before the last sampling started
+ if(totalSampleCount < this->previousSampleCount) {
+ unsigned long int currentSampleCount = totalSampleCount;
+ totalSampleCount = this->previousSampleCount;
+ this->previousSampleCount = currentSampleCount; // Using sampleCount as temporary buffer since it was set to totalSampleCount
+ }
+ else {
+ this->previousSampleCount = totalSampleCount;
+ }
+
+ unsigned long int sampleCount = totalSampleCount;
+ if(!fastRate)
+ sampleCount /= HANTEK_CHANNELS;
+ unsigned long int dataLength = totalSampleCount;
if(this->specification.sampleSize > 8)
dataLength *= 2;
@@ -353,18 +397,19 @@ namespace Hantek {
// How much data did we really receive?
dataLength = errorCode;
if(this->specification.sampleSize > 8)
- dataCount = dataLength / 2;
+ totalSampleCount = dataLength / 2;
else
- dataCount = dataLength;
+ totalSampleCount = dataLength;
this->samplesMutex.lock();
// Convert channel data
- if(this->settings.samplerate.limits == &this->specification.samplerate.multi) {
+ if(fastRate) {
// Fast rate mode, one channel is using all buffers
+ sampleCount = totalSampleCount;
int channel = 0;
for(; channel < HANTEK_CHANNELS; ++channel) {
- if(this->settings.voltage[0].used)
+ if(this->settings.voltage[channel].used)
break;
}
@@ -378,34 +423,34 @@ namespace Hantek {
if(channel < HANTEK_CHANNELS) {
// Reallocate memory for samples if the sample count has changed
- if(!this->samples[channel] || this->samplesSize[channel] != dataCount) {
+ if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) {
if(this->samples[channel])
delete this->samples[channel];
- this->samples[channel] = new double[dataCount];
- this->samplesSize[channel] = dataCount;
+ this->samples[channel] = new double[sampleCount];
+ this->samplesSize[channel] = sampleCount;
}
// Convert data from the oscilloscope and write it into the sample buffer
- unsigned int bufferPosition = (this->settings.trigger.point + 1) * 2;
+ unsigned long int bufferPosition = this->settings.trigger.point * 2;
if(this->specification.sampleSize > 8) {
// Additional most significant bits after the normal data
unsigned int extraBitsPosition; // Track the position of the extra bits in the additional byte
unsigned int extraBitsSize = this->specification.sampleSize - 8; // Number of extra bits
unsigned short int extraBitsMask = (0x00ff << extraBitsSize) & 0xff00; // Mask for extra bits extraction
- for(unsigned int realPosition = 0; realPosition < dataCount; ++realPosition, ++bufferPosition) {
- if(bufferPosition >= dataCount)
- bufferPosition %= dataCount;
+ for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, ++bufferPosition) {
+ if(bufferPosition >= sampleCount)
+ bufferPosition %= sampleCount;
extraBitsPosition = bufferPosition % HANTEK_CHANNELS;
- this->samples[channel][realPosition] = ((double) ((unsigned short int) data[bufferPosition] + (((unsigned short int) data[dataCount + bufferPosition - extraBitsPosition] << (8 - (HANTEK_CHANNELS - 1 - extraBitsPosition) * extraBitsSize)) & extraBitsMask)) / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
+ this->samples[channel][realPosition] = ((double) ((unsigned short int) data[bufferPosition] + (((unsigned short int) data[sampleCount + bufferPosition - extraBitsPosition] << (8 - (HANTEK_CHANNELS - 1 - extraBitsPosition) * extraBitsSize)) & extraBitsMask)) / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
}
}
else {
- for(unsigned int realPosition = 0; realPosition < dataCount; ++realPosition, ++bufferPosition) {
- if(bufferPosition >= dataCount)
- bufferPosition %= dataCount;
+ for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, ++bufferPosition) {
+ if(bufferPosition >= sampleCount)
+ bufferPosition %= sampleCount;
this->samples[channel][realPosition] = ((double) data[bufferPosition] / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
}
@@ -414,39 +459,39 @@ namespace Hantek {
}
else {
// Normal mode, channels are using their separate buffers
- unsigned int channelDataCount = dataCount / HANTEK_CHANNELS;
-
+ sampleCount = totalSampleCount / HANTEK_CHANNELS;
for(int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
if(this->settings.voltage[channel].used) {
// Reallocate memory for samples if the sample count has changed
- if(!this->samples[channel] || this->samplesSize[channel] != channelDataCount) {
+ if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) {
if(this->samples[channel])
delete this->samples[channel];
- this->samples[channel] = new double[channelDataCount];
- this->samplesSize[channel] = channelDataCount;
+ this->samples[channel] = new double[sampleCount];
+ this->samplesSize[channel] = sampleCount;
}
// Convert data from the oscilloscope and write it into the sample buffer
- unsigned int bufferPosition = (this->settings.trigger.point + 1) * 2;
+ unsigned long int bufferPosition = this->settings.trigger.point * 2;
if(this->specification.sampleSize > 8) {
// Additional most significant bits after the normal data
unsigned int extraBitsSize = this->specification.sampleSize - 8; // Number of extra bits
unsigned short int extraBitsMask = (0x00ff << extraBitsSize) & 0xff00; // Mask for extra bits extraction
unsigned int extraBitsIndex = 8 - channel * 2; // Bit position offset for extra bits extraction
- for(unsigned int realPosition = 0; realPosition < channelDataCount; ++realPosition, bufferPosition += 2) {
- if(bufferPosition >= dataCount)
- bufferPosition %= dataCount;
+ for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, bufferPosition += HANTEK_CHANNELS) {
+ if(bufferPosition >= totalSampleCount)
+ bufferPosition %= totalSampleCount;
- this->samples[channel][realPosition] = ((double) ((unsigned short int) data[bufferPosition + HANTEK_CHANNELS - 1 - channel] + (((unsigned short int) data[dataCount + bufferPosition] << extraBitsIndex) & extraBitsMask)) / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
+ this->samples[channel][realPosition] = ((double) ((unsigned short int) data[bufferPosition + HANTEK_CHANNELS - 1 - channel] + (((unsigned short int) data[totalSampleCount + bufferPosition] << extraBitsIndex) & extraBitsMask)) / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
}
}
else {
- for(unsigned int realPosition = 0; realPosition < channelDataCount; ++realPosition, bufferPosition += 2) {
- if(bufferPosition >= dataCount)
- bufferPosition %= dataCount;
+ bufferPosition += HANTEK_CHANNELS - 1 - channel;
+ for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, bufferPosition += HANTEK_CHANNELS) {
+ if(bufferPosition >= totalSampleCount)
+ bufferPosition %= totalSampleCount;
- this->samples[channel][realPosition] = ((double) data[bufferPosition + HANTEK_CHANNELS - 1 - channel] / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
+ this->samples[channel][realPosition] = ((double) data[bufferPosition] / this->specification.voltageLimit[channel][this->settings.voltage[channel].gain] - this->settings.voltage[channel].offsetReal) * this->specification.gainSteps[this->settings.voltage[channel].gain];
}
}
}
@@ -466,29 +511,112 @@ namespace Hantek {
return errorCode;
}
- /// \brief Sets the size of the sample buffer without updating dependencies.
- /// \param size The record length that should be met (S).
- /// \return The record length that has been set, 0 on error.
- unsigned long int Control::updateRecordLength(unsigned long int size) {
- // Get the record length supporting the highest samplerate while meeting the requirement
- int bestSizeId = -1;
- for(int sizeId = 0; sizeId < this->specification.recordLengths.count(); ++sizeId) {
- if(this->specification.recordLengths[sizeId] >= size) {
- // We meet the size-requirement, check if we provide the highest possible samplerate
- if(bestSizeId == -1 || this->specification.recordLengths[bestSizeId] < size || this->specification.bufferDividers[sizeId] < this->specification.bufferDividers[bestSizeId])
- bestSizeId = sizeId;
- }
- else {
- // We don't meet the size-requirement, but maybe we're still the one coming closest
- if(bestSizeId == -1 || this->specification.recordLengths[sizeId] > this->specification.recordLengths[bestSizeId])
- bestSizeId = sizeId;
+ /// \brief Calculated the nearest samplerate supported by the oscilloscope.
+ /// \param samplerate The target samplerate, that should be met as good as possible.
+ /// \param fastRate true, if the fast rate mode is enabled.
+ /// \param maximum The target samplerate is the maximum allowed when true, the minimum otherwise.
+ /// \param downsampler Pointer to where the selected downsampling factor should be written.
+ /// \return The nearest samplerate supported, 0.0 on error.
+ double Control::getBestSamplerate(double samplerate, bool fastRate, bool maximum, unsigned long int *downsampler) {
+ // Abort if the input value is invalid
+ if(samplerate <= 0.0)
+ return 0.0;
+
+ double bestSamplerate = 0.0;
+
+ // Get samplerate specifications for this mode and model
+ ControlSamplerateLimits *limits;
+ if(fastRate)
+ limits = &(this->specification.samplerate.multi);
+ else
+ limits = &(this->specification.samplerate.single);
+
+ // Get downsampling factor that would provide the requested rate
+ double bestDownsampler = (double) limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / samplerate;
+ // Base samplerate sufficient, or is the maximum better?
+ if(bestDownsampler < 1.0 && (samplerate <= limits->max / this->specification.bufferDividers[this->settings.recordLengthId] || !maximum)) {
+ bestDownsampler = 0.0;
+ bestSamplerate = limits->max / this->specification.bufferDividers[this->settings.recordLengthId];
+ }
+ else {
+ switch(this->specification.command.bulk.setSamplerate) {
+ case BULK_SETTRIGGERANDSAMPLERATE:
+ // DSO-2090 supports the downsampling factors 1, 2, 4 and 5 using valueFast or all even values above using valueSlow
+ if((maximum && bestDownsampler <= 5.0) || (!maximum && bestDownsampler < 6.0)) {
+ // valueFast is used
+ if(maximum) {
+ // The samplerate shall not be higher, so we round up
+ bestDownsampler = ceil(bestDownsampler);
+ if(bestDownsampler > 2.0) // 3 and 4 not possible with the DSO-2090
+ bestDownsampler = 5.0;
+ }
+ else {
+ // The samplerate shall not be lower, so we round down
+ bestDownsampler = floor(bestDownsampler);
+ if(bestDownsampler > 2.0 && bestDownsampler < 5.0) // 3 and 4 not possible with the DSO-2090
+ bestDownsampler = 2.0;
+ }
+ }
+ else {
+ // valueSlow is used
+ if(maximum) {
+ bestDownsampler = ceil(bestDownsampler / 2.0) * 2.0; // Round up to next even value
+ }
+ else {
+ bestDownsampler = floor(bestDownsampler / 2.0) * 2.0; // Round down to next even value
+ }
+ if(bestDownsampler > 2.0 * 0x10001) // Check for overflow
+ bestDownsampler = 2.0 * 0x10001;
+ }
+ break;
+
+ case BULK_CSETTRIGGERORSAMPLERATE:
+ // DSO-5200 may not supports all downsampling factors, requires testing
+ if(maximum) {
+ bestDownsampler = ceil(bestDownsampler); // Round up to next integer value
+ }
+ else {
+ bestDownsampler = floor(bestDownsampler); // Round down to next integer value
+ }
+ break;
+
+ case BULK_ESETTRIGGERORSAMPLERATE:
+ // DSO-2250 doesn't have a fast value, so it supports all downsampling factors
+ if(maximum) {
+ bestDownsampler = ceil(bestDownsampler); // Round up to next integer value
+ }
+ else {
+ bestDownsampler = floor(bestDownsampler); // Round down to next integer value
+ }
+ break;
+
+ default:
+ return 0.0;
}
+
+ // Limit maximum downsampler value to avoid overflows in the sent commands
+ if(bestDownsampler > limits->maxDownsampler)
+ bestDownsampler = limits->maxDownsampler;
+
+ bestSamplerate = limits->base / bestDownsampler / this->specification.bufferDividers[this->settings.recordLengthId];
}
+ if(downsampler)
+ *downsampler = (unsigned long int) bestDownsampler;
+ return bestSamplerate;
+ }
+
+ /// \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 long int Control::updateRecordLength(unsigned long int index) {
+ if(index >= (unsigned long int) this->settings.samplerate.limits->recordLengths.size())
+ return 0;
+
switch(this->specification.command.bulk.setRecordLength) {
case BULK_SETTRIGGERANDSAMPLERATE:
// SetTriggerAndSamplerate bulk command for record length
- static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setRecordLength(bestSizeId);
+ static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setRecordLength(index);
this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
break;
@@ -498,7 +626,7 @@ namespace Hantek {
// Pointers to needed commands
BulkSetRecordLength2250 *commandSetRecordLength2250 = static_cast(this->command[BULK_DSETBUFFER]);
- commandSetRecordLength2250->setRecordLength(bestSizeId);
+ commandSetRecordLength2250->setRecordLength(index);
}
else {
// SetBuffer5200 bulk command for record length
@@ -506,7 +634,7 @@ namespace Hantek {
commandSetBuffer5200->setUsedPre(DTRIGGERPOSITION_ON);
commandSetBuffer5200->setUsedPost(DTRIGGERPOSITION_ON);
- commandSetBuffer5200->setRecordLength(bestSizeId);
+ commandSetBuffer5200->setRecordLength(index);
}
this->commandPending[BULK_DSETBUFFER] = true;
@@ -517,9 +645,136 @@ namespace Hantek {
return 0;
}
- this->settings.recordLengthId = bestSizeId;
+ this->settings.recordLengthId = index;
+
+ return this->settings.samplerate.limits->recordLengths[index];
+ }
+
+ /// \brief Sets the samplerate based on the parameters calculated by Control::getBestSamplerate.
+ /// \param downsampler The downsampling factor.
+ /// \param fastRate true, if one channel uses all buffers.
+ /// \return The downsampling factor that has been set.
+ unsigned long int Control::updateSamplerate(unsigned long int downsampler, bool fastRate) {
+ // Set the calculated samplerate
+ switch(this->specification.command.bulk.setSamplerate) {
+ case BULK_SETTRIGGERANDSAMPLERATE: {
+ short int downsamplerValue = 0;
+ unsigned char samplerateId = 0;
+ bool downsampling = false;
+
+ if(downsampler <= 5) {
+ // All dividers up to 5 are done using the special samplerate IDs
+ if(downsampler == 0)
+ samplerateId = 1;
+ else if(downsampler <= 2)
+ samplerateId = downsampler;
+ else { // Downsampling factors 3 and 4 are not supported
+ samplerateId = 3;
+ downsampler = 5;
+ downsamplerValue = 0xffff;
+ }
+ }
+ else {
+ // For any dividers above the downsampling factor can be set directly
+ downsampler &= ~0x0001; // Only even values possible
+ downsamplerValue = (short int) (0x10001 - (downsampler >> 1));
+
+ downsampling = true;
+ }
+
+ // Pointers to needed commands
+ BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE]);
+
+ // Store if samplerate ID or downsampling factor is used
+ commandSetTriggerAndSamplerate->setDownsamplingMode(downsampling);
+ // Store samplerate ID
+ commandSetTriggerAndSamplerate->setSamplerateId(samplerateId);
+ // Store downsampling factor
+ commandSetTriggerAndSamplerate->setDownsampler(downsamplerValue);
+ // Set fast rate when used
+ commandSetTriggerAndSamplerate->setFastRate(false /*fastRate*/);
+
+ this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
+
+ break;
+ }
+ case BULK_CSETTRIGGERORSAMPLERATE: {
+ // Split the resulting divider into the values understood by the device
+ // The fast value is kept at 4 (or 3) for slow sample rates
+ long int valueSlow = qMax(((long int) downsampler - 3) / 2, (long int) 0);
+ unsigned char valueFast = downsampler - valueSlow * 2;
+
+ // Pointers to needed commands
+ BulkSetSamplerate5200 *commandSetSamplerate5200 = static_cast(this->command[BULK_CSETTRIGGERORSAMPLERATE]);
+ BulkSetTrigger5200 *commandSetTrigger5200 = static_cast(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
+
+ // Store samplerate fast value
+ commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
+ // Store samplerate slow value (two's complement)
+ commandSetSamplerate5200->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow);
+ // Set fast rate when used
+ commandSetTrigger5200->setFastRate(fastRate);
+
+ this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
+ this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
+
+ break;
+ }
+ case BULK_ESETTRIGGERORSAMPLERATE: {
+ // Pointers to needed commands
+ BulkSetSamplerate2250 *commandSetSamplerate2250 = static_cast(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
+
+ bool downsampling = downsampler >= 1;
+ // Store downsampler state value
+ commandSetSamplerate2250->setDownsampling(downsampling);
+ // Store samplerate value
+ commandSetSamplerate2250->setSamplerate(downsampler > 1 ? 0x10001 - downsampler : 0);
+ // Set fast rate when used
+ commandSetSamplerate2250->setFastRate(fastRate);
+
+ this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
+
+ break;
+ }
+ default:
+ return ULONG_MAX;
+ }
+
+ // Update settings
+ bool fastRateChanged = fastRate != (this->settings.samplerate.limits == &this->specification.samplerate.multi);
+ if(fastRateChanged) {
+ if(fastRate)
+ this->settings.samplerate.limits = &this->specification.samplerate.multi;
+ else
+ this->settings.samplerate.limits = &this->specification.samplerate.single;
+ }
- return this->specification.recordLengths[this->settings.recordLengthId];
+ this->settings.samplerate.downsampler = downsampler;
+ if(downsampler)
+ this->settings.samplerate.current = this->settings.samplerate.limits->base / downsampler;
+ else
+ this->settings.samplerate.current = this->settings.samplerate.limits->max;
+
+ // Update dependencies
+ this->setPretriggerPosition(this->settings.trigger.position);
+
+ // Emit signals for changed settings
+ if(fastRateChanged) {
+ emit availableRecordLengthsChanged(this->settings.samplerate.limits->recordLengths);
+ emit recordLengthChanged(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId]);
+ }
+ emit recordTimeChanged((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current);
+ emit samplerateChanged(this->settings.samplerate.current);
+
+ return downsampler;
+ }
+
+ /// \brief Try to connect to the oscilloscope.
+ void Control::restoreTargets() {
+ if(this->settings.samplerate.target.samplerateSet)
+ this->setSamplerate();
+ else
+ this->setRecordTime();
}
/// \brief Try to connect to the oscilloscope.
@@ -545,7 +800,7 @@ namespace Hantek {
this->command[BULK_SETGAIN] = new BulkSetGain();
// Initialize the command versions to the ones used on the DSO-2090
this->specification.command.bulk.setRecordLength = (BulkCode) -1;
- this->specification.command.bulk.setFilter = (BulkCode) -1;
+ this->specification.command.bulk.setChannels = (BulkCode) -1;
this->specification.command.bulk.setGain = BULK_SETGAIN;
this->specification.command.bulk.setSamplerate = (BulkCode) -1;
this->specification.command.bulk.setTrigger = (BulkCode) -1;
@@ -563,32 +818,30 @@ namespace Hantek {
case MODEL_DSO2090:
// Instantiate additional commands for the DSO-2090
- this->command[BULK_SETFILTER] = new BulkSetFilter();
this->command[BULK_SETTRIGGERANDSAMPLERATE] = new BulkSetTriggerAndSamplerate();
this->specification.command.bulk.setRecordLength = BULK_SETTRIGGERANDSAMPLERATE;
- this->specification.command.bulk.setFilter = BULK_SETFILTER;
+ this->specification.command.bulk.setChannels = BULK_SETTRIGGERANDSAMPLERATE;
this->specification.command.bulk.setSamplerate = BULK_SETTRIGGERANDSAMPLERATE;
this->specification.command.bulk.setTrigger = BULK_SETTRIGGERANDSAMPLERATE;
this->specification.command.bulk.setPretrigger = BULK_SETTRIGGERANDSAMPLERATE;
// Initialize those as pending
- this->commandPending[BULK_SETFILTER] = true;
this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
break;
case MODEL_DSO2250:
// Instantiate additional commands for the DSO-2250
- this->command[BULK_BSETFILTER] = new BulkSetFilter2250();
+ this->command[BULK_BSETCHANNELS] = new BulkSetChannels2250();
this->command[BULK_CSETTRIGGERORSAMPLERATE] = new BulkSetTrigger2250();
this->command[BULK_DSETBUFFER] = new BulkSetRecordLength2250();
this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetSamplerate2250();
this->command[BULK_FSETBUFFER] = new BulkSetBuffer2250();
this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
- this->specification.command.bulk.setFilter = BULK_BSETFILTER;
+ this->specification.command.bulk.setChannels = BULK_BSETCHANNELS;
this->specification.command.bulk.setSamplerate = BULK_ESETTRIGGERORSAMPLERATE;
this->specification.command.bulk.setTrigger = BULK_CSETTRIGGERORSAMPLERATE;
this->specification.command.bulk.setPretrigger = BULK_FSETBUFFER;
- this->commandPending[BULK_BSETFILTER] = true;
+ this->commandPending[BULK_BSETCHANNELS] = true;
this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
this->commandPending[BULK_DSETBUFFER] = true;
this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
@@ -605,6 +858,7 @@ namespace Hantek {
this->command[BULK_DSETBUFFER] = new BulkSetBuffer5200();
this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetTrigger5200();
this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
+ this->specification.command.bulk.setChannels = BULK_ESETTRIGGERORSAMPLERATE;
this->specification.command.bulk.setSamplerate = BULK_CSETTRIGGERORSAMPLERATE;
this->specification.command.bulk.setTrigger = BULK_ESETTRIGGERORSAMPLERATE;
this->specification.command.bulk.setPretrigger = BULK_ESETTRIGGERORSAMPLERATE;
@@ -630,7 +884,8 @@ namespace Hantek {
// Maximum possible samplerate for a single channel and dividers for record lengths
this->specification.bufferDividers.clear();
- this->specification.recordLengths.clear();
+ this->specification.samplerate.single.recordLengths.clear();
+ this->specification.samplerate.multi.recordLengths.clear();
this->specification.gainSteps.clear();
for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
this->specification.voltageLimit[channel].clear();
@@ -640,10 +895,13 @@ namespace Hantek {
case MODEL_DSO5200A:
this->specification.samplerate.single.base = 100e6;
this->specification.samplerate.single.max = 125e6;
+ this->specification.samplerate.single.maxDownsampler = 131072;
+ this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 14336;
this->specification.samplerate.multi.base = 200e6;
this->specification.samplerate.multi.max = 250e6;
+ this->specification.samplerate.multi.maxDownsampler = 131072;
+ this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 28672;
this->specification.bufferDividers << 1000 << 1 << 1;
- this->specification.recordLengths << ULONG_MAX << 10240 << 14336;
this->specification.gainSteps
<< 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0 << 80.0;
/// \todo Use calibration data to get the DSO-5200(A) sample ranges
@@ -658,10 +916,13 @@ namespace Hantek {
case MODEL_DSO2250:
this->specification.samplerate.single.base = 100e6;
this->specification.samplerate.single.max = 100e6;
+ this->specification.samplerate.single.maxDownsampler = 65536;
+ this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 524288;
this->specification.samplerate.multi.base = 200e6;
this->specification.samplerate.multi.max = 250e6;
+ this->specification.samplerate.multi.maxDownsampler = 65536;
+ this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 1048576;
this->specification.bufferDividers << 1000 << 1 << 1;
- this->specification.recordLengths << ULONG_MAX << 10240 << 524288;
this->specification.gainSteps
<< 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0;
for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
@@ -675,10 +936,13 @@ namespace Hantek {
case MODEL_DSO2150:
this->specification.samplerate.single.base = 50e6;
this->specification.samplerate.single.max = 75e6;
+ this->specification.samplerate.single.maxDownsampler = 131072;
+ this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 32768;
this->specification.samplerate.multi.base = 100e6;
this->specification.samplerate.multi.max = 150e6;
+ this->specification.samplerate.multi.maxDownsampler = 131072;
+ this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 65536;
this->specification.bufferDividers << 1000 << 1 << 1;
- this->specification.recordLengths << ULONG_MAX << 10240 << 32768;
this->specification.gainSteps
<< 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0;
for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
@@ -692,10 +956,13 @@ namespace Hantek {
default:
this->specification.samplerate.single.base = 50e6;
this->specification.samplerate.single.max = 50e6;
+ this->specification.samplerate.single.maxDownsampler = 131072;
+ this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 32768;
this->specification.samplerate.multi.base = 100e6;
this->specification.samplerate.multi.max = 100e6;
+ this->specification.samplerate.multi.maxDownsampler = 131072;
+ this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 65536;
this->specification.bufferDividers << 1000 << 1 << 1;
- this->specification.recordLengths << ULONG_MAX << 10240 << 32768;
this->specification.gainSteps
<< 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0;
for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
@@ -706,8 +973,10 @@ namespace Hantek {
this->specification.sampleSize = 8;
break;
}
+ this->settings.recordLengthId = 1;
this->settings.samplerate.limits = &(this->specification.samplerate.single);
- this->settings.samplerate.downsampling = 1;
+ this->settings.samplerate.downsampler = 1;
+ this->previousSampleCount = 0;
// Get channel level data
errorCode = this->device->controlRead(CONTROL_VALUE, (unsigned char *) &(this->specification.offsetLimit), sizeof(this->specification.offsetLimit), (int) VALUE_OFFSETLIMITS);
@@ -721,131 +990,78 @@ namespace Hantek {
}
/// \brief Sets the size of the oscilloscopes sample buffer.
- /// \param size The record length that should be met (S).
+ /// \param index The record length index that should be set.
/// \return The record length that has been set, 0 on error.
- unsigned long int Control::setRecordLength(unsigned long int size) {
- if(!this->device->isConnected())
+ unsigned long int Control::setRecordLength(unsigned long int index) {
+ if(!this->device->isConnected())
return 0;
- this->updateRecordLength(size);
+ if(!this->updateRecordLength(index))
+ return 0;
- this->setSamplerate();
+ this->restoreTargets();
this->setPretriggerPosition(this->settings.trigger.position);
- return this->specification.recordLengths[this->settings.recordLengthId];
+ emit recordLengthChanged(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId]);
+ return this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId];
}
/// \brief Sets the samplerate of the oscilloscope.
- /// \param samplerate The samplerate that should be met (S/s).
- /// \return The samplerate that has been set, 0 on error.
- unsigned long int Control::setSamplerate(unsigned long int samplerate) {
- if(!this->device->isConnected())
- return 0;
+ /// \param samplerate The samplerate that should be met (S/s), 0.0 to restore current samplerate.
+ /// \return The samplerate that has been set, 0.0 on error.
+ double Control::setSamplerate(double samplerate) {
+ if(samplerate == 0.0) {
+ samplerate = this->settings.samplerate.target.samplerate;
+ }
+ else {
+ this->settings.samplerate.target.samplerate = samplerate;
+ this->settings.samplerate.target.samplerateSet = true;
+ }
- // Keep samplerate if no parameter was given
- if(!samplerate)
- samplerate = this->settings.samplerate.current;
- // Abort samplerate calculation if we didn't get a valid value yet
- if(!samplerate)
- return samplerate;
+ // When possible, enable fast rate if it is required to reach the requested samplerate
+ bool fastRate = (this->settings.usedChannels <= 1) && (samplerate > this->specification.samplerate.single.max);
- // Calculate with fast rate first if only one channel is used
- bool fastRate = false;
- this->settings.samplerate.limits = &(this->specification.samplerate.single);
- if(this->settings.usedChannels <= 1) {
- fastRate = true;
- this->settings.samplerate.limits = &(this->specification.samplerate.multi);
+ // What is the nearest, at least as high samplerate the scope can provide?
+ unsigned long int downsampler = 0;
+ double bestSamplerate = getBestSamplerate(samplerate, fastRate, false, &(downsampler));
+
+ // Set the calculated samplerate
+ if(this->updateSamplerate(downsampler, fastRate) == ULONG_MAX)
+ return 0.0;
+ else {
+ return bestSamplerate;
+ }
+ }
+
+ /// \brief Sets the time duration of one aquisition by adapting the samplerate.
+ /// \param duration The record time duration that should be met (s), 0.0 to restore current record time.
+ /// \return The record time duration that has been set, 0.0 on error.
+ double Control::setRecordTime(double duration) {
+ if(duration == 0.0) {
+ duration = this->settings.samplerate.target.duration;
+ }
+ else {
+ this->settings.samplerate.target.duration = duration;
+ this->settings.samplerate.target.samplerateSet = false;
}
- // Get downsampling factor that would provide the requested rate
- this->settings.samplerate.downsampling = this->settings.samplerate.limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / samplerate;
- // A downsampling factor of zero will result in the maximum rate
- if(this->settings.samplerate.downsampling)
- this->settings.samplerate.current = this->settings.samplerate.limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / this->settings.samplerate.downsampling;
- else
- this->settings.samplerate.current = this->settings.samplerate.limits->max / this->specification.bufferDividers[this->settings.recordLengthId];
+ // Calculate the maximum samplerate that would still provide the requested duration
+ double maxSamplerate = (double) this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] / duration;
- // Maybe normal mode would be sufficient or even better than fast rate mode
- if(fastRate) {
- // Don't set the downsampling factor to zero (maximum rate) if we could use fast rate mode anyway
- unsigned long int slowDownsampling = qMax(this->specification.samplerate.single.base / this->specification.bufferDividers[this->settings.recordLengthId] / samplerate, (long unsigned int) 1);
-
- // Use normal mode if we need valueSlow or it would meet the rate at least as exactly as fast rate mode
- if(this->settings.samplerate.downsampling > 4 || (qAbs((double) this->specification.samplerate.single.base / this->specification.bufferDividers[this->settings.recordLengthId] / slowDownsampling - samplerate) <= qAbs((double) this->settings.samplerate.current - samplerate))) {
- fastRate = false;
- this->settings.samplerate.limits = &(this->specification.samplerate.single);
- this->settings.samplerate.downsampling = slowDownsampling;
- this->settings.samplerate.current = this->specification.samplerate.single.base / this->specification.bufferDividers[this->settings.recordLengthId] / this->settings.samplerate.downsampling;
- }
- }
+ // When possible, enable fast rate if the record time can't be set that low to improve resolution
+ bool fastRate = (this->settings.usedChannels <= 1) && (maxSamplerate >= this->specification.samplerate.multi.base);
- switch(this->specification.command.bulk.setSamplerate) {
- case BULK_SETTRIGGERANDSAMPLERATE: {
- // Split the resulting divider into the values understood by the device
- // The fast value is kept at 4 (or 3) for slow sample rates
- long int valueSlow = qMax(((long int) this->settings.samplerate.downsampling - 3) / 2, (long int) 0);
- unsigned char valueFast = this->settings.samplerate.downsampling - valueSlow * 2;
-
- // Pointers to needed commands
- BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE]);
-
- // Store samplerate fast value
- commandSetTriggerAndSamplerate->setSamplerateFast(valueFast);
- // Store samplerate slow value (two's complement)
- commandSetTriggerAndSamplerate->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow);
- // Set fast rate when used
- commandSetTriggerAndSamplerate->setFastRate(fastRate);
-
- this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
-
- break;
- }
- case BULK_CSETTRIGGERORSAMPLERATE: {
- // Split the resulting divider into the values understood by the device
- // The fast value is kept at 4 (or 3) for slow sample rates
- long int valueSlow = qMax(((long int) this->settings.samplerate.downsampling - 3) / 2, (long int) 0);
- unsigned char valueFast = this->settings.samplerate.downsampling - valueSlow * 2;
-
- // Pointers to needed commands
- BulkSetSamplerate5200 *commandSetSamplerate5200 = static_cast(this->command[BULK_CSETTRIGGERORSAMPLERATE]);
- BulkSetTrigger5200 *commandSetTrigger5200 = static_cast(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
-
- // Store samplerate fast value
- commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
- // Store samplerate slow value (two's complement)
- commandSetSamplerate5200->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow);
- // Set fast rate when used
- commandSetTrigger5200->setFastRate(fastRate);
-
- this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
- this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
-
- break;
- }
- case BULK_ESETTRIGGERORSAMPLERATE: {
- // Pointers to needed commands
- BulkSetSamplerate2250 *commandSetSamplerate2250 = static_cast(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
-
- bool downsampling = this->settings.samplerate.downsampling > 1;
- // Store downsampler state value
- commandSetSamplerate2250->setDownsampling(downsampling);
- // Store samplerate value
- commandSetSamplerate2250->setSamplerate(downsampling ? 0x10001 - this->settings.samplerate.downsampling : 0);
- // Set fast rate when used
- commandSetSamplerate2250->setFastRate(fastRate);
-
- this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
-
- break;
- }
- default:
- return 0;
- }
+ // What is the nearest, at most as high samplerate the scope can provide?
+ unsigned long int downsampler = 0;
+ double bestSamplerate = getBestSamplerate(maxSamplerate, fastRate, true, &(downsampler));
- this->updateRecordLength(this->specification.recordLengths[this->settings.recordLengthId]);
- this->setPretriggerPosition(this->settings.trigger.position);
- return this->settings.samplerate.current;
- }
+ // Set the calculated samplerate
+ if(this->updateSamplerate(downsampler, fastRate) == ULONG_MAX)
+ return 0.0;
+ else {
+ return (double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / bestSamplerate;
+ }
+ }
/// \brief Enables/disables filtering of the given channel.
/// \param channel The channel that should be set.
@@ -858,28 +1074,6 @@ namespace Hantek {
if(channel >= HANTEK_CHANNELS)
return Dso::ERROR_PARAMETER;
- // Channel filtering commands
- switch(this->specification.command.bulk.setFilter) {
- case BULK_SETFILTER: {
- // SetFilter bulk command for channel filter (used has to be inverted!)
- BulkSetFilter *commandSetFilter = static_cast(this->command[BULK_SETFILTER]);
- commandSetFilter->setChannel(channel, !used);
- this->commandPending[BULK_SETFILTER] = true;
-
- break;
- }
- case BULK_BSETFILTER: {
- // SetFilter2250 bulk command for channel filter (used has to be inverted!)
- BulkSetFilter2250 *commandSetFilter2250 = static_cast(this->command[BULK_BSETFILTER]);
- commandSetFilter2250->setChannel(channel, !used);
- this->commandPending[BULK_BSETFILTER] = true;
-
- break;
- }
- default:
- return Dso::ERROR_UNSUPPORTED;
- }
-
// Update settings
this->settings.voltage[channel].used = used;
unsigned int channelCount = 0;
@@ -887,35 +1081,58 @@ namespace Hantek {
if(this->settings.voltage[channelCounter].used)
++channelCount;
}
- this->settings.usedChannels = channelCount;
- // Additional UsedChannels field for all models except DSO-2250
- if(this->specification.command.bulk.setTrigger == BULK_SETTRIGGERANDSAMPLERATE || this->specification.command.bulk.setTrigger == BULK_ESETTRIGGERORSAMPLERATE) {
- unsigned char usedChannels = USED_CH1;
-
- if(this->settings.voltage[1].used) {
- if(this->settings.voltage[0].used)
- usedChannels = USED_CH1CH2;
+ // Calculate the UsedChannels field for the command
+ unsigned char usedChannels = USED_CH1;
+
+ if(this->settings.voltage[1].used) {
+ if(this->settings.voltage[0].used) {
+ usedChannels = USED_CH1CH2;
+ }
+ else {
+ // DSO-2250 uses a different value for channel 2
+ if(this->specification.command.bulk.setTrigger == BULK_BSETCHANNELS)
+ usedChannels = BUSED_CH2;
else
usedChannels = USED_CH2;
}
-
- switch(this->specification.command.bulk.setTrigger) {
- case BULK_SETTRIGGERANDSAMPLERATE: {
- // SetTriggerAndSamplerate bulk command for trigger source
- static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setUsedChannels(usedChannels);
- this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
- break;
- }
- case BULK_ESETTRIGGERORSAMPLERATE: {
- // SetTrigger5200s bulk command for trigger source
- static_cast(this->command[BULK_ESETTRIGGERORSAMPLERATE])->setUsedChannels(usedChannels);
- this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
- break;
- }
- default:
- break;
+ }
+
+ switch(this->specification.command.bulk.setTrigger) {
+ case BULK_SETTRIGGERANDSAMPLERATE: {
+ // SetTriggerAndSamplerate bulk command for trigger source
+ static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setUsedChannels(usedChannels);
+ this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
+ break;
+ }
+ case BULK_BSETCHANNELS: {
+ // SetChannels2250 bulk command for active channels
+ static_cast(this->command[BULK_BSETCHANNELS])->setUsedChannels(usedChannels);
+ this->commandPending[BULK_BSETCHANNELS] = true;
+
+ break;
+ }
+ case BULK_ESETTRIGGERORSAMPLERATE: {
+ // SetTrigger5200s bulk command for trigger source
+ static_cast(this->command[BULK_ESETTRIGGERORSAMPLERATE])->setUsedChannels(usedChannels);
+ this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
+ break;
}
+ default:
+ break;
+ }
+
+ // Check if fast rate mode availability changed
+ bool fastRateChanged = (this->settings.usedChannels <= 1) != (channelCount <= 1);
+ this->settings.usedChannels = channelCount;
+
+ if(fastRateChanged) {
+ // Works only if the minimum samplerate for normal mode is lower than for fast rate mode, which is the case for all models
+ ControlSamplerateLimits *limits = (channelCount <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single;
+ emit samplerateLimitsChanged((double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler, limits->max);
+
+ // Samplerate differs for fast rate mode, recalculate it
+ this->restoreTargets();
}
return Dso::ERROR_NONE;
@@ -1166,7 +1383,7 @@ namespace Hantek {
switch(this->specification.command.bulk.setPretrigger) {
case BULK_SETTRIGGERANDSAMPLERATE: {
// Calculate the position value (Start point depending on record length)
- unsigned long int position = 0x7ffff - this->specification.recordLengths[this->settings.recordLengthId] + positionSamples;
+ unsigned long int position = 0x7ffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
// SetTriggerAndSamplerate bulk command for trigger position
static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setTriggerPosition(position);
@@ -1176,7 +1393,7 @@ namespace Hantek {
}
case BULK_FSETBUFFER: {
// Calculate the position values (Inverse, maximum is 0x7ffff)
- unsigned long int positionPre = 0x7fffful - this->specification.recordLengths[this->settings.recordLengthId] + positionSamples;
+ unsigned long int positionPre = 0x7fffful - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
unsigned long int positionPost = 0x7fffful - positionSamples;
// SetBuffer2250 bulk command for trigger position
@@ -1189,7 +1406,7 @@ namespace Hantek {
}
case BULK_ESETTRIGGERORSAMPLERATE: {
// Calculate the position values (Inverse, maximum is 0xffff)
- unsigned short int positionPre = 0xffff - this->specification.recordLengths[this->settings.recordLengthId] + positionSamples;
+ unsigned short int positionPre = 0xffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
unsigned short int positionPost = 0xffff - positionSamples;
// SetBuffer5200 bulk command for trigger position
diff --git a/openhantek/src/hantek/control.h b/openhantek/src/hantek/control.h
index 1ebfddb..268e0d9 100644
--- a/openhantek/src/hantek/control.h
+++ b/openhantek/src/hantek/control.h
@@ -6,7 +6,7 @@
//
// Copyright (C) 2008, 2009 Oleg Khudyakov
// prcoder@potrebitel.ru
-// Copyright (C) 2010, 2011 Oliver Haag
+// Copyright (C) 2010 - 2012 Oliver Haag
// oliver.haag@gmail.com
//
// This program is free software: you can redistribute it and/or modify it
@@ -56,7 +56,7 @@ namespace Hantek {
/// \struct ControlSpecificationCommandsBulk hantek/control.h
/// \brief Stores the bulk command codes used for this device.
struct ControlSpecificationCommandsBulk {
- BulkCode setFilter; ///< Command for setting used channels
+ BulkCode setChannels; ///< Command for setting used channels
BulkCode setSamplerate; ///< Command for samplerate settings
BulkCode setGain; ///< Command for gain settings (Usually in combination with CONTROL_SETRELAYS)
BulkCode setRecordLength; ///< Command for buffer settings
@@ -95,6 +95,8 @@ namespace Hantek {
struct ControlSamplerateLimits {
unsigned long int base; ///< The base for sample rate calculations
unsigned long int max; ///< The maximum sample rate
+ unsigned long int maxDownsampler; ///< The maximum downsampling ratio
+ QList recordLengths; ///< Available record lengths, ULONG_MAX means rolling
};
//////////////////////////////////////////////////////////////////////////////
@@ -114,7 +116,6 @@ namespace Hantek {
// Limits
ControlSpecificationSamplerate samplerate; ///< The samplerate specifications
- QList recordLengths; ///< Available record lengths, ULONG_MAX means rolling
QList bufferDividers; ///< Samplerate dividers for record lengths
QList gainSteps; ///< Available voltage steps in V/screenheight
unsigned char sampleSize; ///< Number of bits per sample
@@ -129,12 +130,22 @@ namespace Hantek {
};
//////////////////////////////////////////////////////////////////////////////
+ /// \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
+ };
+
+ //////////////////////////////////////////////////////////////////////////////
/// \struct ControlSettingsSamplerate hantek/control.h
/// \brief Stores the current samplerate settings of the device.
struct ControlSettingsSamplerate {
+ ControlSettingsSamplerateTarget target; ///< The target samplerate values
ControlSamplerateLimits *limits; ///< The samplerate limits
- unsigned long int downsampling; ///< The variable downsampling factor
- unsigned long int current; ///< The current samplerate
+ unsigned long int downsampler; ///< The variable downsampling factor
+ double current; ///< The current samplerate
};
//////////////////////////////////////////////////////////////////////////////
@@ -182,6 +193,9 @@ namespace Hantek {
~Control();
unsigned int getChannelCount();
+ QList *getAvailableRecordLengths();
+ double getMinSamplerate();
+ double getMaxSamplerate();
protected:
void run();
@@ -189,7 +203,10 @@ namespace Hantek {
unsigned long int calculateTriggerPoint(unsigned long int value);
int getCaptureState();
int getSamples(bool process);
+ double getBestSamplerate(double samplerate, bool fastRate = false, bool maximum = false, unsigned long int *downsampler = 0);
unsigned long int updateRecordLength(unsigned long int size);
+ unsigned long int updateSamplerate(unsigned long int downsampler, bool fastRate);
+ void restoreTargets();
// Communication with device
Device *device; ///< The USB device for the oscilloscope
@@ -206,14 +223,16 @@ namespace Hantek {
// Results
QList samples; ///< Sample data arrays
- QList samplesSize; ///< Number of samples data array
+ QList samplesSize; ///< Number of samples data array
+ unsigned long int previousSampleCount; ///< The expected total number of samples at the last check before sampling started
QMutex samplesMutex; ///< Mutex for the sample data
public slots:
virtual void connectDevice();
- unsigned long int setSamplerate(unsigned long int samplerate = 0);
unsigned long int setRecordLength(unsigned long int size);
+ double setSamplerate(double samplerate = 0.0);
+ double setRecordTime(double duration = 0.0);
int setChannelUsed(unsigned int channel, bool used);
int setCoupling(unsigned int channel, Dso::Coupling coupling);
diff --git a/openhantek/src/hantek/device.cpp b/openhantek/src/hantek/device.cpp
index 351fb46..953df9c 100644
--- a/openhantek/src/hantek/device.cpp
+++ b/openhantek/src/hantek/device.cpp
@@ -5,7 +5,7 @@
//
// Copyright (C) 2008, 2009 Oleg Khudyakov
// prcoder@potrebitel.ru
-// Copyright (C) 2010 Oliver Haag
+// Copyright (C) 2010 - 2012 Oliver Haag
// oliver.haag@gmail.com
//
// This program is free software: you can redistribute it and/or modify it
@@ -274,20 +274,21 @@ namespace Hantek {
}
#if LIBUSB_VERSION != 0
- /// \brief Bulk transfer to the oscilloscope.
+ /// \brief Bulk transfer to/from the oscilloscope.
/// \param endpoint Endpoint number, also sets the direction of the transfer.
/// \param data Buffer for the sent/recieved data.
/// \param length The length of the packet.
/// \param attempts The number of attempts, that are done on timeouts.
+ /// \param timeout The timeout in ms.
/// \return Number of transferred bytes on success, libusb error code on error.
- int Device::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts) {
+ int Device::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned long int length, int attempts, unsigned int timeout) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
int errorCode = LIBUSB_ERROR_TIMEOUT;
int transferred;
for(int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt)
- errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length, &transferred, HANTEK_TIMEOUT);
+ errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length, &transferred, timeout);
if(errorCode == LIBUSB_ERROR_NO_DEVICE)
this->disconnect();
@@ -303,7 +304,7 @@ namespace Hantek {
/// \param length The length 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 Device::bulkWrite(unsigned char *data, unsigned int length, int attempts) {
+ int Device::bulkWrite(unsigned char *data, unsigned long int length, int attempts) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
@@ -330,7 +331,7 @@ namespace Hantek {
/// \param length The length of the packet.
/// \param attempts The number of attempts, that are done on timeouts.
/// \return Number of received bytes on success, libusb error code on error.
- int Device::bulkRead(unsigned char *data, unsigned int length, int attempts) {
+ int Device::bulkRead(unsigned char *data, unsigned long int length, int attempts) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
@@ -374,7 +375,7 @@ namespace Hantek {
/// \param length The length of data contained in the packets.
/// \param attempts The number of attempts, that are done on timeouts.
/// \return Number of received bytes on success, libusb error code on error.
- int Device::bulkReadMulti(unsigned char *data, unsigned int length, int attempts) {
+ int Device::bulkReadMulti(unsigned char *data, unsigned long int length, int attempts) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
@@ -385,14 +386,14 @@ namespace Hantek {
return errorCode;
errorCode = this->inPacketLength;
- unsigned int packet, received = 0;
+ unsigned long int packet, received = 0;
for(packet = 0; received < length && errorCode == this->inPacketLength; ++packet) {
#if LIBUSB_VERSION == 0
errorCode = LIBUSB_ERROR_TIMEOUT;
for(int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt)
- errorCode = usb_bulk_read(this->handle, HANTEK_EP_IN, (char *) data + packet * this->inPacketLength, qMin(length - received, (unsigned int) this->inPacketLength), HANTEK_TIMEOUT);
+ errorCode = usb_bulk_read(this->handle, HANTEK_EP_IN, (char *) data + packet * this->inPacketLength, qMin(length - received, (unsigned long int) this->inPacketLength), HANTEK_TIMEOUT);
#else
- errorCode = this->bulkTransfer(HANTEK_EP_IN, data + packet * this->inPacketLength, qMin(length - received, (unsigned int) this->inPacketLength), attempts);
+ errorCode = this->bulkTransfer(HANTEK_EP_IN, data + packet * this->inPacketLength, qMin(length - received, (unsigned long int) this->inPacketLength), attempts, HANTEK_TIMEOUT_MULTI);
#endif
if(errorCode > 0)
received += errorCode;
@@ -413,7 +414,7 @@ namespace Hantek {
/// \param index The index field of the packet.
/// \param attempts The number of attempts, that are done on timeouts.
/// \return Number of transferred bytes on success, libusb error code on error.
- int Device::controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) {
+ int Device::controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
@@ -438,7 +439,7 @@ namespace Hantek {
/// \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 Device::controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) {
+ int Device::controlWrite(unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
@@ -453,7 +454,7 @@ namespace Hantek {
/// \param index The index field of the packet.
/// \param attempts The number of attempts, that are done on timeouts.
/// \return Number of received bytes on success, libusb error code on error.
- int Device::controlRead(unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) {
+ int Device::controlRead(unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts) {
if(!this->handle)
return LIBUSB_ERROR_NO_DEVICE;
diff --git a/openhantek/src/hantek/device.h b/openhantek/src/hantek/device.h
index 598cfdc..633bb20 100644
--- a/openhantek/src/hantek/device.h
+++ b/openhantek/src/hantek/device.h
@@ -4,10 +4,8 @@
/// \file hantek/device.h
/// \brief Declares the Hantek::Device class.
//
-// Copyright (C) 2008, 2009 Oleg Khudyakov
-// prcoder@potrebitel.ru
-// Copyright (C) 2010 Oliver Haag
-// oliver.haag@gmail.com
+/// \copyright (c) 2008, 2009 Oleg Khudyakov
+/// \copyright (c) 2010 - 2012 Oliver Haag
//
// 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
@@ -62,17 +60,17 @@ namespace Hantek {
// Various methods to handle USB transfers
#if LIBUSB_VERSION != 0
- int bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
+ int bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS, unsigned int timeout = HANTEK_TIMEOUT);
#endif
- int bulkWrite(unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
- int bulkRead(unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
+ int bulkWrite(unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS);
+ int bulkRead(unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS);
- int bulkCommand(Helper::DataArray *command, int attempts = HANTEK_ATTEMPTS_DEFAULT);
- int bulkReadMulti(unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
+ int bulkCommand(Helper::DataArray *command, int attempts = HANTEK_ATTEMPTS);
+ int bulkReadMulti(unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS_MULTI);
- int controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts = HANTEK_ATTEMPTS_DEFAULT);
- int controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS_DEFAULT);
- int controlRead(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS_DEFAULT);
+ int controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts = HANTEK_ATTEMPTS);
+ int controlWrite(unsigned char request, unsigned char *data, unsigned long int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS);
+ int controlRead(unsigned char request, unsigned char *data, unsigned long int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS);
int getConnectionSpeed();
Model getModel();
diff --git a/openhantek/src/hantek/types.cpp b/openhantek/src/hantek/types.cpp
index ffb197d..11a9081 100644
--- a/openhantek/src/hantek/types.cpp
+++ b/openhantek/src/hantek/types.cpp
@@ -101,24 +101,26 @@ namespace Hantek {
}
/// \brief Sets the data bytes to the specified values.
- /// \param samplerateSlow The SamplerateSlow value.
+ /// \param downsampler The Downsampler value.
/// \param triggerPosition The trigger position value.
/// \param triggerSource The trigger source id (Tsr1).
/// \param recordLength The record length id (Tsr1).
- /// \param samplerateFast The samplerateFast value (Tsr1).
+ /// \param samplerateId The samplerateId value (Tsr1).
+ /// \param downsamplingMode The downsamplingMode value (Tsr1).
/// \param usedChannels The enabled channels (Tsr2).
/// \param fastRate The fastRate state (Tsr2).
/// \param triggerSlope The triggerSlope value (Tsr2).
- BulkSetTriggerAndSamplerate::BulkSetTriggerAndSamplerate(unsigned short int samplerateSlow, unsigned long int triggerPosition, unsigned char triggerSource, unsigned char recordLength, unsigned char samplerateFast, unsigned char usedChannels, bool fastRate, unsigned char triggerSlope) : Helper::DataArray(12) {
+ BulkSetTriggerAndSamplerate::BulkSetTriggerAndSamplerate(unsigned short int downsampler, unsigned long int triggerPosition, unsigned char triggerSource, unsigned char recordLength, unsigned char samplerateId, bool downsamplingMode, unsigned char usedChannels, bool fastRate, unsigned char triggerSlope) : Helper::DataArray(12) {
this->init();
this->setTriggerSource(triggerSource);
this->setRecordLength(recordLength);
- this->setSamplerateFast(samplerateFast);
+ this->setSamplerateId(samplerateId);
+ this->setDownsamplingMode(downsamplingMode);
this->setUsedChannels(usedChannels);
this->setFastRate(fastRate);
this->setTriggerSlope(triggerSlope);
- this->setSamplerateSlow(samplerateSlow);
+ this->setDownsampler(downsampler);
this->setTriggerPosition(triggerPosition);
}
@@ -146,16 +148,28 @@ namespace Hantek {
((Tsr1Bits *) &(this->array[2]))->recordLength = value;
}
- /// \brief Get the samplerateFast value in Tsr1Bits.
- /// \return The samplerateFast value.
- unsigned char BulkSetTriggerAndSamplerate::getSamplerateFast() {
- return ((Tsr1Bits *) &(this->array[2]))->samplerateFast;
+ /// \brief Get the samplerateId value in Tsr1Bits.
+ /// \return The samplerateId value.
+ unsigned char BulkSetTriggerAndSamplerate::getSamplerateId() {
+ return ((Tsr1Bits *) &(this->array[2]))->samplerateId;
+ }
+
+ /// \brief Set the samplerateId in Tsr1Bits to the given value.
+ /// \param value The new samplerateId value.
+ void BulkSetTriggerAndSamplerate::setSamplerateId(unsigned char value) {
+ ((Tsr1Bits *) &(this->array[2]))->samplerateId = value;
}
- /// \brief Set the samplerateFast in Tsr1Bits to the given value.
- /// \param value The new samplerateFast value.
- void BulkSetTriggerAndSamplerate::setSamplerateFast(unsigned char value) {
- ((Tsr1Bits *) &(this->array[2]))->samplerateFast = value;
+ /// \brief Get the downsamplerMode value in Tsr1Bits.
+ /// \return The downsamplerMode value.
+ bool BulkSetTriggerAndSamplerate::getDownsamplingMode() {
+ return ((Tsr1Bits *) &(this->array[2]))->downsamplingMode == 1;
+ }
+
+ /// \brief Set the downsamplerMode in Tsr1Bits to the given value.
+ /// \param downsampling The new downsamplerMode value.
+ void BulkSetTriggerAndSamplerate::setDownsamplingMode(bool downsampling) {
+ ((Tsr1Bits *) &(this->array[2]))->downsamplingMode = downsampling ? 1 : 0;
}
/// \brief Get the usedChannels value in Tsr2Bits.
@@ -194,17 +208,17 @@ namespace Hantek {
((Tsr2Bits *) &(this->array[3]))->triggerSlope = slope;
}
- /// \brief Get the SamplerateSlow value.
- /// \return The SamplerateSlow value.
- unsigned short int BulkSetTriggerAndSamplerate::getSamplerateSlow() {
+ /// \brief Get the Downsampler value.
+ /// \return The Downsampler value.
+ unsigned short int BulkSetTriggerAndSamplerate::getDownsampler() {
return (unsigned short int) this->array[4] | ((unsigned short int) this->array[5] << 8);
}
- /// \brief Set the SamplerateSlow to the given value.
- /// \param samplerate The new SamplerateSlow value.
- void BulkSetTriggerAndSamplerate::setSamplerateSlow(unsigned short int samplerate) {
- this->array[4] = (unsigned char) samplerate;
- this->array[5] = (unsigned char) (samplerate >> 8);
+ /// \brief Set the Downsampler to the given value.
+ /// \param downsampler The new Downsampler value.
+ void BulkSetTriggerAndSamplerate::setDownsampler(unsigned short int downsampler) {
+ this->array[4] = (unsigned char) downsampler;
+ this->array[5] = (unsigned char) (downsampler >> 8);
}
/// \brief Get the TriggerPosition value.
@@ -328,8 +342,6 @@ namespace Hantek {
/// \brief Initialize the array to the needed values.
void BulkSetGain::init() {
this->array[0] = BULK_SETGAIN;
- this->array[1] = 0x0f;
- ((GainBits *) &(this->array[2]))->reserved = 3;
}
@@ -363,7 +375,6 @@ namespace Hantek {
/// \brief Initialize the array to the needed values.
void BulkSetLogicalData::init() {
this->array[0] = BULK_SETLOGICALDATA;
- this->array[1] = 0x0f;
}
@@ -378,45 +389,33 @@ namespace Hantek {
//////////////////////////////////////////////////////////////////////////////
// class BulkSetFilter2250
/// \brief Sets the data array to needed values.
- BulkSetFilter2250::BulkSetFilter2250() : Helper::DataArray(4) {
+ BulkSetChannels2250::BulkSetChannels2250() : Helper::DataArray(4) {
this->init();
}
/// \brief Sets the used channels.
- /// \param channel1 true if channel 1 is filtered.
- /// \param channel2 true if channel 2 is filtered.
- BulkSetFilter2250::BulkSetFilter2250(bool channel1, bool channel2) : Helper::DataArray(4) {
+ /// \param usedChannels The UsedChannels value.
+ BulkSetChannels2250::BulkSetChannels2250(unsigned char usedChannels) : Helper::DataArray(4) {
this->init();
- this->setChannel(0, channel1);
- this->setChannel(1, channel2);
+ this->setUsedChannels(usedChannels);
}
- /// \brief Gets the filtering state of one channel.
- /// \param channel The channel whose filtering state should be returned.
- /// \return The filtering state of the channel.
- bool BulkSetFilter2250::getChannel(unsigned int channel) {
- FilterBits *filterBits = (FilterBits *) &(this->array[2]);
- if(channel == 0)
- return filterBits->channel1 == 1;
- else
- return filterBits->channel2 == 1;
+ /// \brief Get the UsedChannels value
+ /// \return The UsedChannels value.
+ unsigned char BulkSetChannels2250::getUsedChannels() {
+ return this->array[2];
}
- /// \brief Enables/disables filtering of one channel.
- /// \param channel The channel that should be set.
- /// \param filtered true if the channel should be filtered.
- void BulkSetFilter2250::setChannel(unsigned int channel, bool filtered) {
- FilterBits *filterBits = (FilterBits *) &(this->array[2]);
- if(channel == 0)
- filterBits->channel1 = filtered ? 1 : 0;
- else
- filterBits->channel2 = filtered ? 1 : 0;
+ /// \brief Set the UsedChannels to the given value.
+ /// \param value The new UsedChannels value.
+ void BulkSetChannels2250::setUsedChannels(unsigned char value) {
+ this->array[2] = value;
}
/// \brief Initialize the array to the needed values.
- void BulkSetFilter2250::init() {
- this->array[0] = BULK_BSETFILTER;
+ void BulkSetChannels2250::init() {
+ this->array[0] = BULK_BSETCHANNELS;
}
diff --git a/openhantek/src/hantek/types.h b/openhantek/src/hantek/types.h
index 08a77e7..45fd443 100644
--- a/openhantek/src/hantek/types.h
+++ b/openhantek/src/hantek/types.h
@@ -36,7 +36,9 @@
#define HANTEK_EP_OUT 0x02 ///< OUT Endpoint for bulk transfers
#define HANTEK_EP_IN 0x86 ///< IN Endpoint for bulk transfers
#define HANTEK_TIMEOUT 500 ///< Timeout for USB transfers in ms
-#define HANTEK_ATTEMPTS_DEFAULT 3 ///< The number of transfer attempts
+#define HANTEK_TIMEOUT_MULTI 10 ///< Timeout for multi packet USB transfers in ms
+#define HANTEK_ATTEMPTS 3 ///< The number of transfer attempts
+#define HANTEK_ATTEMPTS_MULTI 1 ///< The number of multi packet transfer attempts
#define HANTEK_CHANNELS 2 ///< Number of physical channels
#define HANTEK_SPECIAL_CHANNELS 2 ///< Number of special channels
@@ -57,7 +59,7 @@ namespace Hantek {
///
///
/// 0x00
- /// 0x0f
+ /// 0x00
/// FilterBits
/// 0x00
/// 0x00
@@ -67,6 +69,8 @@ namespace Hantek {
///
///
///
+ ///
+ /// This command is used by the official %Hantek software, but doesn't seem to be used by the device.
///
BULK_SETFILTER,
@@ -79,8 +83,8 @@ namespace Hantek {
/// 0x00
/// Tsr1Bits
/// Tsr2Bits
- /// SamplerateSlow[0]
- /// SamplerateSlow[1]
+ /// Downsampler[0]
+ /// Downsampler[1]
///
///
///
@@ -95,11 +99,20 @@ namespace Hantek {
///
///
///
- /// The samplerate is set relative to the maximum sample rate by a divider that is set in Tsr1Bits.samplerateFast and the 16-bit value in the two SamplerateSlow bytes.
- /// Without using fast rate mode, the samplerate is:
- /// Samplerate = SamplerateMax / (1comp(SamplerateSlow) * 2 + Tsr1Bits.samplerateFast)
- /// SamplerateMax is 50 MHz for the DSO-2090.
- /// When using fast rate mode the resulting samplerate is twice (For DSO-2150 three times) as fast, when using the large buffer it is half as fast. When Tsr1Bits.recordLength is 0 (Roll mode) the sampling rate is divided by 1000. Setting Tsr1Bits.samplerateFast to 0 doesn't work, the result will be the same as Tsr1Bits.samplerateFast = 1. SamplerateSlow can't be used together with fast rate mode, the result is always the the same as SlowValue = 0.
+ /// 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.samplerateId 0 1 2 3
+ ///
+ ///
+ /// Samplerate Max Base Base / 2 Base / 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.
@@ -225,7 +238,7 @@ namespace Hantek {
///
///
/// 0x07
- /// 0x0f
+ /// 0x00
/// GainBits
/// 0x00
/// 0x00
@@ -245,7 +258,7 @@ namespace Hantek {
///
///
/// 0x08
- /// 0x0f
+ /// 0x00
/// Data | 0x01
/// 0x00
/// 0x00
@@ -293,20 +306,20 @@ namespace Hantek {
///
BULK_AUNKNOWN,
- /// BulkSetFilter2250 [::MODEL_DSO2250 ]
+ /// BulkSetChannels2250 [::MODEL_DSO2250 ]
///
/// This command sets the activated channels for the DSO-2250:
///
///
/// 0x0b
/// 0x00
- /// FilterBits
+ /// BUsedChannels
/// 0x00
///
///
///
///
- BULK_BSETFILTER,
+ BULK_BSETCHANNELS,
/// BulkSetTrigger2250 [::MODEL_DSO2250 ]
///
@@ -314,10 +327,10 @@ namespace Hantek {
///
///
/// 0x0c
- /// 0x0f
+ /// 0x00
/// CTriggerBits
/// 0x00
- /// 0x02
+ /// 0x00
/// 0x00
/// 0x00
/// 0x00
@@ -340,9 +353,10 @@ namespace Hantek {
///
///
///
- /// The values are similar to the ones used with ::BULK_SETTRIGGERANDSAMPLERATE. The formula is a bit different here:
+ /// 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)
- /// SamplerateMax is 100 MS/s for the DSO-5200 in default configuration and 250 MS/s in fast rate mode though, the modifications regarding record length are the the same that apply for the DSO-2090.
+ /// 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.
///
///
BULK_CSETTRIGGERORSAMPLERATE,
@@ -397,17 +411,17 @@ namespace Hantek {
/// 0x00
/// ESamplerateBits
/// 0x00
- /// SamplerateSlow[0]
- /// SamplerateSlow[1]
+ /// Samplerate[0]
+ /// Samplerate[1]
/// 0x00
/// 0x00
///
///
///
///
- /// The values are similar to the ones used with ::BULK_SETTRIGGERANDSAMPLERATE. The formula is a bit different here:
- /// Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + ESamplerateBits.samplerateFast)
- /// SamplerateMax is 100 MS/s for the DSO-2250 in default configuration and 250 MS/s in fast rate mode though, the modifications regarding record length are the the same that apply for the DSO-2090.
+ /// 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 ]
@@ -436,25 +450,25 @@ namespace Hantek {
///
/// 0x0f
/// 0x00
- /// TriggerPositionPre[0]
- /// TriggerPositionPre[1]
- /// FBuffer1Bits
+ /// TriggerPositionPost[0]
+ /// TriggerPositionPost[1]
+ /// TriggerPositionPost[2]
/// 0x00
///
///
///
///
- /// TriggerPositionPost[0]
- /// TriggerPositionPost[1]
- /// FBuffer1Bits
+ /// TriggerPositionPre[0]
+ /// TriggerPositionPre[1]
+ /// TriggerPositionPre[2]
+ /// 0x00
/// 0x00
- /// FBuffer2Bits
/// 0x00
///
///
///
///
- /// 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%.
+ /// 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%.
///
///
BULK_FSETBUFFER,
@@ -703,6 +717,16 @@ namespace Hantek {
};
//////////////////////////////////////////////////////////////////////////////
+ /// \enum BUsedChannels hantek/types.h
+ /// \brief The enabled channels for the DSO-2250.
+ enum BUsedChannels {
+ BUSED_CH1, ///< Only channel 1 is activated
+ BUSED_NONE, ///< No channels are activated
+ BUSED_CH1CH2, ///< Channel 1 and 2 are both activated
+ BUSED_CH2 ///< Only channel 2 is activated
+ };
+
+ //////////////////////////////////////////////////////////////////////////////
/// \enum DTriggerPositionUsed hantek/types.h
/// \brief The trigger position states for the 0x0d command.
enum DTriggerPositionUsed {
@@ -711,14 +735,6 @@ namespace Hantek {
};
//////////////////////////////////////////////////////////////////////////////
- /// \enum FTriggerPositionUsed hantek/types.h
- /// \brief The trigger position states for the 0x0f command.
- enum FTriggerPositionUsed {
- FTRIGGERPOSITION_OFF = 0, ///< Used for Roll mode
- FTRIGGERPOSITION_ON = 3 ///< Used for normal operation
- };
-
- //////////////////////////////////////////////////////////////////////////////
/// \struct FilterBits hantek/types.h
/// \brief The bits for BULK_SETFILTER.
struct FilterBits {
@@ -743,7 +759,8 @@ namespace Hantek {
struct Tsr1Bits {
unsigned char triggerSource:2; ///< The trigger source, see Hantek::TriggerSource
unsigned char recordLength:3; ///< See ::RecordLengthId
- unsigned char samplerateFast:3; ///< samplerate value for fast sampling rates
+ unsigned char samplerateId:2; ///< Samplerate ID when downsampler is disabled
+ unsigned char downsamplingMode:1; ///< true, if Downsampler is used
};
//////////////////////////////////////////////////////////////////////////////
@@ -795,23 +812,6 @@ namespace Hantek {
};
//////////////////////////////////////////////////////////////////////////////
- /// \struct FBuffer1Bits hantek/types.h
- /// \brief Buffer mode bits for 0x0f command (Byte 1).
- struct FBuffer1Bits {
- unsigned char triggerPositionUsed:2; ///< See ::DTriggerPositionUsed
- unsigned char largeBuffer:1; ///< false, if ::RecordLengthId is ::RECORDLENGTHID_LARGE
- unsigned char reserved:5; ///< Unused bits
- };
-
- //////////////////////////////////////////////////////////////////////////////
- /// \struct FBuffer2Bits hantek/types.h
- /// \brief Buffer mode bits for 0x0f command (Byte 2).
- struct FBuffer2Bits {
- unsigned char reserved:7; ///< Unused bits
- unsigned char slowBuffer:1; ///< false, if ::RecordLengthId is ::RECORDLENGTHID_SMALL
- };
-
- //////////////////////////////////////////////////////////////////////////////
/// \class BulkSetFilter hantek/types.h
/// \brief The BULK_SETFILTER builder.
class BulkSetFilter : public Helper::DataArray {
@@ -834,22 +834,24 @@ namespace Hantek {
class BulkSetTriggerAndSamplerate : public Helper::DataArray {
public:
BulkSetTriggerAndSamplerate();
- BulkSetTriggerAndSamplerate(unsigned short int samplerateSlow, unsigned long int triggerPosition, unsigned char triggerSource = 0, unsigned char recordLength = 0, unsigned char samplerateFast = 0, unsigned char usedChannels = 0, bool fastRate = false, unsigned char triggerSlope = 0);
+ BulkSetTriggerAndSamplerate(unsigned short int downsampler, unsigned long int triggerPosition, unsigned char triggerSource = 0, unsigned char recordLength = 0, unsigned char samplerateId = 0, bool downsamplingMode = true, unsigned char usedChannels = 0, bool fastRate = false, unsigned char triggerSlope = 0);
unsigned char getTriggerSource();
void setTriggerSource(unsigned char value);
unsigned char getRecordLength();
void setRecordLength(unsigned char value);
- unsigned char getSamplerateFast();
- void setSamplerateFast(unsigned char value);
+ unsigned char getSamplerateId();
+ void setSamplerateId(unsigned char value);
+ bool getDownsamplingMode();
+ void setDownsamplingMode(bool downsampling);
unsigned char getUsedChannels();
void setUsedChannels(unsigned char value);
bool getFastRate();
void setFastRate(bool fastRate);
unsigned char getTriggerSlope();
void setTriggerSlope(unsigned char slope);
- unsigned short int getSamplerateSlow();
- void setSamplerateSlow(unsigned short int samplerate);
+ unsigned short int getDownsampler();
+ void setDownsampler(unsigned short int downsampler);
unsigned long int getTriggerPosition();
void setTriggerPosition(unsigned long int position);
@@ -947,15 +949,15 @@ namespace Hantek {
};
//////////////////////////////////////////////////////////////////////////////
- /// \class BulkSetFilter2250 hantek/types.h
+ /// \class BulkSetChannels2250 hantek/types.h
/// \brief The DSO-2250 BULK_BSETFILTER builder.
- class BulkSetFilter2250 : public Helper::DataArray {
+ class BulkSetChannels2250 : public Helper::DataArray {
public:
- BulkSetFilter2250();
- BulkSetFilter2250(bool channel1, bool channel2);
+ BulkSetChannels2250();
+ BulkSetChannels2250(unsigned char usedChannels);
- bool getChannel(unsigned int channel);
- void setChannel(unsigned int channel, bool filtered);
+ unsigned char getUsedChannels();
+ void setUsedChannels(unsigned char value);
private:
void init();
diff --git a/openhantek/src/openhantek.cpp b/openhantek/src/openhantek.cpp
index 4635d7c..8a76ff1 100644
--- a/openhantek/src/openhantek.cpp
+++ b/openhantek/src/openhantek.cpp
@@ -92,61 +92,12 @@ OpenHantekMainWindow::OpenHantekMainWindow(QWidget *parent, Qt::WindowFlags flag
this->settings->options.window.position = this->pos();
this->settings->options.window.size = this->size();
- // Connect general signals
- connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
- //connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
- connect(this->dsoControl, SIGNAL(statusMessage(QString, int)), this->statusBar(), SLOT(showMessage(QString, int)));
- connect(this->dsoControl, SIGNAL(samplesAvailable(const QList *, const QList *, double, QMutex *)), this->dataAnalyzer, SLOT(analyze(const QList *, const QList *, double, QMutex *)));
-
- // Connect signals to DSO controller and widget
- //connect(this->horizontalDock, SIGNAL(formatChanged(HorizontalFormat)), this->dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
- connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this, SLOT(updateTimebase()));
- connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this->dsoWidget, SLOT(updateTimebase()));
- connect(this->horizontalDock, SIGNAL(frequencybaseChanged(double)), this->dsoWidget, SLOT(updateFrequencybase()));
-
- connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoControl, SLOT(setTriggerMode(Dso::TriggerMode)));
- connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoWidget, SLOT(updateTriggerMode()));
- connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoControl, SLOT(setTriggerSource(bool, unsigned int)));
- connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoWidget, SLOT(updateTriggerSource()));
- connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoControl, SLOT(setTriggerSlope(Dso::Slope)));
- connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoWidget, SLOT(updateTriggerSlope()));
- connect(this->dsoWidget, SIGNAL(triggerPositionChanged(double)), this->dsoControl, SLOT(setPretriggerPosition(double)));
- connect(this->dsoWidget, SIGNAL(triggerLevelChanged(unsigned int, double)), this->dsoControl, SLOT(setTriggerLevel(unsigned int, double)));
-
- connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
- connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateVoltageUsed(unsigned int, bool)));
- connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoControl, SLOT(setCoupling(unsigned int, Dso::Coupling)));
- connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoWidget, SLOT(updateVoltageCoupling(unsigned int)));
- connect(this->voltageDock, SIGNAL(modeChanged(Dso::MathMode)), this->dsoWidget, SLOT(updateMathMode()));
- connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this, SLOT(updateVoltageGain(unsigned int)));
- connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this->dsoWidget, SLOT(updateVoltageGain(unsigned int)));
- connect(this->dsoWidget, SIGNAL(offsetChanged(unsigned int, double)), this, SLOT(updateOffset(unsigned int)));
-
- connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
- connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool)));
- connect(this->spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)), this->dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int)));
-
- // Started/stopped signals from oscilloscope
- connect(this->dsoControl, SIGNAL(samplingStarted()), this, SLOT(started()));
- connect(this->dsoControl, SIGNAL(samplingStopped()), this, SLOT(stopped()));
+ // Connect all signals
+ this->connectSignals();
// Set up the oscilloscope
this->dsoControl->connectDevice();
-
- for(unsigned int channel = 0; channel < this->settings->scope.physicalChannels; ++channel) {
- this->dsoControl->setCoupling(channel, (Dso::Coupling) this->settings->scope.voltage[channel].misc);
- this->updateVoltageGain(channel);
- this->updateOffset(channel);
- this->dsoControl->setTriggerLevel(channel, this->settings->scope.voltage[channel].trigger);
- }
- this->updateUsed(this->settings->scope.physicalChannels);
- this->dsoControl->setRecordLength(this->settings->scope.horizontal.samples);
- this->updateTimebase();
- this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode);
- this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
- this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope);
- this->dsoControl->setTriggerSource(this->settings->scope.trigger.special, this->settings->scope.trigger.source);
-
+ this->initializeDevice();
this->dsoControl->startSampling();
}
@@ -202,21 +153,6 @@ void OpenHantekMainWindow::createActions() {
this->startStopAction = new QAction(this);
this->startStopAction->setShortcut(tr("Space"));
this->stopped();
-
- this->recordLengthActionGroup = new QActionGroup(this);
- connect(this->recordLengthActionGroup, SIGNAL(selected(QAction *)), this, SLOT(recordLengthSelected(QAction *)));
-
- this->recordLengthSmallAction = new QAction(tr("&Small"), this);
- this->recordLengthSmallAction->setActionGroup(this->recordLengthActionGroup);
- this->recordLengthSmallAction->setCheckable(true);
- this->recordLengthSmallAction->setChecked(this->settings->scope.horizontal.samples == 10240);
- this->recordLengthSmallAction->setStatusTip(tr("10240 Samples"));
-
- this->recordLengthLargeAction = new QAction(tr("&Large"), this);
- this->recordLengthLargeAction->setActionGroup(this->recordLengthActionGroup);
- this->recordLengthLargeAction->setCheckable(true);
- this->recordLengthLargeAction->setChecked(this->settings->scope.horizontal.samples != 10240);
- this->recordLengthLargeAction->setStatusTip(tr("32768 Samples"));
this->digitalPhosphorAction = new QAction(QIcon(":actions/digitalphosphor.png"), tr("Digital &phosphor"), this);
this->digitalPhosphorAction->setCheckable(true);
@@ -276,12 +212,9 @@ void OpenHantekMainWindow::createMenus() {
this->oscilloscopeMenu->addSeparator();
this->oscilloscopeMenu->addAction(this->startStopAction);
#ifdef DEBUG
+ this->oscilloscopeMenu->addSeparator();
this->oscilloscopeMenu->addAction(this->commandAction);
#endif
- this->oscilloscopeMenu->addSeparator();
- this->recordLengthMenu = this->oscilloscopeMenu->addMenu(tr("&Record length"));
- this->recordLengthMenu->addAction(this->recordLengthSmallAction);
- this->recordLengthMenu->addAction(this->recordLengthLargeAction);
this->menuBar()->addSeparator();
@@ -337,6 +270,82 @@ void OpenHantekMainWindow::createDockWindows()
this->voltageDock = new VoltageDock(this->settings);
}
+/// \brief Connect general signals and device management signals.
+void OpenHantekMainWindow::connectSignals() {
+ // Connect general signals
+ connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
+ //connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
+ connect(this->dsoControl, SIGNAL(statusMessage(QString, int)), this->statusBar(), SLOT(showMessage(QString, int)));
+ connect(this->dsoControl, SIGNAL(samplesAvailable(const QList *, const QList *, double, QMutex *)), this->dataAnalyzer, SLOT(analyze(const QList *, const QList *, double, QMutex *)));
+
+ // Connect signals to DSO controller and widget
+ connect(this->horizontalDock, SIGNAL(samplerateChanged(double)), this, SLOT(samplerateSelected()));
+ connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this, SLOT(timebaseSelected()));
+ connect(this->horizontalDock, SIGNAL(frequencybaseChanged(double)), this->dsoWidget, SLOT(updateFrequencybase(double)));
+ connect(this->horizontalDock, SIGNAL(recordLengthChanged(unsigned long)), this, SLOT(recordLengthSelected(unsigned long)));
+ //connect(this->horizontalDock, SIGNAL(formatChanged(HorizontalFormat)), this->dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
+
+ connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoControl, SLOT(setTriggerMode(Dso::TriggerMode)));
+ connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoWidget, SLOT(updateTriggerMode()));
+ connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoControl, SLOT(setTriggerSource(bool, unsigned int)));
+ connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoWidget, SLOT(updateTriggerSource()));
+ connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoControl, SLOT(setTriggerSlope(Dso::Slope)));
+ connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoWidget, SLOT(updateTriggerSlope()));
+ connect(this->dsoWidget, SIGNAL(triggerPositionChanged(double)), this->dsoControl, SLOT(setPretriggerPosition(double)));
+ connect(this->dsoWidget, SIGNAL(triggerLevelChanged(unsigned int, double)), this->dsoControl, SLOT(setTriggerLevel(unsigned int, double)));
+
+ connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
+ connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateVoltageUsed(unsigned int, bool)));
+ connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoControl, SLOT(setCoupling(unsigned int, Dso::Coupling)));
+ connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoWidget, SLOT(updateVoltageCoupling(unsigned int)));
+ connect(this->voltageDock, SIGNAL(modeChanged(Dso::MathMode)), this->dsoWidget, SLOT(updateMathMode()));
+ connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this, SLOT(updateVoltageGain(unsigned int)));
+ connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this->dsoWidget, SLOT(updateVoltageGain(unsigned int)));
+ connect(this->dsoWidget, SIGNAL(offsetChanged(unsigned int, double)), this, SLOT(updateOffset(unsigned int)));
+
+ connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
+ connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool)));
+ connect(this->spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)), this->dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int)));
+
+ // Started/stopped signals from oscilloscope
+ connect(this->dsoControl, SIGNAL(samplingStarted()), this, SLOT(started()));
+ connect(this->dsoControl, SIGNAL(samplingStopped()), this, SLOT(stopped()));
+
+ //connect(this->dsoControl, SIGNAL(recordLengthChanged(unsigned long)), this, SLOT(recordLengthChanged()));
+ connect(this->dsoControl, SIGNAL(recordTimeChanged(double)), this, SLOT(recordTimeChanged(double)));
+ connect(this->dsoControl, SIGNAL(samplerateChanged(double)), this, SLOT(samplerateChanged(double)));
+
+ connect(this->dsoControl, SIGNAL(availableRecordLengthsChanged(QList)), this->horizontalDock, SLOT(availableRecordLengthsChanged(QList)));
+ connect(this->dsoControl, SIGNAL(samplerateLimitsChanged(double, double)), this->horizontalDock, SLOT(samplerateLimitsChanged(double, double)));
+}
+
+/// \brief Initialize the device with the current settings.
+void OpenHantekMainWindow::initializeDevice() {
+ for(unsigned int channel = 0; channel < this->settings->scope.physicalChannels; ++channel) {
+ this->dsoControl->setCoupling(channel, (Dso::Coupling) this->settings->scope.voltage[channel].misc);
+ this->updateVoltageGain(channel);
+ this->updateOffset(channel);
+ this->dsoControl->setTriggerLevel(channel, this->settings->scope.voltage[channel].trigger);
+ }
+ this->updateUsed(this->settings->scope.physicalChannels);
+ if(this->dsoControl->getAvailableRecordLengths()->isEmpty())
+ this->dsoControl->setRecordLength(this->settings->scope.horizontal.recordLength);
+ else
+ this->dsoControl->setRecordLength(this->dsoControl->getAvailableRecordLengths()->indexOf(this->settings->scope.horizontal.recordLength));
+ if(this->settings->scope.horizontal.samplerateSet)
+ this->samplerateSelected();
+ else
+ this->timebaseSelected();
+ this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode);
+ this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
+ this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope);
+ this->dsoControl->setTriggerSource(this->settings->scope.trigger.special, this->settings->scope.trigger.source);
+
+ // Apply the limits to the dock widgets
+ this->horizontalDock->availableRecordLengthsChanged(*this->dsoControl->getAvailableRecordLengths());
+ this->horizontalDock->samplerateLimitsChanged(this->dsoControl->getMinSamplerate(), this->dsoControl->getMaxSamplerate());
+}
+
/// \brief Read the settings from an ini file.
/// \param fileName Optional filename to export the settings to a specific file.
/// \return 0 on success, negative on error.
@@ -598,11 +607,47 @@ void OpenHantekMainWindow::updateSettings() {
}
}
+/// \brief The oscilloscope changed the record time.
+/// \param duration The new record time duration in seconds.
+void OpenHantekMainWindow::recordTimeChanged(double duration) {
+ if(this->settings->scope.horizontal.samplerateSet) {
+ // The samplerate was set, let's adapt the timebase accordingly
+ this->settings->scope.horizontal.timebase = duration / DIVS_TIME;
+ this->horizontalDock->setTimebase(this->settings->scope.horizontal.timebase);
+ }
+
+ // The trigger position should be kept at the same place but the timebase has changed
+ this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
+
+ this->dsoWidget->updateTimebase(this->settings->scope.horizontal.timebase);
+}
+
+/// \brief The oscilloscope changed the samplerate.
+/// \param samplerate The new samplerate in samples per second.
+void OpenHantekMainWindow::samplerateChanged(double samplerate) {
+ if(!this->settings->scope.horizontal.samplerateSet) {
+ // The timebase was set, let's adapt the samplerate accordingly
+ this->settings->scope.horizontal.samplerate = samplerate;
+ this->horizontalDock->setSamplerate(samplerate);
+ }
+
+ this->dsoWidget->updateSamplerate(samplerate);
+}
+
/// \brief Apply new record length to settings.
-/// \param action The selected record length menu item.
-void OpenHantekMainWindow::recordLengthSelected(QAction *action) {
- this->settings->scope.horizontal.samples = (action == this->recordLengthSmallAction) ? 10240 : 32768;
- this->dsoControl->setRecordLength(this->settings->scope.horizontal.samples);
+/// \param recordLength The selected record length in samples.
+void OpenHantekMainWindow::recordLengthSelected(unsigned long recordLength) {
+ this->dsoControl->setRecordLength(recordLength);
+}
+
+/// \brief Sets the samplerate of the oscilloscope.
+void OpenHantekMainWindow::samplerateSelected() {
+ this->dsoControl->setSamplerate(this->settings->scope.horizontal.samplerate);
+}
+
+/// \brief Sets the record time of the oscilloscope.
+void OpenHantekMainWindow::timebaseSelected() {
+ this->dsoControl->setRecordTime(this->settings->scope.horizontal.timebase * DIVS_TIME);
}
/// \brief Sets the offset of the oscilloscope for the given channel.
@@ -614,15 +659,6 @@ void OpenHantekMainWindow::updateOffset(unsigned int channel) {
this->dsoControl->setOffset(channel, (this->settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
}
-/// \brief Sets the samplerate of the oscilloscope.
-void OpenHantekMainWindow::updateTimebase() {
- this->settings->scope.horizontal.samplerate = this->dsoControl->setSamplerate(1e3 / this->settings->scope.horizontal.timebase);
- this->dsoWidget->updateSamplerate();
-
- // The trigger position should be kept at the same place but the timebase has changed
- this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
-}
-
/// \brief Sets the state of the given oscilloscope channel.
/// \param channel The channel whose state has changed.
void OpenHantekMainWindow::updateUsed(unsigned int channel) {
diff --git a/openhantek/src/openhantek.h b/openhantek/src/openhantek.h
index cb9e4b2..e6cd6ae 100644
--- a/openhantek/src/openhantek.h
+++ b/openhantek/src/openhantek.h
@@ -65,6 +65,10 @@ class OpenHantekMainWindow : public QMainWindow {
void createToolBars();
void createStatusBar();
void createDockWindows();
+
+ // Device management
+ void connectSignals();
+ void initializeDevice();
// Settings
int readSettings(const QString &fileName = QString());
@@ -81,8 +85,6 @@ class OpenHantekMainWindow : public QMainWindow {
QAction *configAction;
QAction *startStopAction;
- QActionGroup *recordLengthActionGroup;
- QAction *recordLengthSmallAction, *recordLengthLargeAction;
QAction *digitalPhosphorAction, *zoomAction;
QAction *aboutAction, *aboutQtAction;
@@ -94,7 +96,7 @@ class OpenHantekMainWindow : public QMainWindow {
// Menus
QMenu *fileMenu;
QMenu *viewMenu, *dockMenu, *toolbarMenu;
- QMenu *oscilloscopeMenu, *recordLengthMenu;
+ QMenu *oscilloscopeMenu;
QMenu *helpMenu;
// Toolbars
@@ -143,9 +145,12 @@ class OpenHantekMainWindow : public QMainWindow {
void applySettings();
void updateSettings();
- void recordLengthSelected(QAction *action);
+ void recordTimeChanged(double duration);
+ void samplerateChanged(double samplerate);
+ void recordLengthSelected(unsigned long recordLength);
+ void samplerateSelected();
+ void timebaseSelected();
void updateOffset(unsigned int channel);
- void updateTimebase();
void updateUsed(unsigned int channel);
void updateVoltageGain(unsigned int channel);
diff --git a/openhantek/src/settings.cpp b/openhantek/src/settings.cpp
index f382c42..f2cbf1e 100644
--- a/openhantek/src/settings.cpp
+++ b/openhantek/src/settings.cpp
@@ -64,8 +64,9 @@ DsoSettings::DsoSettings(QWidget *parent) : QObject(parent) {
this->scope.horizontal.marker[0] = -1.0;
this->scope.horizontal.marker[1] = 1.0;
this->scope.horizontal.timebase = 1e-3;
- this->scope.horizontal.samples = 10240;
+ this->scope.horizontal.recordLength = 0;
this->scope.horizontal.samplerate = 1e6;
+ this->scope.horizontal.samplerateSet = false;
// Trigger
this->scope.trigger.filter = true;
this->scope.trigger.mode = Dso::TRIGGERMODE_NORMAL;
@@ -276,6 +277,12 @@ int DsoSettings::load(const QString &fileName) {
}
if(settingsLoader->contains("timebase"))
this->scope.horizontal.timebase = settingsLoader->value("timebase").toDouble();
+ if(settingsLoader->contains("recordLength"))
+ this->scope.horizontal.recordLength = settingsLoader->value("recordLength").toUInt();
+ if(settingsLoader->contains("samplerate"))
+ this->scope.horizontal.samplerate = settingsLoader->value("samplerate").toDouble();
+ if(settingsLoader->contains("samplerateSet"))
+ this->scope.horizontal.samplerateSet = settingsLoader->value("samplerateSet").toBool();
settingsLoader->endGroup();
// Trigger
settingsLoader->beginGroup("trigger");
@@ -449,6 +456,9 @@ int DsoSettings::save(const QString &fileName) {
for(int marker = 0; marker < 2; ++marker)
settingsSaver->setValue(QString("marker%1").arg(marker), this->scope.horizontal.marker[marker]);
settingsSaver->setValue("timebase", this->scope.horizontal.timebase);
+ settingsSaver->setValue("recordLength", (unsigned int) this->scope.horizontal.recordLength);
+ settingsSaver->setValue("samplerate", this->scope.horizontal.samplerate);
+ settingsSaver->setValue("samplerateSet", this->scope.horizontal.samplerateSet);
settingsSaver->endGroup();
// Trigger
settingsSaver->beginGroup("trigger");
@@ -457,6 +467,7 @@ int DsoSettings::save(const QString &fileName) {
settingsSaver->setValue("position", this->scope.trigger.position);
settingsSaver->setValue("slope", this->scope.trigger.slope);
settingsSaver->setValue("source", this->scope.trigger.source);
+ settingsSaver->setValue("special", this->scope.trigger.special);
settingsSaver->endGroup();
// Spectrum
for(int channel = 0; channel < this->scope.spectrum.count(); ++channel) {
diff --git a/openhantek/src/settings.h b/openhantek/src/settings.h
index f4803d0..4746a0a 100644
--- a/openhantek/src/settings.h
+++ b/openhantek/src/settings.h
@@ -93,8 +93,9 @@ struct DsoSettingsScopeHorizontal {
double frequencybase; ///< Frequencybase in Hz/div
double marker[2]; ///< Marker positions in div
double timebase; ///< Timebase in s/div
- unsigned long int samples; ///< Sample count
- unsigned long int samplerate; ///< The samplerate of the oscilloscope in S
+ unsigned long int recordLength; ///< Sample count
+ double samplerate; ///< The samplerate of the oscilloscope in S
+ bool samplerateSet; ///< The samplerate was set by the user, not the timebase
};
////////////////////////////////////////////////////////////////////////////////
@@ -105,8 +106,8 @@ struct DsoSettingsScopeTrigger {
Dso::TriggerMode mode; ///< Automatic, normal or single trigger
double position; ///< Horizontal position for pretrigger
Dso::Slope slope; ///< Rising or falling edge causes trigger
- bool special; ///< true if the trigger source is not a standard channel
unsigned int source; ///< Channel that is used as trigger source
+ bool special; ///< true if the trigger source is not a standard channel
};
////////////////////////////////////////////////////////////////////////////////
diff --git a/openhantek/translations/openhantek_de.ts b/openhantek/translations/openhantek_de.ts
index 179d167..62394b1 100644
--- a/openhantek/translations/openhantek_de.ts
+++ b/openhantek/translations/openhantek_de.ts
@@ -270,67 +270,62 @@
DsoWidget
-
+
Zoom x%L1
Zoom x%L1
-
-
-
-
-
+
+
+
+
+
/div
/div
-
+
Portable Document Format (*.pdf)
Portables Dokumentenformat (*.pdf)
-
+
PostScript (*.ps)
PostScript (*.ps)
-
+
Export file...
Datei exportieren...
-
+
Marker 1/2
Marker 1/2
-
+
%L1%
%L1%
-
+
%1 %2 %3 %4
%1 %2 %3 %4
-
+
/s
/s
-
- %1 S
- %1 S
-
-
-
+
Image (*.png *.xpm *.jpg)
Bild (*.png *.xpm *.jpg)
-
+
Comma-Separated Values (*.csv)
Kommagetrennte Werte (*.csv)
@@ -343,42 +338,42 @@
Oszillograph drucken
-
+
%L1%
%L1%
-
+
%1 %2 %3 %4
%1 %2 %3 %4
-
+
%1 S
%1 S
-
+
/s
/s
-
-
-
-
-
+
+
+
+
+
/div
/div
-
+
Zoom x%L1
Zoom x%L1
-
+
Marker 1/2
Marker 1/2
@@ -386,27 +381,27 @@
Hantek::Control
-
+
EXT
EXT
-
+
EXT/10
EXT/10
-
+
The device has been disconnected
Die Verbindung zum Gerät wurde getrennt
-
+
Unknown model
Unbekanntes Modell
-
+
Couldn't get channel level data from oscilloscope
Konnte Kanalpegeldaten des Oszilloskops nicht lesen
@@ -414,41 +409,41 @@
Hantek::Device
-
+
Can't search for Hantek oscilloscopes: %1
Suche nach Hantek Oszilloskopen fehlgeschlagen: %1
-
-
+
+
Failed to claim interface %1 of device %2: %3
Anforderung der Schnittstelle %1 des Gerätes %2 fehlgeschlagen: %3
-
-
+
+
Device found: Hantek %1 (%2)
Gerät gefunden: Hantek %1 (%2)
-
+
Couldn't open device %1
Konnte Gerät %1 nicht öffnen
-
-
+
+
No Hantek oscilloscope found
Keine Hantek Oszilloskope gefunden
-
-
+
+
Failed to get device list: %1
Abrufen der Geräteliste fehlgeschlagen: %1
-
+
Couldn't open device %1: %2
Konnte Gerät %1 nicht öffnen: %2
@@ -456,25 +451,41 @@
HorizontalDock
-
+
Horizontal
Horizontal
-
+
+ Samplerate
+ Samplerate
+
+
+
Timebase
Zeitbasis
-
+
Frequencybase
Frequenzbasis
-
+
+ Record length
+ Satzlänge
+
+
+
Format
Format
+
+
+
+ Roll
+ Rollen
+
OpenHantekMainWindow
@@ -484,289 +495,264 @@
OpenHantek
-
+
&Open...
&Öffnen...
-
+
Ctrl+O
Strg+O
-
+
Open saved settings
Gespeicherte Einstellungen öffnen
-
+
&Save
&Speichern
-
-
+
+
Ctrl+S
Strg+S
-
+
Save the current settings
Aktuelle Einstellungen speichern
-
+
Save &as...
Speichern &unter...
-
+
Save the current settings to another file
Aktuelle Einstellungen in anderer Datei speichern
-
+
&Print...
&Drucken...
-
+
Ctrl+P
Strg+P
-
+
Print the oscilloscope screen
Den Oscilloskopbildschirm drucken
-
+
&Export as...
&Exportieren als...
-
+
Ctrl+E
Strg+E
-
+
Export the oscilloscope data to a file
Die Oszilloskopdaten in eine Datei exportieren
-
+
E&xit
&Beenden
-
+
Ctrl+Q
Strg+Q
-
+
Exit the application
Anwendung beenden
-
+
&Settings
&Einstellungen
-
+
Configure the oscilloscope
Das Oszilloskop konfigurieren
-
+
Send command
Befehl senden
-
+
Shift+C
Shift+C
-
+
&Docking windows
&Dockfenster
-
+
&Toolbars
&Werkzeugleisten
-
-
+
+
Settings (*.ini)
Einstellungen (*.ini)
-
+
Save settings
Einstellungen speichern
-
+
&Stop
&Stop
-
+
<p>This is a open source software for Hantek USB oscilloscopes.</p><p>Copyright © 2010, 2011 Oliver Haag <oliver.haag@gmail.com></p>
<p>Dies ist ein Open-Source Programm für Hantek USB Oszilloskope.</p><p>Copyright © 2010, 2011 Oliver Haag <oliver.haag@gmail.com></p>
-
+
Invalid command
Ungültiger Befehl
-
+
Space
Leertaste
-
+
Stop the oscilloscope
Das Oszilloskop anhalten
-
- &Small
- &Klein
-
-
-
- 10240 Samples
- 10240 Werte
-
-
-
- &Large
- &Groß
-
-
-
- 32768 Samples
- 32768 Werte
-
-
-
+
Digital &phosphor
Digitaler &Phosphor
-
+
&Zoom
&Zoom
-
+
&About
&Über
-
+
Show information about this program
Zeige Informationen über dieses Programm
-
+
About &Qt
Über &Qt
-
+
Show the Qt library's About box
Zeige Dialog zur Qt Bibliothek
-
+
&File
&Datei
-
+
&View
&Ansicht
-
+
&Oscilloscope
&Oszilloskop
-
- &Buffer size
- &Puffergröße
-
-
-
+
&Help
&Hilfe
-
+
File
Datei
-
+
Oscilloscope
Oszilloskop
-
+
View
Ansicht
-
+
Ready
Bereit
-
+
Open file
Datei öffnen
-
+
&Start
&Start
-
+
Start the oscilloscope
Startet das Oszilloskop
-
+
Disable fading of previous graphs
Nachleuchten von vorigen Graphen deaktivieren
-
+
Enable fading of previous graphs
Nachleuchten von vorigen Graphen aktivieren
-
+
Hide magnified scope
Vergrößerte Anzeige ausblenden
-
+
Show magnified scope
Vergrößerte Anzeige anzeigen
-
+
About OpenHantek %1
*ber OpenHantek %1
@@ -774,187 +760,187 @@
QApplication
-
+
Success (no error)
Erfolgreich (Kein Fehler)
-
+
Input/output error
Ein-/Ausgabe Fehler
-
+
Invalid parameter
Ungültiger Parameter
-
+
Access denied (insufficient permissions)
Zugriff verweigert (Unzureichende Berechtigungen)
-
+
No such device (it may have been disconnected)
Gerät nicht vorhanden (Möglicherweise wurde es abgesteckt)
-
+
Entity not found
Datensatz nicht gefunden
-
+
Resource busy
Quelle belegt
-
+
Operation timed out
Zeitüberschreitung
-
+
Overflow
Überlauf
-
+
Pipe error
Leitungsfehler
-
+
System call interrupted (perhaps due to signal)
Systemaufruf unterbrochen (Möglicherweise aufgrund eines Signals)
-
+
Insufficient memory
Unzureichender Speicher
-
+
Operation not supported or unimplemented on this platform
Vorgang auf diesem System nicht unterstützt oder nicht implementiert
-
+
Other error
Anderer Fehler
-
+
%L1 µV
%L1 µV
-
+
%L1 mV
%L1 mV
-
+
%L1 V
%L1 V
-
+
%L1 dB
%L1 dB
-
+
%L1 ps
%L1 ps
-
+
%L1 ns
%L1 ns
-
+
%L1 µs
%L1 µs
-
+
%L1 ms
%L1 ms
-
+
%L1 s
%L1 s
-
+
%L1 min
%L1 min
-
+
%L1 h
%L1 h
-
+
%L1 Hz
%L1 Hz
-
+
%L1 kHz
%L1 kHz
-
+
%L1 MHz
%L1 MHz
-
+
%L1 GHz
%L1 GHz
-
+
%L1 S
%L1 S
-
+
%L1 kS
%L1 kS
-
+
%L1 MS
%L1 MS
-
+
%L1 GS
%L1 GS
-
+
CH%1
CH%1
-
+
SP%1
SP%1
-
+
MATH
MATH
-
+
SPM
SPM
@@ -1112,7 +1098,7 @@
SpectrumDock
-
+
Spectrum
Spektrum
@@ -1120,27 +1106,27 @@
TriggerDock
-
+
Trigger
Trigger
-
+
CH%1
CH%1
-
+
Mode
Modus
-
+
Slope
Flanke
-
+
Source
Quelle
@@ -1148,7 +1134,7 @@
VoltageDock
-
+
Voltage
Spannung
--
libgit2 0.21.4