Commit d52c9b8280c05d6b0add84dd2005024eb25db356

Authored by oliverhaag
1 parent 8ee5d2fc

Record length and samplerate can be set

openhantek/ChangeLog
... ... @@ -183,3 +183,12 @@
183 183  
184 184 2012-11-21 Oliver Haag <oliver.haag@gmail.com>
185 185 * Bugfix: DSO-2250 detection failed
  186 +
  187 +2012-11-25 Oliver Haag <oliver.haag@gmail.com>
  188 +* Added samplerate spinbox to horizontal dock
  189 +* Moved record length selection from menu into horizontal dock
  190 +* Large rework to allow setting either samplerate or timebase
  191 +* Calculate the samplerate depending on the set parameter and the record length
  192 +* Added signals to DsoControl to update horizontal dock automatically
  193 +* Reworks in signal connections to make this work properly
  194 +* Bugfix: DSO-2250 used channels wasn't set
... ...
openhantek/roadmap.dox
... ... @@ -17,11 +17,18 @@ Released February 9, 2011
17 17 </ul>
18 18  
19 19 \section sec_0_3 OpenHantek 0.3.0
20   -Planned Q2/Q3, 2011
  20 +Planned Q1, 2013
21 21 <ul>
22 22 <li>%Hantek DSO-2250 support</li>
23   - <li>USB hotplugging</li>
  23 + <li>Proper support for different record lengths</li>
  24 + <li>Arbitrary samplerate support</li>
  25 +</ul>
  26 +
  27 +\section sec_0_4 OpenHantek 0.4.0
  28 +<ul>
24 29 <li>Improved zoom functionality</li>
  30 + <li>Self alignment routines</li>
  31 + <li>USB hotplugging</li>
25 32 </ul>
26 33  
27 34 **/
... ...
openhantek/src/dataanalyzer.cpp
... ... @@ -139,7 +139,7 @@ void DataAnalyzer::run() {
139 139 // Set sampling interval
140 140 channelData->samples.voltage.interval = 1.0 / this->waitingDataSamplerate;
141 141  
142   - unsigned int size;
  142 + unsigned long int size;
143 143 if(channel < this->settings->scope.physicalChannels) {
144 144 size = this->waitingDataSize[channel];
145 145 if(size > maxSamples)
... ... @@ -159,7 +159,7 @@ void DataAnalyzer::run() {
159 159 if(channel < this->settings->scope.physicalChannels) {
160 160 // Copy the buffer of the oscilloscope into the sample buffer
161 161 if(channel < (unsigned int) this->waitingData.count())
162   - for(unsigned int position = 0; position < this->waitingDataSize[channel]; ++position)
  162 + for(unsigned long int position = 0; position < this->waitingDataSize[channel]; ++position)
163 163 channelData->samples.voltage.sample[position] = this->waitingData[channel][position];
164 164 }
165 165 // Math channel
... ... @@ -176,7 +176,7 @@ void DataAnalyzer::run() {
176 176 }
177 177  
178 178 // Calculate values and write them into the sample buffer
179   - for(unsigned int realPosition = 0; realPosition < this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count; ++realPosition) {
  179 + for(unsigned long int realPosition = 0; realPosition < this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count; ++realPosition) {
180 180 switch(this->settings->scope.voltage[this->settings->scope.physicalChannels].misc) {
181 181 case Dso::MATHMODE_1ADD2:
182 182 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() {
223 223 this->window = (double *) fftw_malloc(sizeof(double) * this->lastRecordLength);
224 224 }
225 225  
226   - unsigned int windowEnd = this->lastRecordLength - 1;
  226 + unsigned long int windowEnd = this->lastRecordLength - 1;
227 227 this->lastWindow = this->settings->scope.spectrumWindow;
228 228  
229 229 switch(this->settings->scope.spectrumWindow) {
230 230 case Dso::WINDOW_HAMMING:
231   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  231 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
232 232 *(this->window + windowPosition) = 0.54 - 0.46 * cos(2.0 * M_PI * windowPosition / windowEnd);
233 233 break;
234 234 case Dso::WINDOW_HANN:
235   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  235 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
236 236 *(this->window + windowPosition) = 0.5 * (1.0 - cos(2.0 * M_PI * windowPosition / windowEnd));
237 237 break;
238 238 case Dso::WINDOW_COSINE:
239   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  239 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
240 240 *(this->window + windowPosition) = sin(M_PI * windowPosition / windowEnd);
241 241 break;
242 242 case Dso::WINDOW_LANCZOS:
243   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition) {
  243 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition) {
244 244 double sincParameter = (2.0 * windowPosition / windowEnd - 1.0) * M_PI;
245 245 if(sincParameter == 0)
246 246 *(this->window + windowPosition) = 1;
... ... @@ -249,55 +249,55 @@ void DataAnalyzer::run() {
249 249 }
250 250 break;
251 251 case Dso::WINDOW_BARTLETT:
252   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  252 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
253 253 *(this->window + windowPosition) = 2.0 / windowEnd * (windowEnd / 2 - abs(windowPosition - windowEnd / 2));
254 254 break;
255 255 case Dso::WINDOW_TRIANGULAR:
256   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  256 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
257 257 *(this->window + windowPosition) = 2.0 / this->lastRecordLength * (this->lastRecordLength / 2 - abs(windowPosition - windowEnd / 2));
258 258 break;
259 259 case Dso::WINDOW_GAUSS:
260 260 {
261 261 double sigma = 0.4;
262   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  262 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
263 263 *(this->window + windowPosition) = exp(-0.5 * pow(((windowPosition - windowEnd / 2) / (sigma * windowEnd / 2)), 2));
264 264 }
265 265 break;
266 266 case Dso::WINDOW_BARTLETTHANN:
267   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  267 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
268 268 *(this->window + windowPosition) = 0.62 - 0.48 * abs(windowPosition / windowEnd - 0.5) - 0.38 * cos(2.0 * M_PI * windowPosition / windowEnd);
269 269 break;
270 270 case Dso::WINDOW_BLACKMAN:
271 271 {
272 272 double alpha = 0.16;
273   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  273 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
274 274 *(this->window + windowPosition) = (1 - alpha) / 2 - 0.5 * cos(2.0 * M_PI * windowPosition / windowEnd) + alpha / 2 * cos(4.0 * M_PI * windowPosition / windowEnd);
275 275 }
276 276 break;
277 277 //case WINDOW_KAISER:
278 278 // TODO
279 279 //double alpha = 3.0;
280   - //for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  280 + //for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
281 281 //*(this->window + windowPosition) = ;
282 282 //break;
283 283 case Dso::WINDOW_NUTTALL:
284   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  284 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
285 285 *(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);
286 286 break;
287 287 case Dso::WINDOW_BLACKMANHARRIS:
288   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  288 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
289 289 *(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);
290 290 break;
291 291 case Dso::WINDOW_BLACKMANNUTTALL:
292   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  292 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
293 293 *(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);
294 294 break;
295 295 case Dso::WINDOW_FLATTOP:
296   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  296 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
297 297 *(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);
298 298 break;
299 299 default: // Dso::WINDOW_RECTANGULAR
300   - for(unsigned int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
  300 + for(unsigned long int windowPosition = 0; windowPosition < this->lastRecordLength; ++windowPosition)
301 301 *(this->window + windowPosition) = 1.0;
302 302 }
303 303 }
... ... @@ -306,7 +306,7 @@ void DataAnalyzer::run() {
306 306 channelData->samples.spectrum.interval = 1.0 / channelData->samples.voltage.interval / channelData->samples.voltage.count;
307 307  
308 308 // Number of real/complex samples
309   - unsigned int dftLength = channelData->samples.voltage.count / 2;
  309 + unsigned long int dftLength = channelData->samples.voltage.count / 2;
310 310  
311 311 // Reallocate memory for samples if the sample count has changed
312 312 if(channelData->samples.spectrum.count != dftLength) {
... ... @@ -318,7 +318,7 @@ void DataAnalyzer::run() {
318 318  
319 319 // Create sample buffer and apply window
320 320 double *windowedValues = new double[channelData->samples.voltage.count];
321   - for(unsigned int position = 0; position < channelData->samples.voltage.count; ++position)
  321 + for(unsigned long int position = 0; position < channelData->samples.voltage.count; ++position)
322 322 windowedValues[position] = this->window[position] * channelData->samples.voltage.sample[position];
323 323  
324 324 // Do discrete real to half-complex transformation
... ... @@ -332,7 +332,7 @@ void DataAnalyzer::run() {
332 332 double *conjugateComplex = windowedValues; // Reuse the windowedValues buffer
333 333  
334 334 // Real values
335   - unsigned int position;
  335 + unsigned long int position;
336 336 double correctionFactor = 1.0 / dftLength / dftLength;
337 337 conjugateComplex[0] = (channelData->samples.spectrum.sample[0] * channelData->samples.spectrum.sample[0]) * correctionFactor;
338 338 for(position = 1; position < dftLength; ++position)
... ... @@ -353,7 +353,7 @@ void DataAnalyzer::run() {
353 353 double minimalVoltage, maximalVoltage;
354 354 minimalVoltage = maximalVoltage = channelData->samples.voltage.sample[0];
355 355  
356   - for(unsigned int position = 1; position < channelData->samples.voltage.count; ++position) {
  356 + for(unsigned long int position = 1; position < channelData->samples.voltage.count; ++position) {
357 357 if(channelData->samples.voltage.sample[position] < minimalVoltage)
358 358 minimalVoltage = channelData->samples.voltage.sample[position];
359 359 else if(channelData->samples.voltage.sample[position] > maximalVoltage)
... ... @@ -365,9 +365,9 @@ void DataAnalyzer::run() {
365 365 // Get the frequency from the correlation results
366 366 double minimumCorrelation = correlation[0];
367 367 double peakCorrelation = 0;
368   - unsigned int peakPosition = 0;
  368 + unsigned long int peakPosition = 0;
369 369  
370   - for(unsigned int position = 1; position < channelData->samples.voltage.count / 2; ++position) {
  370 + for(unsigned long int position = 1; position < channelData->samples.voltage.count / 2; ++position) {
371 371 if(correlation[position] > peakCorrelation && correlation[position] > minimumCorrelation * 2) {
372 372 peakCorrelation = correlation[position];
373 373 peakPosition = position;
... ... @@ -388,7 +388,7 @@ void DataAnalyzer::run() {
388 388 // Convert values into dB (Relative to the reference level)
389 389 double offset = 60 - this->settings->scope.spectrumReference - 20 * log10(dftLength);
390 390 double offsetLimit = this->settings->scope.spectrumLimit - this->settings->scope.spectrumReference;
391   - for(unsigned int position = 0; position < channelData->samples.spectrum.count; ++position) {
  391 + for(unsigned long int position = 0; position < channelData->samples.spectrum.count; ++position) {
392 392 channelData->samples.spectrum.sample[position] = 20 * log10(fabs(channelData->samples.spectrum.sample[position])) + offset;
393 393  
394 394 // Check if this value has to be limited
... ... @@ -417,7 +417,7 @@ void DataAnalyzer::run() {
417 417 /// \param size The sizes of the data arrays.
418 418 /// \param samplerate The samplerate for all input data.
419 419 /// \param mutex The mutex for all input data.
420   -void DataAnalyzer::analyze(const QList<double *> *data, const QList<unsigned int> *size, double samplerate, QMutex *mutex) {
  420 +void DataAnalyzer::analyze(const QList<double *> *data, const QList<unsigned long int> *size, double samplerate, QMutex *mutex) {
421 421 // Previous analysis still running, drop the new data
422 422 if(this->isRunning())
423 423 return;
... ...
openhantek/src/dataanalyzer.h
... ... @@ -95,15 +95,15 @@ class DataAnalyzer : public QThread {
95 95 double *window; ///< The array for the dft window factors
96 96  
97 97 QList<double *> waitingData; ///< Pointer to input data from device
98   - QList<unsigned int> waitingDataSize; ///< Number of input data samples
  98 + QList<unsigned long int> waitingDataSize; ///< Number of input data samples
99 99 double waitingDataSamplerate; ///< The samplerate of the input data
100 100 QMutex *waitingDataMutex; ///< A mutex for the input data
101 101  
102 102 public slots:
103   - void analyze(const QList<double *> *data, const QList<unsigned int> *size, double samplerate, QMutex *mutex);
  103 + void analyze(const QList<double *> *data, const QList<unsigned long int> *size, double samplerate, QMutex *mutex);
104 104  
105 105 signals:
106   - void analyzed(unsigned int samples); ///< The data with that much samples has been analyzed
  106 + void analyzed(unsigned long samples); ///< The data with that much samples has been analyzed
107 107 };
108 108  
109 109 #endif
... ...
openhantek/src/dockwindows.cpp
... ... @@ -46,20 +46,29 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
46 46 this->settings = settings;
47 47  
48 48 // Initialize elements
  49 + this->samplerateLabel = new QLabel(tr("Samplerate"));
  50 + this->samplerateSiSpinBox = new SiSpinBox(Helper::UNIT_SAMPLES);
  51 + this->samplerateSiSpinBox->setMinimum(1);
  52 + this->samplerateSiSpinBox->setMaximum(1e8);
  53 + this->samplerateSiSpinBox->setUnitPostfix("/s");
  54 +
  55 + QList<double> timebaseSteps;
  56 + timebaseSteps << 1.0 << 2.0 << 4.0 << 10.0;
  57 +
49 58 this->timebaseLabel = new QLabel(tr("Timebase"));
50 59 this->timebaseSiSpinBox = new SiSpinBox(Helper::UNIT_SECONDS);
  60 + this->timebaseSiSpinBox->setSteps(timebaseSteps);
51 61 this->timebaseSiSpinBox->setMinimum(1e-9);
52 62 this->timebaseSiSpinBox->setMaximum(3.6e3);
53 63  
54   - QList<double> frequencybaseSteps;
55   - frequencybaseSteps << 1.0 << 2.0 << 5.0 << 10.0;
56   -
57 64 this->frequencybaseLabel = new QLabel(tr("Frequencybase"));
58 65 this->frequencybaseSiSpinBox = new SiSpinBox(Helper::UNIT_HERTZ);
59   - this->frequencybaseSiSpinBox->setSteps(frequencybaseSteps);
60 66 this->frequencybaseSiSpinBox->setMinimum(1.0);
61 67 this->frequencybaseSiSpinBox->setMaximum(100e6);
62 68  
  69 + this->recordLengthLabel = new QLabel(tr("Record length"));
  70 + this->recordLengthComboBox = new QComboBox();
  71 +
63 72 this->formatLabel = new QLabel(tr("Format"));
64 73 this->formatComboBox = new QComboBox();
65 74 for(int format = Dso::GRAPHFORMAT_TY; format < Dso::GRAPHFORMAT_COUNT; ++format)
... ... @@ -68,12 +77,16 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
68 77 this->dockLayout = new QGridLayout();
69 78 this->dockLayout->setColumnMinimumWidth(0, 64);
70 79 this->dockLayout->setColumnStretch(1, 1);
71   - this->dockLayout->addWidget(this->timebaseLabel, 0, 0);
72   - this->dockLayout->addWidget(this->timebaseSiSpinBox, 0, 1);
73   - this->dockLayout->addWidget(this->frequencybaseLabel, 1, 0);
74   - this->dockLayout->addWidget(this->frequencybaseSiSpinBox, 1, 1);
75   - this->dockLayout->addWidget(this->formatLabel, 2, 0);
76   - this->dockLayout->addWidget(this->formatComboBox, 2, 1);
  80 + this->dockLayout->addWidget(this->samplerateLabel, 0, 0);
  81 + this->dockLayout->addWidget(this->samplerateSiSpinBox, 0, 1);
  82 + this->dockLayout->addWidget(this->timebaseLabel, 1, 0);
  83 + this->dockLayout->addWidget(this->timebaseSiSpinBox, 1, 1);
  84 + this->dockLayout->addWidget(this->frequencybaseLabel, 2, 0);
  85 + this->dockLayout->addWidget(this->frequencybaseSiSpinBox, 2, 1);
  86 + this->dockLayout->addWidget(this->recordLengthLabel, 3, 0);
  87 + this->dockLayout->addWidget(this->recordLengthComboBox, 3, 1);
  88 + this->dockLayout->addWidget(this->formatLabel, 4, 0);
  89 + this->dockLayout->addWidget(this->formatComboBox, 4, 1);
77 90  
78 91 this->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
79 92  
... ... @@ -82,13 +95,17 @@ HorizontalDock::HorizontalDock(DsoSettings *settings, QWidget *parent, Qt::Windo
82 95 this->setWidget(this->dockWidget);
83 96  
84 97 // Connect signals and slots
85   - connect(this->frequencybaseSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(frequencybaseSelected(double)));
  98 + connect(this->samplerateSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(samplerateSelected(double)));
86 99 connect(this->timebaseSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(timebaseSelected(double)));
  100 + connect(this->frequencybaseSiSpinBox, SIGNAL(valueChanged(double)), this, SLOT(frequencybaseSelected(double)));
  101 + connect(this->recordLengthComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(recordLengthSelected(int)));
87 102 connect(this->formatComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(formatSelected(int)));
88 103  
89 104 // Set values
  105 + this->setSamplerate(this->settings->scope.horizontal.samplerate);
90 106 this->setTimebase(this->settings->scope.horizontal.timebase);
91 107 this->setFrequencybase(this->settings->scope.horizontal.frequencybase);
  108 + this->setRecordLength(this->settings->scope.horizontal.recordLength);
92 109 this->setFormat(this->settings->scope.horizontal.format);
93 110 }
94 111  
... ... @@ -104,16 +121,40 @@ void HorizontalDock::closeEvent(QCloseEvent *event) {
104 121 event->accept();
105 122 }
106 123  
107   -/// \brief Changes the frequencybase if the new value is supported.
  124 +/// \brief Changes the frequencybase.
108 125 /// \param frequencybase The frequencybase in hertz.
109 126 void HorizontalDock::setFrequencybase(double frequencybase) {
  127 + this->suppressSignals = true;
110 128 this->frequencybaseSiSpinBox->setValue(frequencybase);
  129 + this->suppressSignals = false;
111 130 }
112 131  
113   -/// \brief Changes the timebase if the new value is supported.
  132 +/// \brief Changes the samplerate.
  133 +/// \param samplerate The samplerate in seconds.
  134 +void HorizontalDock::setSamplerate(double samplerate) {
  135 + this->suppressSignals = true;
  136 + this->samplerateSiSpinBox->setValue(samplerate);
  137 + this->suppressSignals = false;
  138 +}
  139 +
  140 +/// \brief Changes the timebase.
114 141 /// \param timebase The timebase in seconds.
115 142 void HorizontalDock::setTimebase(double timebase) {
  143 + this->suppressSignals = true;
116 144 this->timebaseSiSpinBox->setValue(timebase);
  145 + this->suppressSignals = false;
  146 +}
  147 +
  148 +/// \brief Changes the record length if the new value is supported.
  149 +/// \param recordLength The record length in samples.
  150 +void HorizontalDock::setRecordLength(unsigned long int recordLength) {
  151 + int index = this->recordLengthComboBox->findData((uint) recordLength); // QVariant doesn't take unsigned long int, doesn't matter for 32 bit platforms at least
  152 +
  153 + if(index != -1) {
  154 + this->suppressSignals = true;
  155 + this->recordLengthComboBox->setCurrentIndex(index);
  156 + this->suppressSignals = false;
  157 + }
117 158 }
118 159  
119 160 /// \brief Changes the format if the new value is supported.
... ... @@ -121,32 +162,96 @@ void HorizontalDock::setTimebase(double timebase) {
121 162 /// \return Index of format-value, -1 on error.
122 163 int HorizontalDock::setFormat(Dso::GraphFormat format) {
123 164 if(format >= Dso::GRAPHFORMAT_TY && format <= Dso::GRAPHFORMAT_XY) {
  165 + this->suppressSignals = true;
124 166 this->formatComboBox->setCurrentIndex(format);
  167 + this->suppressSignals = false;
125 168 return format;
126 169 }
127 170  
128 171 return -1;
129 172 }
130 173  
131   -/// \brief Called when the frequencybase combo box changes it's value.
  174 +/// \brief Updates the available record lengths in the combo box.
  175 +/// \param recordLengths The available record lengths for the combo box.
  176 +void HorizontalDock::availableRecordLengthsChanged(const QList<unsigned long int> &recordLengths) {
  177 + /// \todo Empty lists should be interpreted as scope supporting continuous record length values.
  178 + this->recordLengthComboBox->blockSignals(true); // Avoid messing up the settings
  179 + this->recordLengthComboBox->setUpdatesEnabled(false);
  180 +
  181 + // Update existing elements to avoid unnecessary index updates
  182 + int index = 0;
  183 + for(; index < recordLengths.size(); ++index) {
  184 + unsigned long int recordLengthItem = recordLengths[index];
  185 + if(index < this->recordLengthComboBox->count()) {
  186 + this->recordLengthComboBox->setItemData(index, (unsigned int) recordLengthItem);
  187 + this->recordLengthComboBox->setItemText(index, recordLengthItem == ULONG_MAX ? tr("Roll") : Helper::valueToString(recordLengthItem, Helper::UNIT_SAMPLES, 3));
  188 + }
  189 + else {
  190 + this->recordLengthComboBox->addItem(recordLengthItem == ULONG_MAX ? tr("Roll") : Helper::valueToString(recordLengthItem, Helper::UNIT_SAMPLES, 3), (uint) recordLengthItem);
  191 + }
  192 + }
  193 + // Remove extra elements
  194 + for(int extraIndex = this->recordLengthComboBox->count() - 1; extraIndex > index; --extraIndex) {
  195 + this->recordLengthComboBox->removeItem(extraIndex);
  196 + }
  197 +
  198 + this->setRecordLength(this->settings->scope.horizontal.recordLength);
  199 + this->recordLengthComboBox->setUpdatesEnabled(true);
  200 + this->recordLengthComboBox->blockSignals(false);
  201 +}
  202 +
  203 +/// \brief Updates the minimum and maximum of the samplerate spin box.
  204 +/// \param minimum The minimum value the spin box should accept.
  205 +/// \param maximum The minimum value the spin box should accept.
  206 +void HorizontalDock::samplerateLimitsChanged(double minimum, double maximum) {
  207 + this->suppressSignals = true;
  208 + this->samplerateSiSpinBox->setMinimum(minimum);
  209 + this->samplerateSiSpinBox->setMaximum(maximum);
  210 + this->suppressSignals = false;
  211 +}
  212 +
  213 +/// \brief Called when the frequencybase spinbox changes its value.
132 214 /// \param frequencybase The frequencybase in hertz.
133 215 void HorizontalDock::frequencybaseSelected(double frequencybase) {
134 216 this->settings->scope.horizontal.frequencybase = frequencybase;
135   - emit frequencybaseChanged(frequencybase);
  217 + if(!this->suppressSignals)
  218 + emit frequencybaseChanged(frequencybase);
136 219 }
137 220  
138   -/// \brief Called when the timebase combo box changes it's value.
  221 +/// \brief Called when the samplerate spinbox changes its value.
  222 +/// \param samplerate The samplerate in samples/second.
  223 +void HorizontalDock::samplerateSelected(double samplerate) {
  224 + this->settings->scope.horizontal.samplerate = samplerate;
  225 + if(!this->suppressSignals) {
  226 + this->settings->scope.horizontal.samplerateSet = true;
  227 + emit samplerateChanged(samplerate);
  228 + }
  229 +}
  230 +
  231 +/// \brief Called when the timebase spinbox changes its value.
139 232 /// \param timebase The timebase in seconds.
140 233 void HorizontalDock::timebaseSelected(double timebase) {
141 234 this->settings->scope.horizontal.timebase = timebase;
142   - emit timebaseChanged(timebase);
  235 + if(!this->suppressSignals) {
  236 + this->settings->scope.horizontal.samplerateSet = false;
  237 + emit timebaseChanged(timebase);
  238 + }
  239 +}
  240 +
  241 +/// \brief Called when the record length combo box changes its value.
  242 +/// \param index The index of the combo box item.
  243 +void HorizontalDock::recordLengthSelected(int index) {
  244 + this->settings->scope.horizontal.recordLength = this->recordLengthComboBox->itemData(index).toUInt();
  245 + if(!this->suppressSignals)
  246 + emit recordLengthChanged(index);
143 247 }
144 248  
145   -/// \brief Called when the format combo box changes it's value.
  249 +/// \brief Called when the format combo box changes its value.
146 250 /// \param index The index of the combo box item.
147 251 void HorizontalDock::formatSelected(int index) {
148 252 this->settings->scope.horizontal.format = (Dso::GraphFormat) index;
149   - emit formatChanged(this->settings->scope.horizontal.format);
  253 + if(!this->suppressSignals)
  254 + emit formatChanged(this->settings->scope.horizontal.format);
150 255 }
151 256  
152 257  
... ...
openhantek/src/dockwindows.h
... ... @@ -54,7 +54,9 @@ class HorizontalDock : public QDockWidget {
54 54 ~HorizontalDock();
55 55  
56 56 void setFrequencybase(double timebase);
  57 + void setSamplerate(double samplerate);
57 58 void setTimebase(double timebase);
  59 + void setRecordLength(unsigned long int recordLength);
58 60 int setFormat(Dso::GraphFormat format);
59 61  
60 62 protected:
... ... @@ -62,25 +64,39 @@ class HorizontalDock : public QDockWidget {
62 64  
63 65 QGridLayout *dockLayout; ///< The main layout for the dock window
64 66 QWidget *dockWidget; ///< The main widget for the dock window
65   - QLabel *timebaseLabel; ///< The label for the timebase combobox
66   - QLabel *frequencybaseLabel; ///< The label for the frequencybase combobox
  67 + QLabel *samplerateLabel; ///< The label for the samplerate spinbox
  68 + QLabel *timebaseLabel; ///< The label for the timebase spinbox
  69 + QLabel *frequencybaseLabel; ///< The label for the frequencybase spinbox
  70 + QLabel *recordLengthLabel; ///< The label for the record length combobox
67 71 QLabel *formatLabel; ///< The label for the format combobox
  72 + SiSpinBox *samplerateSiSpinBox; ///< Selects the samplerate for aquisitions
68 73 SiSpinBox *timebaseSiSpinBox; ///< Selects the timebase for voltage graphs
69 74 SiSpinBox *frequencybaseSiSpinBox; ///< Selects the frequencybase for spectrum graphs
  75 + QComboBox *recordLengthComboBox; ///< Selects the record length for aquisitions
70 76 QComboBox *formatComboBox; ///< Selects the way the sampled data is interpreted and shown
71 77  
72 78 DsoSettings *settings; ///< The settings provided by the parent class
73 79  
74 80 QStringList formatStrings; ///< Strings for the formats
  81 +
  82 + bool suppressSignals; ///< Disable changed-signals temporarily
75 83  
  84 + public slots:
  85 + void availableRecordLengthsChanged(const QList<unsigned long int> &recordLengths);
  86 + void samplerateLimitsChanged(double minimum, double maximum);
  87 +
76 88 protected slots:
77 89 void frequencybaseSelected(double frequencybase);
  90 + void samplerateSelected(double samplerate);
78 91 void timebaseSelected(double timebase);
  92 + void recordLengthSelected(int index);
79 93 void formatSelected(int index);
80 94  
81 95 signals:
82 96 void frequencybaseChanged(double frequencybase); ///< The frequencybase has been changed
  97 + void samplerateChanged(double samplerate); ///< The samplerate has been changed
83 98 void timebaseChanged(double timebase); ///< The timebase has been changed
  99 + void recordLengthChanged(unsigned long recordLength); ///< The recordd length has been changed
84 100 void formatChanged(Dso::GraphFormat format); ///< The viewing format has been changed
85 101 };
86 102  
... ...
openhantek/src/dsocontrol.h
... ... @@ -47,6 +47,9 @@ class DsoControl : public QThread {
47 47 DsoControl(QObject *parent = 0);
48 48  
49 49 virtual unsigned int getChannelCount() = 0; ///< Get the number of channels for this oscilloscope
  50 + virtual QList<unsigned long int> *getAvailableRecordLengths() = 0; ///< Get available record lengths, empty list for continuous
  51 + virtual double getMinSamplerate() = 0; ///< The minimum samplerate supported
  52 + virtual double getMaxSamplerate() = 0; ///< The maximum samplerate supported
50 53  
51 54 const QStringList *getSpecialTriggerSources();
52 55  
... ... @@ -62,7 +65,13 @@ class DsoControl : public QThread {
62 65 void samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger
63 66 void samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger
64 67 void statusMessage(const QString &message, int timeout); ///< Status message about the oscilloscope
65   - void samplesAvailable(const QList<double *> *data, const QList<unsigned int> *size, double samplerate, QMutex *mutex); ///< New sample data is available
  68 + void samplesAvailable(const QList<double *> *data, const QList<unsigned long int> *size, double samplerate, QMutex *mutex); ///< New sample data is available
  69 +
  70 + void recordLengthChanged(unsigned long duration); ///< The record length has changed
  71 + void recordTimeChanged(double duration); ///< The record time duration has changed
  72 + void samplerateChanged(double samplerate); ///< The samplerate has changed
  73 + void availableRecordLengthsChanged(const QList<unsigned long int> &recordLengths); ///< The available record lengths, empty list for continuous
  74 + void samplerateLimitsChanged(double minimum, double maximum); ///< The minimum or maximum samplerate has changed
66 75  
67 76 public slots:
68 77 virtual void connectDevice();
... ... @@ -71,8 +80,9 @@ class DsoControl : public QThread {
71 80 virtual void startSampling();
72 81 virtual void stopSampling();
73 82  
74   - virtual unsigned long int setSamplerate(unsigned long int samplerate) = 0; ///< Set the samplerate that should be met
75   - virtual unsigned long int setRecordLength(unsigned long int size) = 0; ///< Set the required record length
  83 + virtual unsigned long int setRecordLength(unsigned long int size) = 0; ///< Set record length id, minimum for continuous
  84 + virtual double setSamplerate(double samplerate) = 0; ///< Set the samplerate that should be met
  85 + virtual double setRecordTime(double duration) = 0; ///< Set the record time duration that should be met
76 86  
77 87 virtual int setTriggerMode(Dso::TriggerMode mode) = 0; ///< Set the trigger mode
78 88 virtual int setTriggerSource(bool special, unsigned int id) = 0; ///< Set the trigger source
... ...
openhantek/src/dsowidget.cpp
... ... @@ -225,9 +225,10 @@ DsoWidget::DsoWidget(DsoSettings *settings, DataAnalyzer *dataAnalyzer, QWidget
225 225  
226 226 // Apply settings and update measured values
227 227 this->updateTriggerDetails();
228   - this->updateRecordLength(this->settings->scope.horizontal.samples);
229   - this->updateFrequencybase();
230   - this->updateTimebase();
  228 + this->updateRecordLength(this->settings->scope.horizontal.recordLength);
  229 + this->updateFrequencybase(this->settings->scope.horizontal.frequencybase);
  230 + this->updateSamplerate(this->settings->scope.horizontal.samplerate);
  231 + this->updateTimebase(this->settings->scope.horizontal.timebase);
231 232 this->updateZoom(this->settings->view.zoom);
232 233  
233 234 // The widget itself
... ... @@ -245,8 +246,8 @@ DsoWidget::DsoWidget(DsoSettings *settings, DataAnalyzer *dataAnalyzer, QWidget
245 246 this->connect(this->markerSlider, SIGNAL(valueChanged(int, double)), this->zoomScope, SLOT(updateGL()));
246 247  
247 248 // Connect other signals
248   - this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned int)), this, SLOT(dataAnalyzed()));
249   - this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned int)), this, SLOT(updateRecordLength(unsigned int)));
  249 + this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned long)), this, SLOT(dataAnalyzed()));
  250 + this->connect(this->dataAnalyzer, SIGNAL(analyzed(unsigned long)), this, SLOT(updateRecordLength(unsigned long)));
250 251 }
251 252  
252 253 /// \brief Stops the oscilloscope thread and the timer.
... ... @@ -283,7 +284,7 @@ void DsoWidget::updateMarkerDetails() {
283 284 if(this->settings->view.zoom) {
284 285 this->markerInfoLabel->setText(tr("Zoom x%L1").arg(DIVS_TIME / divs, -1, 'g', 3));
285 286 this->markerTimebaseLabel->setText(Helper::valueToString(time / DIVS_TIME, Helper::UNIT_SECONDS, 3) + tr("/div"));
286   - this->markerFrequencybaseLabel->setText(Helper::valueToString(divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME, Helper::UNIT_HERTZ, 3) + tr("/div"));
  287 + this->markerFrequencybaseLabel->setText(Helper::valueToString(divs * this->settings->scope.horizontal.frequencybase / DIVS_TIME, Helper::UNIT_HERTZ, 4) + tr("/div"));
287 288 }
288 289 this->markerTimeLabel->setText(Helper::valueToString(time, Helper::UNIT_SECONDS, 4));
289 290 this->markerFrequencyLabel->setText(Helper::valueToString(1.0 / time, Helper::UNIT_HERTZ, 4));
... ... @@ -294,7 +295,7 @@ void DsoWidget::updateSpectrumDetails(unsigned int channel) {
294 295 this->setMeasurementVisible(channel, this->settings->scope.voltage[channel].used || this->settings->scope.spectrum[channel].used);
295 296  
296 297 if(this->settings->scope.spectrum[channel].used)
297   - this->measurementMagnitudeLabel[channel]->setText(Helper::valueToString(this->settings->scope.spectrum[channel].magnitude, Helper::UNIT_DECIBEL, 0) + tr("/div"));
  298 + this->measurementMagnitudeLabel[channel]->setText(Helper::valueToString(this->settings->scope.spectrum[channel].magnitude, Helper::UNIT_DECIBEL, 3) + tr("/div"));
298 299 else
299 300 this->measurementMagnitudeLabel[channel]->setText(QString());
300 301 }
... ... @@ -320,24 +321,27 @@ void DsoWidget::updateVoltageDetails(unsigned int channel) {
320 321 this->setMeasurementVisible(channel, this->settings->scope.voltage[channel].used || this->settings->scope.spectrum[channel].used);
321 322  
322 323 if(this->settings->scope.voltage[channel].used)
323   - this->measurementGainLabel[channel]->setText(Helper::valueToString(this->settings->scope.voltage[channel].gain, Helper::UNIT_VOLTS, 0) + tr("/div"));
  324 + this->measurementGainLabel[channel]->setText(Helper::valueToString(this->settings->scope.voltage[channel].gain, Helper::UNIT_VOLTS, 3) + tr("/div"));
324 325 else
325 326 this->measurementGainLabel[channel]->setText(QString());
326 327 }
327 328  
328 329 /// \brief Handles frequencybaseChanged signal from the horizontal dock.
329   -void DsoWidget::updateFrequencybase() {
330   - this->settingsFrequencybaseLabel->setText(Helper::valueToString(this->settings->scope.horizontal.frequencybase, Helper::UNIT_HERTZ, 0) + tr("/div"));
  330 +/// \param frequencybase The frequencybase used for displaying the trace.
  331 +void DsoWidget::updateFrequencybase(double frequencybase) {
  332 + this->settingsFrequencybaseLabel->setText(Helper::valueToString(frequencybase, Helper::UNIT_HERTZ, 4) + tr("/div"));
331 333 }
332 334  
333 335 /// \brief Updates the samplerate field after changing the samplerate.
334   -void DsoWidget::updateSamplerate() {
335   - this->settingsSamplerateLabel->setText(Helper::valueToString(this->settings->scope.horizontal.samplerate, Helper::UNIT_SAMPLES) + tr("/s"));
  336 +/// \param samplerate The samplerate set in the oscilloscope.
  337 +void DsoWidget::updateSamplerate(double samplerate) {
  338 + this->settingsSamplerateLabel->setText(Helper::valueToString(samplerate, Helper::UNIT_SAMPLES, 4) + tr("/s"));
336 339 }
337 340  
338 341 /// \brief Handles timebaseChanged signal from the horizontal dock.
339   -void DsoWidget::updateTimebase() {
340   - this->settingsTimebaseLabel->setText(Helper::valueToString(this->settings->scope.horizontal.timebase, Helper::UNIT_SECONDS, 0) + tr("/div"));
  342 +/// \param timebase The timebase used for displaying the trace.
  343 +void DsoWidget::updateTimebase(double timebase) {
  344 + this->settingsTimebaseLabel->setText(Helper::valueToString(timebase, Helper::UNIT_SECONDS, 4) + tr("/div"));
341 345  
342 346 this->updateMarkerDetails();
343 347 }
... ... @@ -425,8 +429,8 @@ void DsoWidget::updateVoltageUsed(unsigned int channel, bool used) {
425 429 }
426 430  
427 431 /// \brief Change the record length.
428   -void DsoWidget::updateRecordLength(unsigned int size) {
429   - this->settingsRecordLengthLabel->setText(tr("%1 S").arg(size));
  432 +void DsoWidget::updateRecordLength(unsigned long size) {
  433 + this->settingsRecordLengthLabel->setText(Helper::valueToString(size, Helper::UNIT_SAMPLES, 4));
430 434 }
431 435  
432 436 /// \brief Export the oscilloscope screen to a file.
... ...
openhantek/src/dsowidget.h
... ... @@ -96,9 +96,9 @@ class DsoWidget : public QWidget {
96 96 public slots:
97 97 // Horizontal axis
98 98 //void horizontalFormatChanged(HorizontalFormat format);
99   - void updateFrequencybase();
100   - void updateSamplerate();
101   - void updateTimebase();
  99 + void updateFrequencybase(double frequencybase);
  100 + void updateSamplerate(double samplerate);
  101 + void updateTimebase(double timebase);
102 102  
103 103 // Trigger
104 104 void updateTriggerMode();
... ... @@ -116,7 +116,7 @@ class DsoWidget : public QWidget {
116 116 void updateVoltageUsed(unsigned int channel, bool used);
117 117  
118 118 // Menus
119   - void updateRecordLength(unsigned int size);
  119 + void updateRecordLength(unsigned long size);
120 120  
121 121 // Export
122 122 bool exportAs();
... ...
openhantek/src/glgenerator.cpp
... ... @@ -86,7 +86,7 @@ GlGenerator::GlGenerator(DsoSettings *settings, QObject *parent) : QObject(paren
86 86  
87 87 /// \brief Deletes OpenGL objects.
88 88 GlGenerator::~GlGenerator() {
89   - // todo: Clean up vaChannel
  89 + /// \todo Clean up vaChannel
90 90 }
91 91  
92 92 /// \brief Set the data analyzer whose data will be drawn.
... ...
openhantek/src/hantek/control.cpp
... ... @@ -5,7 +5,7 @@
5 5 //
6 6 // Copyright (C) 2008, 2009 Oleg Khudyakov
7 7 // prcoder@potrebitel.ru
8   -// Copyright (C) 2010, 2011 Oliver Haag
  8 +// Copyright (C) 2010 - 2012 Oliver Haag
9 9 // oliver.haag@gmail.com
10 10 //
11 11 // This program is free software: you can redistribute it and/or modify it
... ... @@ -24,6 +24,7 @@
24 24 ////////////////////////////////////////////////////////////////////////////////
25 25  
26 26  
  27 +#include <cmath>
27 28 #include <limits>
28 29  
29 30 #include <QList>
... ... @@ -43,7 +44,7 @@ namespace Hantek {
43 44 Control::Control(QObject *parent) : DsoControl(parent) {
44 45 // Use DSO-2090 specification as default
45 46 this->specification.command.bulk.setRecordLength = (BulkCode) -1;
46   - this->specification.command.bulk.setFilter = (BulkCode) -1;
  47 + this->specification.command.bulk.setChannels = (BulkCode) -1;
47 48 this->specification.command.bulk.setGain = (BulkCode) -1;
48 49 this->specification.command.bulk.setSamplerate = (BulkCode) -1;
49 50 this->specification.command.bulk.setTrigger = (BulkCode) -1;
... ... @@ -53,12 +54,12 @@ namespace Hantek {
53 54 this->specification.command.values.offsetLimits = (ControlValue) -1;
54 55 this->specification.command.values.voltageLimits = (ControlValue) -1;
55 56  
56   - this->specification.recordLengths << 0;
57   -
58 57 this->specification.samplerate.single.base = 50e6;
59 58 this->specification.samplerate.single.max = 50e6;
  59 + this->specification.samplerate.single.recordLengths << 0;
60 60 this->specification.samplerate.multi.base = 100e6;
61 61 this->specification.samplerate.multi.max = 100e6;
  62 + this->specification.samplerate.multi.recordLengths << 0;
62 63  
63 64 for(unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
64 65 for(unsigned int gainId = 0; gainId < 9; ++gainId) {
... ... @@ -69,8 +70,8 @@ namespace Hantek {
69 70  
70 71 // Set settings to default values
71 72 this->settings.samplerate.limits = &(this->specification.samplerate.single);
72   - this->settings.samplerate.downsampling = 1;
73   - this->settings.samplerate.current = 0.0;
  73 + this->settings.samplerate.downsampler = 1;
  74 + this->settings.samplerate.current = 1e8;
74 75 this->settings.trigger.position = 0;
75 76 this->settings.trigger.point = 0;
76 77 this->settings.trigger.mode = Dso::TRIGGERMODE_NORMAL;
... ... @@ -114,6 +115,8 @@ namespace Hantek {
114 115 this->samplesSize.append(0);
115 116 }
116 117  
  118 + this->previousSampleCount = 0;
  119 +
117 120 connect(this->device, SIGNAL(disconnected()), this, SLOT(disconnectDevice()));
118 121 }
119 122  
... ... @@ -134,6 +137,25 @@ namespace Hantek {
134 137 return HANTEK_CHANNELS;
135 138 }
136 139  
  140 + /// \brief Get available record lengths for this oscilloscope.
  141 + /// \return The number of physical channels, empty list for continuous.
  142 + QList<unsigned long int> *Control::getAvailableRecordLengths() {
  143 + return &this->settings.samplerate.limits->recordLengths;
  144 + }
  145 +
  146 + /// \brief Get minimum samplerate for this oscilloscope.
  147 + /// \return The minimum samplerate for the current configuration in S/s.
  148 + double Control::getMinSamplerate() {
  149 + return (double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler;
  150 + }
  151 +
  152 + /// \brief Get maximum samplerate for this oscilloscope.
  153 + /// \return The maximum samplerate for the current configuration in S/s.
  154 + double Control::getMaxSamplerate() {
  155 + ControlSamplerateLimits *limits = (this->settings.usedChannels <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single;
  156 + return limits->max;
  157 + }
  158 +
137 159 /// \brief Handles all USB things until the device gets disconnected.
138 160 void Control::run() {
139 161 int errorCode, cycleCounter = 0, startCycle = 0;
... ... @@ -194,7 +216,7 @@ namespace Hantek {
194 216  
195 217 // Check the current oscilloscope state everytime 25% of the time the buffer should be refilled
196 218 // Not more often than every 10 ms though
197   - int cycleTime = qMax((unsigned long int) (this->specification.recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10lu);
  219 + int cycleTime = qMax((unsigned long int) (this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10lu);
198 220 this->msleep(cycleTime);
199 221  
200 222 if(!this->sampling) {
... ... @@ -237,6 +259,12 @@ namespace Hantek {
237 259 break;
238 260  
239 261 case CAPTURE_WAITING:
  262 + // Sampling hasn't started, update the expected sample count
  263 + if(this->settings.samplerate.limits == &this->specification.samplerate.multi)
  264 + this->previousSampleCount = this->specification.samplerate.multi.recordLengths[this->settings.recordLengthId];
  265 + else
  266 + this->previousSampleCount = this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] * HANTEK_CHANNELS;
  267 +
240 268 if(samplingStarted && lastTriggerMode == this->settings.trigger.mode) {
241 269 ++cycleCounter;
242 270  
... ... @@ -338,8 +366,24 @@ namespace Hantek {
338 366 return errorCode;
339 367  
340 368 // Save raw data to temporary buffer
341   - unsigned int dataCount = this->specification.recordLengths[this->settings.recordLengthId] * HANTEK_CHANNELS;
342   - unsigned int dataLength = dataCount;
  369 + bool fastRate = this->settings.samplerate.limits == &this->specification.samplerate.multi;
  370 +
  371 + unsigned long int totalSampleCount = fastRate ? this->specification.samplerate.multi.recordLengths[this->settings.recordLengthId] : this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] * HANTEK_CHANNELS;
  372 +
  373 + // To make sure no samples will remain in the scope buffer, also check the sample count before the last sampling started
  374 + if(totalSampleCount < this->previousSampleCount) {
  375 + unsigned long int currentSampleCount = totalSampleCount;
  376 + totalSampleCount = this->previousSampleCount;
  377 + this->previousSampleCount = currentSampleCount; // Using sampleCount as temporary buffer since it was set to totalSampleCount
  378 + }
  379 + else {
  380 + this->previousSampleCount = totalSampleCount;
  381 + }
  382 +
  383 + unsigned long int sampleCount = totalSampleCount;
  384 + if(!fastRate)
  385 + sampleCount /= HANTEK_CHANNELS;
  386 + unsigned long int dataLength = totalSampleCount;
343 387 if(this->specification.sampleSize > 8)
344 388 dataLength *= 2;
345 389  
... ... @@ -353,18 +397,19 @@ namespace Hantek {
353 397 // How much data did we really receive?
354 398 dataLength = errorCode;
355 399 if(this->specification.sampleSize > 8)
356   - dataCount = dataLength / 2;
  400 + totalSampleCount = dataLength / 2;
357 401 else
358   - dataCount = dataLength;
  402 + totalSampleCount = dataLength;
359 403  
360 404 this->samplesMutex.lock();
361 405  
362 406 // Convert channel data
363   - if(this->settings.samplerate.limits == &this->specification.samplerate.multi) {
  407 + if(fastRate) {
364 408 // Fast rate mode, one channel is using all buffers
  409 + sampleCount = totalSampleCount;
365 410 int channel = 0;
366 411 for(; channel < HANTEK_CHANNELS; ++channel) {
367   - if(this->settings.voltage[0].used)
  412 + if(this->settings.voltage[channel].used)
368 413 break;
369 414 }
370 415  
... ... @@ -378,34 +423,34 @@ namespace Hantek {
378 423  
379 424 if(channel < HANTEK_CHANNELS) {
380 425 // Reallocate memory for samples if the sample count has changed
381   - if(!this->samples[channel] || this->samplesSize[channel] != dataCount) {
  426 + if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) {
382 427 if(this->samples[channel])
383 428 delete this->samples[channel];
384   - this->samples[channel] = new double[dataCount];
385   - this->samplesSize[channel] = dataCount;
  429 + this->samples[channel] = new double[sampleCount];
  430 + this->samplesSize[channel] = sampleCount;
386 431 }
387 432  
388 433 // Convert data from the oscilloscope and write it into the sample buffer
389   - unsigned int bufferPosition = (this->settings.trigger.point + 1) * 2;
  434 + unsigned long int bufferPosition = this->settings.trigger.point * 2;
390 435 if(this->specification.sampleSize > 8) {
391 436 // Additional most significant bits after the normal data
392 437 unsigned int extraBitsPosition; // Track the position of the extra bits in the additional byte
393 438 unsigned int extraBitsSize = this->specification.sampleSize - 8; // Number of extra bits
394 439 unsigned short int extraBitsMask = (0x00ff << extraBitsSize) & 0xff00; // Mask for extra bits extraction
395 440  
396   - for(unsigned int realPosition = 0; realPosition < dataCount; ++realPosition, ++bufferPosition) {
397   - if(bufferPosition >= dataCount)
398   - bufferPosition %= dataCount;
  441 + for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, ++bufferPosition) {
  442 + if(bufferPosition >= sampleCount)
  443 + bufferPosition %= sampleCount;
399 444  
400 445 extraBitsPosition = bufferPosition % HANTEK_CHANNELS;
401 446  
402   - 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];
  447 + 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];
403 448 }
404 449 }
405 450 else {
406   - for(unsigned int realPosition = 0; realPosition < dataCount; ++realPosition, ++bufferPosition) {
407   - if(bufferPosition >= dataCount)
408   - bufferPosition %= dataCount;
  451 + for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, ++bufferPosition) {
  452 + if(bufferPosition >= sampleCount)
  453 + bufferPosition %= sampleCount;
409 454  
410 455 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];
411 456 }
... ... @@ -414,39 +459,39 @@ namespace Hantek {
414 459 }
415 460 else {
416 461 // Normal mode, channels are using their separate buffers
417   - unsigned int channelDataCount = dataCount / HANTEK_CHANNELS;
418   -
  462 + sampleCount = totalSampleCount / HANTEK_CHANNELS;
419 463 for(int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
420 464 if(this->settings.voltage[channel].used) {
421 465 // Reallocate memory for samples if the sample count has changed
422   - if(!this->samples[channel] || this->samplesSize[channel] != channelDataCount) {
  466 + if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) {
423 467 if(this->samples[channel])
424 468 delete this->samples[channel];
425   - this->samples[channel] = new double[channelDataCount];
426   - this->samplesSize[channel] = channelDataCount;
  469 + this->samples[channel] = new double[sampleCount];
  470 + this->samplesSize[channel] = sampleCount;
427 471 }
428 472  
429 473 // Convert data from the oscilloscope and write it into the sample buffer
430   - unsigned int bufferPosition = (this->settings.trigger.point + 1) * 2;
  474 + unsigned long int bufferPosition = this->settings.trigger.point * 2;
431 475 if(this->specification.sampleSize > 8) {
432 476 // Additional most significant bits after the normal data
433 477 unsigned int extraBitsSize = this->specification.sampleSize - 8; // Number of extra bits
434 478 unsigned short int extraBitsMask = (0x00ff << extraBitsSize) & 0xff00; // Mask for extra bits extraction
435 479 unsigned int extraBitsIndex = 8 - channel * 2; // Bit position offset for extra bits extraction
436 480  
437   - for(unsigned int realPosition = 0; realPosition < channelDataCount; ++realPosition, bufferPosition += 2) {
438   - if(bufferPosition >= dataCount)
439   - bufferPosition %= dataCount;
  481 + for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, bufferPosition += HANTEK_CHANNELS) {
  482 + if(bufferPosition >= totalSampleCount)
  483 + bufferPosition %= totalSampleCount;
440 484  
441   - 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];
  485 + 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];
442 486 }
443 487 }
444 488 else {
445   - for(unsigned int realPosition = 0; realPosition < channelDataCount; ++realPosition, bufferPosition += 2) {
446   - if(bufferPosition >= dataCount)
447   - bufferPosition %= dataCount;
  489 + bufferPosition += HANTEK_CHANNELS - 1 - channel;
  490 + for(unsigned long int realPosition = 0; realPosition < sampleCount; ++realPosition, bufferPosition += HANTEK_CHANNELS) {
  491 + if(bufferPosition >= totalSampleCount)
  492 + bufferPosition %= totalSampleCount;
448 493  
449   - 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];
  494 + 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];
450 495 }
451 496 }
452 497 }
... ... @@ -466,29 +511,112 @@ namespace Hantek {
466 511 return errorCode;
467 512 }
468 513  
469   - /// \brief Sets the size of the sample buffer without updating dependencies.
470   - /// \param size The record length that should be met (S).
471   - /// \return The record length that has been set, 0 on error.
472   - unsigned long int Control::updateRecordLength(unsigned long int size) {
473   - // Get the record length supporting the highest samplerate while meeting the requirement
474   - int bestSizeId = -1;
475   - for(int sizeId = 0; sizeId < this->specification.recordLengths.count(); ++sizeId) {
476   - if(this->specification.recordLengths[sizeId] >= size) {
477   - // We meet the size-requirement, check if we provide the highest possible samplerate
478   - if(bestSizeId == -1 || this->specification.recordLengths[bestSizeId] < size || this->specification.bufferDividers[sizeId] < this->specification.bufferDividers[bestSizeId])
479   - bestSizeId = sizeId;
480   - }
481   - else {
482   - // We don't meet the size-requirement, but maybe we're still the one coming closest
483   - if(bestSizeId == -1 || this->specification.recordLengths[sizeId] > this->specification.recordLengths[bestSizeId])
484   - bestSizeId = sizeId;
  514 + /// \brief Calculated the nearest samplerate supported by the oscilloscope.
  515 + /// \param samplerate The target samplerate, that should be met as good as possible.
  516 + /// \param fastRate true, if the fast rate mode is enabled.
  517 + /// \param maximum The target samplerate is the maximum allowed when true, the minimum otherwise.
  518 + /// \param downsampler Pointer to where the selected downsampling factor should be written.
  519 + /// \return The nearest samplerate supported, 0.0 on error.
  520 + double Control::getBestSamplerate(double samplerate, bool fastRate, bool maximum, unsigned long int *downsampler) {
  521 + // Abort if the input value is invalid
  522 + if(samplerate <= 0.0)
  523 + return 0.0;
  524 +
  525 + double bestSamplerate = 0.0;
  526 +
  527 + // Get samplerate specifications for this mode and model
  528 + ControlSamplerateLimits *limits;
  529 + if(fastRate)
  530 + limits = &(this->specification.samplerate.multi);
  531 + else
  532 + limits = &(this->specification.samplerate.single);
  533 +
  534 + // Get downsampling factor that would provide the requested rate
  535 + double bestDownsampler = (double) limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / samplerate;
  536 + // Base samplerate sufficient, or is the maximum better?
  537 + if(bestDownsampler < 1.0 && (samplerate <= limits->max / this->specification.bufferDividers[this->settings.recordLengthId] || !maximum)) {
  538 + bestDownsampler = 0.0;
  539 + bestSamplerate = limits->max / this->specification.bufferDividers[this->settings.recordLengthId];
  540 + }
  541 + else {
  542 + switch(this->specification.command.bulk.setSamplerate) {
  543 + case BULK_SETTRIGGERANDSAMPLERATE:
  544 + // DSO-2090 supports the downsampling factors 1, 2, 4 and 5 using valueFast or all even values above using valueSlow
  545 + if((maximum && bestDownsampler <= 5.0) || (!maximum && bestDownsampler < 6.0)) {
  546 + // valueFast is used
  547 + if(maximum) {
  548 + // The samplerate shall not be higher, so we round up
  549 + bestDownsampler = ceil(bestDownsampler);
  550 + if(bestDownsampler > 2.0) // 3 and 4 not possible with the DSO-2090
  551 + bestDownsampler = 5.0;
  552 + }
  553 + else {
  554 + // The samplerate shall not be lower, so we round down
  555 + bestDownsampler = floor(bestDownsampler);
  556 + if(bestDownsampler > 2.0 && bestDownsampler < 5.0) // 3 and 4 not possible with the DSO-2090
  557 + bestDownsampler = 2.0;
  558 + }
  559 + }
  560 + else {
  561 + // valueSlow is used
  562 + if(maximum) {
  563 + bestDownsampler = ceil(bestDownsampler / 2.0) * 2.0; // Round up to next even value
  564 + }
  565 + else {
  566 + bestDownsampler = floor(bestDownsampler / 2.0) * 2.0; // Round down to next even value
  567 + }
  568 + if(bestDownsampler > 2.0 * 0x10001) // Check for overflow
  569 + bestDownsampler = 2.0 * 0x10001;
  570 + }
  571 + break;
  572 +
  573 + case BULK_CSETTRIGGERORSAMPLERATE:
  574 + // DSO-5200 may not supports all downsampling factors, requires testing
  575 + if(maximum) {
  576 + bestDownsampler = ceil(bestDownsampler); // Round up to next integer value
  577 + }
  578 + else {
  579 + bestDownsampler = floor(bestDownsampler); // Round down to next integer value
  580 + }
  581 + break;
  582 +
  583 + case BULK_ESETTRIGGERORSAMPLERATE:
  584 + // DSO-2250 doesn't have a fast value, so it supports all downsampling factors
  585 + if(maximum) {
  586 + bestDownsampler = ceil(bestDownsampler); // Round up to next integer value
  587 + }
  588 + else {
  589 + bestDownsampler = floor(bestDownsampler); // Round down to next integer value
  590 + }
  591 + break;
  592 +
  593 + default:
  594 + return 0.0;
485 595 }
  596 +
  597 + // Limit maximum downsampler value to avoid overflows in the sent commands
  598 + if(bestDownsampler > limits->maxDownsampler)
  599 + bestDownsampler = limits->maxDownsampler;
  600 +
  601 + bestSamplerate = limits->base / bestDownsampler / this->specification.bufferDividers[this->settings.recordLengthId];
486 602 }
487 603  
  604 + if(downsampler)
  605 + *downsampler = (unsigned long int) bestDownsampler;
  606 + return bestSamplerate;
  607 + }
  608 +
  609 + /// \brief Sets the size of the sample buffer without updating dependencies.
  610 + /// \param index The record length index that should be set.
  611 + /// \return The record length that has been set, 0 on error.
  612 + unsigned long int Control::updateRecordLength(unsigned long int index) {
  613 + if(index >= (unsigned long int) this->settings.samplerate.limits->recordLengths.size())
  614 + return 0;
  615 +
488 616 switch(this->specification.command.bulk.setRecordLength) {
489 617 case BULK_SETTRIGGERANDSAMPLERATE:
490 618 // SetTriggerAndSamplerate bulk command for record length
491   - static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setRecordLength(bestSizeId);
  619 + static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setRecordLength(index);
492 620 this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
493 621  
494 622 break;
... ... @@ -498,7 +626,7 @@ namespace Hantek {
498 626 // Pointers to needed commands
499 627 BulkSetRecordLength2250 *commandSetRecordLength2250 = static_cast<BulkSetRecordLength2250 *>(this->command[BULK_DSETBUFFER]);
500 628  
501   - commandSetRecordLength2250->setRecordLength(bestSizeId);
  629 + commandSetRecordLength2250->setRecordLength(index);
502 630 }
503 631 else {
504 632 // SetBuffer5200 bulk command for record length
... ... @@ -506,7 +634,7 @@ namespace Hantek {
506 634  
507 635 commandSetBuffer5200->setUsedPre(DTRIGGERPOSITION_ON);
508 636 commandSetBuffer5200->setUsedPost(DTRIGGERPOSITION_ON);
509   - commandSetBuffer5200->setRecordLength(bestSizeId);
  637 + commandSetBuffer5200->setRecordLength(index);
510 638 }
511 639  
512 640 this->commandPending[BULK_DSETBUFFER] = true;
... ... @@ -517,9 +645,136 @@ namespace Hantek {
517 645 return 0;
518 646 }
519 647  
520   - this->settings.recordLengthId = bestSizeId;
  648 + this->settings.recordLengthId = index;
  649 +
  650 + return this->settings.samplerate.limits->recordLengths[index];
  651 + }
  652 +
  653 + /// \brief Sets the samplerate based on the parameters calculated by Control::getBestSamplerate.
  654 + /// \param downsampler The downsampling factor.
  655 + /// \param fastRate true, if one channel uses all buffers.
  656 + /// \return The downsampling factor that has been set.
  657 + unsigned long int Control::updateSamplerate(unsigned long int downsampler, bool fastRate) {
  658 + // Set the calculated samplerate
  659 + switch(this->specification.command.bulk.setSamplerate) {
  660 + case BULK_SETTRIGGERANDSAMPLERATE: {
  661 + short int downsamplerValue = 0;
  662 + unsigned char samplerateId = 0;
  663 + bool downsampling = false;
  664 +
  665 + if(downsampler <= 5) {
  666 + // All dividers up to 5 are done using the special samplerate IDs
  667 + if(downsampler == 0)
  668 + samplerateId = 1;
  669 + else if(downsampler <= 2)
  670 + samplerateId = downsampler;
  671 + else { // Downsampling factors 3 and 4 are not supported
  672 + samplerateId = 3;
  673 + downsampler = 5;
  674 + downsamplerValue = 0xffff;
  675 + }
  676 + }
  677 + else {
  678 + // For any dividers above the downsampling factor can be set directly
  679 + downsampler &= ~0x0001; // Only even values possible
  680 + downsamplerValue = (short int) (0x10001 - (downsampler >> 1));
  681 +
  682 + downsampling = true;
  683 + }
  684 +
  685 + // Pointers to needed commands
  686 + BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE]);
  687 +
  688 + // Store if samplerate ID or downsampling factor is used
  689 + commandSetTriggerAndSamplerate->setDownsamplingMode(downsampling);
  690 + // Store samplerate ID
  691 + commandSetTriggerAndSamplerate->setSamplerateId(samplerateId);
  692 + // Store downsampling factor
  693 + commandSetTriggerAndSamplerate->setDownsampler(downsamplerValue);
  694 + // Set fast rate when used
  695 + commandSetTriggerAndSamplerate->setFastRate(false /*fastRate*/);
  696 +
  697 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  698 +
  699 + break;
  700 + }
  701 + case BULK_CSETTRIGGERORSAMPLERATE: {
  702 + // Split the resulting divider into the values understood by the device
  703 + // The fast value is kept at 4 (or 3) for slow sample rates
  704 + long int valueSlow = qMax(((long int) downsampler - 3) / 2, (long int) 0);
  705 + unsigned char valueFast = downsampler - valueSlow * 2;
  706 +
  707 + // Pointers to needed commands
  708 + BulkSetSamplerate5200 *commandSetSamplerate5200 = static_cast<BulkSetSamplerate5200 *>(this->command[BULK_CSETTRIGGERORSAMPLERATE]);
  709 + BulkSetTrigger5200 *commandSetTrigger5200 = static_cast<BulkSetTrigger5200 *>(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
  710 +
  711 + // Store samplerate fast value
  712 + commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
  713 + // Store samplerate slow value (two's complement)
  714 + commandSetSamplerate5200->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow);
  715 + // Set fast rate when used
  716 + commandSetTrigger5200->setFastRate(fastRate);
  717 +
  718 + this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
  719 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  720 +
  721 + break;
  722 + }
  723 + case BULK_ESETTRIGGERORSAMPLERATE: {
  724 + // Pointers to needed commands
  725 + BulkSetSamplerate2250 *commandSetSamplerate2250 = static_cast<BulkSetSamplerate2250 *>(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
  726 +
  727 + bool downsampling = downsampler >= 1;
  728 + // Store downsampler state value
  729 + commandSetSamplerate2250->setDownsampling(downsampling);
  730 + // Store samplerate value
  731 + commandSetSamplerate2250->setSamplerate(downsampler > 1 ? 0x10001 - downsampler : 0);
  732 + // Set fast rate when used
  733 + commandSetSamplerate2250->setFastRate(fastRate);
  734 +
  735 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  736 +
  737 + break;
  738 + }
  739 + default:
  740 + return ULONG_MAX;
  741 + }
  742 +
  743 + // Update settings
  744 + bool fastRateChanged = fastRate != (this->settings.samplerate.limits == &this->specification.samplerate.multi);
  745 + if(fastRateChanged) {
  746 + if(fastRate)
  747 + this->settings.samplerate.limits = &this->specification.samplerate.multi;
  748 + else
  749 + this->settings.samplerate.limits = &this->specification.samplerate.single;
  750 + }
521 751  
522   - return this->specification.recordLengths[this->settings.recordLengthId];
  752 + this->settings.samplerate.downsampler = downsampler;
  753 + if(downsampler)
  754 + this->settings.samplerate.current = this->settings.samplerate.limits->base / downsampler;
  755 + else
  756 + this->settings.samplerate.current = this->settings.samplerate.limits->max;
  757 +
  758 + // Update dependencies
  759 + this->setPretriggerPosition(this->settings.trigger.position);
  760 +
  761 + // Emit signals for changed settings
  762 + if(fastRateChanged) {
  763 + emit availableRecordLengthsChanged(this->settings.samplerate.limits->recordLengths);
  764 + emit recordLengthChanged(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId]);
  765 + }
  766 + emit recordTimeChanged((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current);
  767 + emit samplerateChanged(this->settings.samplerate.current);
  768 +
  769 + return downsampler;
  770 + }
  771 +
  772 + /// \brief Try to connect to the oscilloscope.
  773 + void Control::restoreTargets() {
  774 + if(this->settings.samplerate.target.samplerateSet)
  775 + this->setSamplerate();
  776 + else
  777 + this->setRecordTime();
523 778 }
524 779  
525 780 /// \brief Try to connect to the oscilloscope.
... ... @@ -545,7 +800,7 @@ namespace Hantek {
545 800 this->command[BULK_SETGAIN] = new BulkSetGain();
546 801 // Initialize the command versions to the ones used on the DSO-2090
547 802 this->specification.command.bulk.setRecordLength = (BulkCode) -1;
548   - this->specification.command.bulk.setFilter = (BulkCode) -1;
  803 + this->specification.command.bulk.setChannels = (BulkCode) -1;
549 804 this->specification.command.bulk.setGain = BULK_SETGAIN;
550 805 this->specification.command.bulk.setSamplerate = (BulkCode) -1;
551 806 this->specification.command.bulk.setTrigger = (BulkCode) -1;
... ... @@ -563,32 +818,30 @@ namespace Hantek {
563 818  
564 819 case MODEL_DSO2090:
565 820 // Instantiate additional commands for the DSO-2090
566   - this->command[BULK_SETFILTER] = new BulkSetFilter();
567 821 this->command[BULK_SETTRIGGERANDSAMPLERATE] = new BulkSetTriggerAndSamplerate();
568 822 this->specification.command.bulk.setRecordLength = BULK_SETTRIGGERANDSAMPLERATE;
569   - this->specification.command.bulk.setFilter = BULK_SETFILTER;
  823 + this->specification.command.bulk.setChannels = BULK_SETTRIGGERANDSAMPLERATE;
570 824 this->specification.command.bulk.setSamplerate = BULK_SETTRIGGERANDSAMPLERATE;
571 825 this->specification.command.bulk.setTrigger = BULK_SETTRIGGERANDSAMPLERATE;
572 826 this->specification.command.bulk.setPretrigger = BULK_SETTRIGGERANDSAMPLERATE;
573 827 // Initialize those as pending
574   - this->commandPending[BULK_SETFILTER] = true;
575 828 this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
576 829 break;
577 830  
578 831 case MODEL_DSO2250:
579 832 // Instantiate additional commands for the DSO-2250
580   - this->command[BULK_BSETFILTER] = new BulkSetFilter2250();
  833 + this->command[BULK_BSETCHANNELS] = new BulkSetChannels2250();
581 834 this->command[BULK_CSETTRIGGERORSAMPLERATE] = new BulkSetTrigger2250();
582 835 this->command[BULK_DSETBUFFER] = new BulkSetRecordLength2250();
583 836 this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetSamplerate2250();
584 837 this->command[BULK_FSETBUFFER] = new BulkSetBuffer2250();
585 838 this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
586   - this->specification.command.bulk.setFilter = BULK_BSETFILTER;
  839 + this->specification.command.bulk.setChannels = BULK_BSETCHANNELS;
587 840 this->specification.command.bulk.setSamplerate = BULK_ESETTRIGGERORSAMPLERATE;
588 841 this->specification.command.bulk.setTrigger = BULK_CSETTRIGGERORSAMPLERATE;
589 842 this->specification.command.bulk.setPretrigger = BULK_FSETBUFFER;
590 843  
591   - this->commandPending[BULK_BSETFILTER] = true;
  844 + this->commandPending[BULK_BSETCHANNELS] = true;
592 845 this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
593 846 this->commandPending[BULK_DSETBUFFER] = true;
594 847 this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
... ... @@ -605,6 +858,7 @@ namespace Hantek {
605 858 this->command[BULK_DSETBUFFER] = new BulkSetBuffer5200();
606 859 this->command[BULK_ESETTRIGGERORSAMPLERATE] = new BulkSetTrigger5200();
607 860 this->specification.command.bulk.setRecordLength = BULK_DSETBUFFER;
  861 + this->specification.command.bulk.setChannels = BULK_ESETTRIGGERORSAMPLERATE;
608 862 this->specification.command.bulk.setSamplerate = BULK_CSETTRIGGERORSAMPLERATE;
609 863 this->specification.command.bulk.setTrigger = BULK_ESETTRIGGERORSAMPLERATE;
610 864 this->specification.command.bulk.setPretrigger = BULK_ESETTRIGGERORSAMPLERATE;
... ... @@ -630,7 +884,8 @@ namespace Hantek {
630 884  
631 885 // Maximum possible samplerate for a single channel and dividers for record lengths
632 886 this->specification.bufferDividers.clear();
633   - this->specification.recordLengths.clear();
  887 + this->specification.samplerate.single.recordLengths.clear();
  888 + this->specification.samplerate.multi.recordLengths.clear();
634 889 this->specification.gainSteps.clear();
635 890 for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
636 891 this->specification.voltageLimit[channel].clear();
... ... @@ -640,10 +895,13 @@ namespace Hantek {
640 895 case MODEL_DSO5200A:
641 896 this->specification.samplerate.single.base = 100e6;
642 897 this->specification.samplerate.single.max = 125e6;
  898 + this->specification.samplerate.single.maxDownsampler = 131072;
  899 + this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 14336;
643 900 this->specification.samplerate.multi.base = 200e6;
644 901 this->specification.samplerate.multi.max = 250e6;
  902 + this->specification.samplerate.multi.maxDownsampler = 131072;
  903 + this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 28672;
645 904 this->specification.bufferDividers << 1000 << 1 << 1;
646   - this->specification.recordLengths << ULONG_MAX << 10240 << 14336;
647 905 this->specification.gainSteps
648 906 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0 << 80.0;
649 907 /// \todo Use calibration data to get the DSO-5200(A) sample ranges
... ... @@ -658,10 +916,13 @@ namespace Hantek {
658 916 case MODEL_DSO2250:
659 917 this->specification.samplerate.single.base = 100e6;
660 918 this->specification.samplerate.single.max = 100e6;
  919 + this->specification.samplerate.single.maxDownsampler = 65536;
  920 + this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 524288;
661 921 this->specification.samplerate.multi.base = 200e6;
662 922 this->specification.samplerate.multi.max = 250e6;
  923 + this->specification.samplerate.multi.maxDownsampler = 65536;
  924 + this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 1048576;
663 925 this->specification.bufferDividers << 1000 << 1 << 1;
664   - this->specification.recordLengths << ULONG_MAX << 10240 << 524288;
665 926 this->specification.gainSteps
666 927 << 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0;
667 928 for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
... ... @@ -675,10 +936,13 @@ namespace Hantek {
675 936 case MODEL_DSO2150:
676 937 this->specification.samplerate.single.base = 50e6;
677 938 this->specification.samplerate.single.max = 75e6;
  939 + this->specification.samplerate.single.maxDownsampler = 131072;
  940 + this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 32768;
678 941 this->specification.samplerate.multi.base = 100e6;
679 942 this->specification.samplerate.multi.max = 150e6;
  943 + this->specification.samplerate.multi.maxDownsampler = 131072;
  944 + this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 65536;
680 945 this->specification.bufferDividers << 1000 << 1 << 1;
681   - this->specification.recordLengths << ULONG_MAX << 10240 << 32768;
682 946 this->specification.gainSteps
683 947 << 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0;
684 948 for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
... ... @@ -692,10 +956,13 @@ namespace Hantek {
692 956 default:
693 957 this->specification.samplerate.single.base = 50e6;
694 958 this->specification.samplerate.single.max = 50e6;
  959 + this->specification.samplerate.single.maxDownsampler = 131072;
  960 + this->specification.samplerate.single.recordLengths << ULONG_MAX << 10240 << 32768;
695 961 this->specification.samplerate.multi.base = 100e6;
696 962 this->specification.samplerate.multi.max = 100e6;
  963 + this->specification.samplerate.multi.maxDownsampler = 131072;
  964 + this->specification.samplerate.multi.recordLengths << ULONG_MAX << 20480 << 65536;
697 965 this->specification.bufferDividers << 1000 << 1 << 1;
698   - this->specification.recordLengths << ULONG_MAX << 10240 << 32768;
699 966 this->specification.gainSteps
700 967 << 0.08 << 0.16 << 0.40 << 0.80 << 1.60 << 4.00 << 8.0 << 16.0 << 40.0;
701 968 for(int channel = 0; channel < HANTEK_CHANNELS; ++channel)
... ... @@ -706,8 +973,10 @@ namespace Hantek {
706 973 this->specification.sampleSize = 8;
707 974 break;
708 975 }
  976 + this->settings.recordLengthId = 1;
709 977 this->settings.samplerate.limits = &(this->specification.samplerate.single);
710   - this->settings.samplerate.downsampling = 1;
  978 + this->settings.samplerate.downsampler = 1;
  979 + this->previousSampleCount = 0;
711 980  
712 981 // Get channel level data
713 982 errorCode = this->device->controlRead(CONTROL_VALUE, (unsigned char *) &(this->specification.offsetLimit), sizeof(this->specification.offsetLimit), (int) VALUE_OFFSETLIMITS);
... ... @@ -721,131 +990,78 @@ namespace Hantek {
721 990 }
722 991  
723 992 /// \brief Sets the size of the oscilloscopes sample buffer.
724   - /// \param size The record length that should be met (S).
  993 + /// \param index The record length index that should be set.
725 994 /// \return The record length that has been set, 0 on error.
726   - unsigned long int Control::setRecordLength(unsigned long int size) {
727   - if(!this->device->isConnected())
  995 + unsigned long int Control::setRecordLength(unsigned long int index) {
  996 + if(!this->device->isConnected())
728 997 return 0;
729 998  
730   - this->updateRecordLength(size);
  999 + if(!this->updateRecordLength(index))
  1000 + return 0;
731 1001  
732   - this->setSamplerate();
  1002 + this->restoreTargets();
733 1003 this->setPretriggerPosition(this->settings.trigger.position);
734 1004  
735   - return this->specification.recordLengths[this->settings.recordLengthId];
  1005 + emit recordLengthChanged(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId]);
  1006 + return this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId];
736 1007 }
737 1008  
738 1009 /// \brief Sets the samplerate of the oscilloscope.
739   - /// \param samplerate The samplerate that should be met (S/s).
740   - /// \return The samplerate that has been set, 0 on error.
741   - unsigned long int Control::setSamplerate(unsigned long int samplerate) {
742   - if(!this->device->isConnected())
743   - return 0;
  1010 + /// \param samplerate The samplerate that should be met (S/s), 0.0 to restore current samplerate.
  1011 + /// \return The samplerate that has been set, 0.0 on error.
  1012 + double Control::setSamplerate(double samplerate) {
  1013 + if(samplerate == 0.0) {
  1014 + samplerate = this->settings.samplerate.target.samplerate;
  1015 + }
  1016 + else {
  1017 + this->settings.samplerate.target.samplerate = samplerate;
  1018 + this->settings.samplerate.target.samplerateSet = true;
  1019 + }
744 1020  
745   - // Keep samplerate if no parameter was given
746   - if(!samplerate)
747   - samplerate = this->settings.samplerate.current;
748   - // Abort samplerate calculation if we didn't get a valid value yet
749   - if(!samplerate)
750   - return samplerate;
  1021 + // When possible, enable fast rate if it is required to reach the requested samplerate
  1022 + bool fastRate = (this->settings.usedChannels <= 1) && (samplerate > this->specification.samplerate.single.max);
751 1023  
752   - // Calculate with fast rate first if only one channel is used
753   - bool fastRate = false;
754   - this->settings.samplerate.limits = &(this->specification.samplerate.single);
755   - if(this->settings.usedChannels <= 1) {
756   - fastRate = true;
757   - this->settings.samplerate.limits = &(this->specification.samplerate.multi);
  1024 + // What is the nearest, at least as high samplerate the scope can provide?
  1025 + unsigned long int downsampler = 0;
  1026 + double bestSamplerate = getBestSamplerate(samplerate, fastRate, false, &(downsampler));
  1027 +
  1028 + // Set the calculated samplerate
  1029 + if(this->updateSamplerate(downsampler, fastRate) == ULONG_MAX)
  1030 + return 0.0;
  1031 + else {
  1032 + return bestSamplerate;
  1033 + }
  1034 + }
  1035 +
  1036 + /// \brief Sets the time duration of one aquisition by adapting the samplerate.
  1037 + /// \param duration The record time duration that should be met (s), 0.0 to restore current record time.
  1038 + /// \return The record time duration that has been set, 0.0 on error.
  1039 + double Control::setRecordTime(double duration) {
  1040 + if(duration == 0.0) {
  1041 + duration = this->settings.samplerate.target.duration;
  1042 + }
  1043 + else {
  1044 + this->settings.samplerate.target.duration = duration;
  1045 + this->settings.samplerate.target.samplerateSet = false;
758 1046 }
759 1047  
760   - // Get downsampling factor that would provide the requested rate
761   - this->settings.samplerate.downsampling = this->settings.samplerate.limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / samplerate;
762   - // A downsampling factor of zero will result in the maximum rate
763   - if(this->settings.samplerate.downsampling)
764   - this->settings.samplerate.current = this->settings.samplerate.limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / this->settings.samplerate.downsampling;
765   - else
766   - this->settings.samplerate.current = this->settings.samplerate.limits->max / this->specification.bufferDividers[this->settings.recordLengthId];
  1048 + // Calculate the maximum samplerate that would still provide the requested duration
  1049 + double maxSamplerate = (double) this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] / duration;
767 1050  
768   - // Maybe normal mode would be sufficient or even better than fast rate mode
769   - if(fastRate) {
770   - // Don't set the downsampling factor to zero (maximum rate) if we could use fast rate mode anyway
771   - unsigned long int slowDownsampling = qMax(this->specification.samplerate.single.base / this->specification.bufferDividers[this->settings.recordLengthId] / samplerate, (long unsigned int) 1);
772   -
773   - // Use normal mode if we need valueSlow or it would meet the rate at least as exactly as fast rate mode
774   - 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))) {
775   - fastRate = false;
776   - this->settings.samplerate.limits = &(this->specification.samplerate.single);
777   - this->settings.samplerate.downsampling = slowDownsampling;
778   - this->settings.samplerate.current = this->specification.samplerate.single.base / this->specification.bufferDividers[this->settings.recordLengthId] / this->settings.samplerate.downsampling;
779   - }
780   - }
  1051 + // When possible, enable fast rate if the record time can't be set that low to improve resolution
  1052 + bool fastRate = (this->settings.usedChannels <= 1) && (maxSamplerate >= this->specification.samplerate.multi.base);
781 1053  
782   - switch(this->specification.command.bulk.setSamplerate) {
783   - case BULK_SETTRIGGERANDSAMPLERATE: {
784   - // Split the resulting divider into the values understood by the device
785   - // The fast value is kept at 4 (or 3) for slow sample rates
786   - long int valueSlow = qMax(((long int) this->settings.samplerate.downsampling - 3) / 2, (long int) 0);
787   - unsigned char valueFast = this->settings.samplerate.downsampling - valueSlow * 2;
788   -
789   - // Pointers to needed commands
790   - BulkSetTriggerAndSamplerate *commandSetTriggerAndSamplerate = static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE]);
791   -
792   - // Store samplerate fast value
793   - commandSetTriggerAndSamplerate->setSamplerateFast(valueFast);
794   - // Store samplerate slow value (two's complement)
795   - commandSetTriggerAndSamplerate->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow);
796   - // Set fast rate when used
797   - commandSetTriggerAndSamplerate->setFastRate(fastRate);
798   -
799   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
800   -
801   - break;
802   - }
803   - case BULK_CSETTRIGGERORSAMPLERATE: {
804   - // Split the resulting divider into the values understood by the device
805   - // The fast value is kept at 4 (or 3) for slow sample rates
806   - long int valueSlow = qMax(((long int) this->settings.samplerate.downsampling - 3) / 2, (long int) 0);
807   - unsigned char valueFast = this->settings.samplerate.downsampling - valueSlow * 2;
808   -
809   - // Pointers to needed commands
810   - BulkSetSamplerate5200 *commandSetSamplerate5200 = static_cast<BulkSetSamplerate5200 *>(this->command[BULK_CSETTRIGGERORSAMPLERATE]);
811   - BulkSetTrigger5200 *commandSetTrigger5200 = static_cast<BulkSetTrigger5200 *>(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
812   -
813   - // Store samplerate fast value
814   - commandSetSamplerate5200->setSamplerateFast(4 - valueFast);
815   - // Store samplerate slow value (two's complement)
816   - commandSetSamplerate5200->setSamplerateSlow(valueSlow == 0 ? 0 : 0xffff - valueSlow);
817   - // Set fast rate when used
818   - commandSetTrigger5200->setFastRate(fastRate);
819   -
820   - this->commandPending[BULK_CSETTRIGGERORSAMPLERATE] = true;
821   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
822   -
823   - break;
824   - }
825   - case BULK_ESETTRIGGERORSAMPLERATE: {
826   - // Pointers to needed commands
827   - BulkSetSamplerate2250 *commandSetSamplerate2250 = static_cast<BulkSetSamplerate2250 *>(this->command[BULK_ESETTRIGGERORSAMPLERATE]);
828   -
829   - bool downsampling = this->settings.samplerate.downsampling > 1;
830   - // Store downsampler state value
831   - commandSetSamplerate2250->setDownsampling(downsampling);
832   - // Store samplerate value
833   - commandSetSamplerate2250->setSamplerate(downsampling ? 0x10001 - this->settings.samplerate.downsampling : 0);
834   - // Set fast rate when used
835   - commandSetSamplerate2250->setFastRate(fastRate);
836   -
837   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
838   -
839   - break;
840   - }
841   - default:
842   - return 0;
843   - }
  1054 + // What is the nearest, at most as high samplerate the scope can provide?
  1055 + unsigned long int downsampler = 0;
  1056 + double bestSamplerate = getBestSamplerate(maxSamplerate, fastRate, true, &(downsampler));
844 1057  
845   - this->updateRecordLength(this->specification.recordLengths[this->settings.recordLengthId]);
846   - this->setPretriggerPosition(this->settings.trigger.position);
847   - return this->settings.samplerate.current;
848   - }
  1058 + // Set the calculated samplerate
  1059 + if(this->updateSamplerate(downsampler, fastRate) == ULONG_MAX)
  1060 + return 0.0;
  1061 + else {
  1062 + return (double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / bestSamplerate;
  1063 + }
  1064 + }
849 1065  
850 1066 /// \brief Enables/disables filtering of the given channel.
851 1067 /// \param channel The channel that should be set.
... ... @@ -858,28 +1074,6 @@ namespace Hantek {
858 1074 if(channel >= HANTEK_CHANNELS)
859 1075 return Dso::ERROR_PARAMETER;
860 1076  
861   - // Channel filtering commands
862   - switch(this->specification.command.bulk.setFilter) {
863   - case BULK_SETFILTER: {
864   - // SetFilter bulk command for channel filter (used has to be inverted!)
865   - BulkSetFilter *commandSetFilter = static_cast<BulkSetFilter *>(this->command[BULK_SETFILTER]);
866   - commandSetFilter->setChannel(channel, !used);
867   - this->commandPending[BULK_SETFILTER] = true;
868   -
869   - break;
870   - }
871   - case BULK_BSETFILTER: {
872   - // SetFilter2250 bulk command for channel filter (used has to be inverted!)
873   - BulkSetFilter2250 *commandSetFilter2250 = static_cast<BulkSetFilter2250 *>(this->command[BULK_BSETFILTER]);
874   - commandSetFilter2250->setChannel(channel, !used);
875   - this->commandPending[BULK_BSETFILTER] = true;
876   -
877   - break;
878   - }
879   - default:
880   - return Dso::ERROR_UNSUPPORTED;
881   - }
882   -
883 1077 // Update settings
884 1078 this->settings.voltage[channel].used = used;
885 1079 unsigned int channelCount = 0;
... ... @@ -887,35 +1081,58 @@ namespace Hantek {
887 1081 if(this->settings.voltage[channelCounter].used)
888 1082 ++channelCount;
889 1083 }
890   - this->settings.usedChannels = channelCount;
891 1084  
892   - // Additional UsedChannels field for all models except DSO-2250
893   - if(this->specification.command.bulk.setTrigger == BULK_SETTRIGGERANDSAMPLERATE || this->specification.command.bulk.setTrigger == BULK_ESETTRIGGERORSAMPLERATE) {
894   - unsigned char usedChannels = USED_CH1;
895   -
896   - if(this->settings.voltage[1].used) {
897   - if(this->settings.voltage[0].used)
898   - usedChannels = USED_CH1CH2;
  1085 + // Calculate the UsedChannels field for the command
  1086 + unsigned char usedChannels = USED_CH1;
  1087 +
  1088 + if(this->settings.voltage[1].used) {
  1089 + if(this->settings.voltage[0].used) {
  1090 + usedChannels = USED_CH1CH2;
  1091 + }
  1092 + else {
  1093 + // DSO-2250 uses a different value for channel 2
  1094 + if(this->specification.command.bulk.setTrigger == BULK_BSETCHANNELS)
  1095 + usedChannels = BUSED_CH2;
899 1096 else
900 1097 usedChannels = USED_CH2;
901 1098 }
902   -
903   - switch(this->specification.command.bulk.setTrigger) {
904   - case BULK_SETTRIGGERANDSAMPLERATE: {
905   - // SetTriggerAndSamplerate bulk command for trigger source
906   - static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setUsedChannels(usedChannels);
907   - this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
908   - break;
909   - }
910   - case BULK_ESETTRIGGERORSAMPLERATE: {
911   - // SetTrigger5200s bulk command for trigger source
912   - static_cast<BulkSetTrigger5200 *>(this->command[BULK_ESETTRIGGERORSAMPLERATE])->setUsedChannels(usedChannels);
913   - this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
914   - break;
915   - }
916   - default:
917   - break;
  1099 + }
  1100 +
  1101 + switch(this->specification.command.bulk.setTrigger) {
  1102 + case BULK_SETTRIGGERANDSAMPLERATE: {
  1103 + // SetTriggerAndSamplerate bulk command for trigger source
  1104 + static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setUsedChannels(usedChannels);
  1105 + this->commandPending[BULK_SETTRIGGERANDSAMPLERATE] = true;
  1106 + break;
  1107 + }
  1108 + case BULK_BSETCHANNELS: {
  1109 + // SetChannels2250 bulk command for active channels
  1110 + static_cast<BulkSetChannels2250 *>(this->command[BULK_BSETCHANNELS])->setUsedChannels(usedChannels);
  1111 + this->commandPending[BULK_BSETCHANNELS] = true;
  1112 +
  1113 + break;
  1114 + }
  1115 + case BULK_ESETTRIGGERORSAMPLERATE: {
  1116 + // SetTrigger5200s bulk command for trigger source
  1117 + static_cast<BulkSetTrigger5200 *>(this->command[BULK_ESETTRIGGERORSAMPLERATE])->setUsedChannels(usedChannels);
  1118 + this->commandPending[BULK_ESETTRIGGERORSAMPLERATE] = true;
  1119 + break;
918 1120 }
  1121 + default:
  1122 + break;
  1123 + }
  1124 +
  1125 + // Check if fast rate mode availability changed
  1126 + bool fastRateChanged = (this->settings.usedChannels <= 1) != (channelCount <= 1);
  1127 + this->settings.usedChannels = channelCount;
  1128 +
  1129 + if(fastRateChanged) {
  1130 + // Works only if the minimum samplerate for normal mode is lower than for fast rate mode, which is the case for all models
  1131 + ControlSamplerateLimits *limits = (channelCount <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single;
  1132 + emit samplerateLimitsChanged((double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler, limits->max);
  1133 +
  1134 + // Samplerate differs for fast rate mode, recalculate it
  1135 + this->restoreTargets();
919 1136 }
920 1137  
921 1138 return Dso::ERROR_NONE;
... ... @@ -1166,7 +1383,7 @@ namespace Hantek {
1166 1383 switch(this->specification.command.bulk.setPretrigger) {
1167 1384 case BULK_SETTRIGGERANDSAMPLERATE: {
1168 1385 // Calculate the position value (Start point depending on record length)
1169   - unsigned long int position = 0x7ffff - this->specification.recordLengths[this->settings.recordLengthId] + positionSamples;
  1386 + unsigned long int position = 0x7ffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
1170 1387  
1171 1388 // SetTriggerAndSamplerate bulk command for trigger position
1172 1389 static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setTriggerPosition(position);
... ... @@ -1176,7 +1393,7 @@ namespace Hantek {
1176 1393 }
1177 1394 case BULK_FSETBUFFER: {
1178 1395 // Calculate the position values (Inverse, maximum is 0x7ffff)
1179   - unsigned long int positionPre = 0x7fffful - this->specification.recordLengths[this->settings.recordLengthId] + positionSamples;
  1396 + unsigned long int positionPre = 0x7fffful - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
1180 1397 unsigned long int positionPost = 0x7fffful - positionSamples;
1181 1398  
1182 1399 // SetBuffer2250 bulk command for trigger position
... ... @@ -1189,7 +1406,7 @@ namespace Hantek {
1189 1406 }
1190 1407 case BULK_ESETTRIGGERORSAMPLERATE: {
1191 1408 // Calculate the position values (Inverse, maximum is 0xffff)
1192   - unsigned short int positionPre = 0xffff - this->specification.recordLengths[this->settings.recordLengthId] + positionSamples;
  1409 + unsigned short int positionPre = 0xffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
1193 1410 unsigned short int positionPost = 0xffff - positionSamples;
1194 1411  
1195 1412 // SetBuffer5200 bulk command for trigger position
... ...
openhantek/src/hantek/control.h
... ... @@ -6,7 +6,7 @@
6 6 //
7 7 // Copyright (C) 2008, 2009 Oleg Khudyakov
8 8 // prcoder@potrebitel.ru
9   -// Copyright (C) 2010, 2011 Oliver Haag
  9 +// Copyright (C) 2010 - 2012 Oliver Haag
10 10 // oliver.haag@gmail.com
11 11 //
12 12 // This program is free software: you can redistribute it and/or modify it
... ... @@ -56,7 +56,7 @@ namespace Hantek {
56 56 /// \struct ControlSpecificationCommandsBulk hantek/control.h
57 57 /// \brief Stores the bulk command codes used for this device.
58 58 struct ControlSpecificationCommandsBulk {
59   - BulkCode setFilter; ///< Command for setting used channels
  59 + BulkCode setChannels; ///< Command for setting used channels
60 60 BulkCode setSamplerate; ///< Command for samplerate settings
61 61 BulkCode setGain; ///< Command for gain settings (Usually in combination with CONTROL_SETRELAYS)
62 62 BulkCode setRecordLength; ///< Command for buffer settings
... ... @@ -95,6 +95,8 @@ namespace Hantek {
95 95 struct ControlSamplerateLimits {
96 96 unsigned long int base; ///< The base for sample rate calculations
97 97 unsigned long int max; ///< The maximum sample rate
  98 + unsigned long int maxDownsampler; ///< The maximum downsampling ratio
  99 + QList<unsigned long int> recordLengths; ///< Available record lengths, ULONG_MAX means rolling
98 100 };
99 101  
100 102 //////////////////////////////////////////////////////////////////////////////
... ... @@ -114,7 +116,6 @@ namespace Hantek {
114 116  
115 117 // Limits
116 118 ControlSpecificationSamplerate samplerate; ///< The samplerate specifications
117   - QList<unsigned long int> recordLengths; ///< Available record lengths, ULONG_MAX means rolling
118 119 QList<unsigned long int> bufferDividers; ///< Samplerate dividers for record lengths
119 120 QList<double> gainSteps; ///< Available voltage steps in V/screenheight
120 121 unsigned char sampleSize; ///< Number of bits per sample
... ... @@ -129,12 +130,22 @@ namespace Hantek {
129 130 };
130 131  
131 132 //////////////////////////////////////////////////////////////////////////////
  133 + /// \struct ControlSettingsSamplerateTarget hantek/control.h
  134 + /// \brief Stores the target samplerate settings of the device.
  135 + struct ControlSettingsSamplerateTarget {
  136 + double samplerate; ///< The target samplerate set via setSamplerate
  137 + double duration; ///< The target record time set via setRecordTime
  138 + bool samplerateSet; ///< true means samplerate was set last, false duration
  139 + };
  140 +
  141 + //////////////////////////////////////////////////////////////////////////////
132 142 /// \struct ControlSettingsSamplerate hantek/control.h
133 143 /// \brief Stores the current samplerate settings of the device.
134 144 struct ControlSettingsSamplerate {
  145 + ControlSettingsSamplerateTarget target; ///< The target samplerate values
135 146 ControlSamplerateLimits *limits; ///< The samplerate limits
136   - unsigned long int downsampling; ///< The variable downsampling factor
137   - unsigned long int current; ///< The current samplerate
  147 + unsigned long int downsampler; ///< The variable downsampling factor
  148 + double current; ///< The current samplerate
138 149 };
139 150  
140 151 //////////////////////////////////////////////////////////////////////////////
... ... @@ -182,6 +193,9 @@ namespace Hantek {
182 193 ~Control();
183 194  
184 195 unsigned int getChannelCount();
  196 + QList<unsigned long int> *getAvailableRecordLengths();
  197 + double getMinSamplerate();
  198 + double getMaxSamplerate();
185 199  
186 200 protected:
187 201 void run();
... ... @@ -189,7 +203,10 @@ namespace Hantek {
189 203 unsigned long int calculateTriggerPoint(unsigned long int value);
190 204 int getCaptureState();
191 205 int getSamples(bool process);
  206 + double getBestSamplerate(double samplerate, bool fastRate = false, bool maximum = false, unsigned long int *downsampler = 0);
192 207 unsigned long int updateRecordLength(unsigned long int size);
  208 + unsigned long int updateSamplerate(unsigned long int downsampler, bool fastRate);
  209 + void restoreTargets();
193 210  
194 211 // Communication with device
195 212 Device *device; ///< The USB device for the oscilloscope
... ... @@ -206,14 +223,16 @@ namespace Hantek {
206 223  
207 224 // Results
208 225 QList<double *> samples; ///< Sample data arrays
209   - QList<unsigned int> samplesSize; ///< Number of samples data array
  226 + QList<unsigned long int> samplesSize; ///< Number of samples data array
  227 + unsigned long int previousSampleCount; ///< The expected total number of samples at the last check before sampling started
210 228 QMutex samplesMutex; ///< Mutex for the sample data
211 229  
212 230 public slots:
213 231 virtual void connectDevice();
214 232  
215   - unsigned long int setSamplerate(unsigned long int samplerate = 0);
216 233 unsigned long int setRecordLength(unsigned long int size);
  234 + double setSamplerate(double samplerate = 0.0);
  235 + double setRecordTime(double duration = 0.0);
217 236  
218 237 int setChannelUsed(unsigned int channel, bool used);
219 238 int setCoupling(unsigned int channel, Dso::Coupling coupling);
... ...
openhantek/src/hantek/device.cpp
... ... @@ -5,7 +5,7 @@
5 5 //
6 6 // Copyright (C) 2008, 2009 Oleg Khudyakov
7 7 // prcoder@potrebitel.ru
8   -// Copyright (C) 2010 Oliver Haag
  8 +// Copyright (C) 2010 - 2012 Oliver Haag
9 9 // oliver.haag@gmail.com
10 10 //
11 11 // This program is free software: you can redistribute it and/or modify it
... ... @@ -274,20 +274,21 @@ namespace Hantek {
274 274 }
275 275  
276 276 #if LIBUSB_VERSION != 0
277   - /// \brief Bulk transfer to the oscilloscope.
  277 + /// \brief Bulk transfer to/from the oscilloscope.
278 278 /// \param endpoint Endpoint number, also sets the direction of the transfer.
279 279 /// \param data Buffer for the sent/recieved data.
280 280 /// \param length The length of the packet.
281 281 /// \param attempts The number of attempts, that are done on timeouts.
  282 + /// \param timeout The timeout in ms.
282 283 /// \return Number of transferred bytes on success, libusb error code on error.
283   - int Device::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts) {
  284 + int Device::bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned long int length, int attempts, unsigned int timeout) {
284 285 if(!this->handle)
285 286 return LIBUSB_ERROR_NO_DEVICE;
286 287  
287 288 int errorCode = LIBUSB_ERROR_TIMEOUT;
288 289 int transferred;
289 290 for(int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt)
290   - errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length, &transferred, HANTEK_TIMEOUT);
  291 + errorCode = libusb_bulk_transfer(this->handle, endpoint, data, length, &transferred, timeout);
291 292  
292 293 if(errorCode == LIBUSB_ERROR_NO_DEVICE)
293 294 this->disconnect();
... ... @@ -303,7 +304,7 @@ namespace Hantek {
303 304 /// \param length The length of the packet.
304 305 /// \param attempts The number of attempts, that are done on timeouts.
305 306 /// \return Number of sent bytes on success, libusb error code on error.
306   - int Device::bulkWrite(unsigned char *data, unsigned int length, int attempts) {
  307 + int Device::bulkWrite(unsigned char *data, unsigned long int length, int attempts) {
307 308 if(!this->handle)
308 309 return LIBUSB_ERROR_NO_DEVICE;
309 310  
... ... @@ -330,7 +331,7 @@ namespace Hantek {
330 331 /// \param length The length of the packet.
331 332 /// \param attempts The number of attempts, that are done on timeouts.
332 333 /// \return Number of received bytes on success, libusb error code on error.
333   - int Device::bulkRead(unsigned char *data, unsigned int length, int attempts) {
  334 + int Device::bulkRead(unsigned char *data, unsigned long int length, int attempts) {
334 335 if(!this->handle)
335 336 return LIBUSB_ERROR_NO_DEVICE;
336 337  
... ... @@ -374,7 +375,7 @@ namespace Hantek {
374 375 /// \param length The length of data contained in the packets.
375 376 /// \param attempts The number of attempts, that are done on timeouts.
376 377 /// \return Number of received bytes on success, libusb error code on error.
377   - int Device::bulkReadMulti(unsigned char *data, unsigned int length, int attempts) {
  378 + int Device::bulkReadMulti(unsigned char *data, unsigned long int length, int attempts) {
378 379 if(!this->handle)
379 380 return LIBUSB_ERROR_NO_DEVICE;
380 381  
... ... @@ -385,14 +386,14 @@ namespace Hantek {
385 386 return errorCode;
386 387  
387 388 errorCode = this->inPacketLength;
388   - unsigned int packet, received = 0;
  389 + unsigned long int packet, received = 0;
389 390 for(packet = 0; received < length && errorCode == this->inPacketLength; ++packet) {
390 391 #if LIBUSB_VERSION == 0
391 392 errorCode = LIBUSB_ERROR_TIMEOUT;
392 393 for(int attempt = 0; (attempt < attempts || attempts == -1) && errorCode == LIBUSB_ERROR_TIMEOUT; ++attempt)
393   - errorCode = usb_bulk_read(this->handle, HANTEK_EP_IN, (char *) data + packet * this->inPacketLength, qMin(length - received, (unsigned int) this->inPacketLength), HANTEK_TIMEOUT);
  394 + errorCode = usb_bulk_read(this->handle, HANTEK_EP_IN, (char *) data + packet * this->inPacketLength, qMin(length - received, (unsigned long int) this->inPacketLength), HANTEK_TIMEOUT);
394 395 #else
395   - errorCode = this->bulkTransfer(HANTEK_EP_IN, data + packet * this->inPacketLength, qMin(length - received, (unsigned int) this->inPacketLength), attempts);
  396 + errorCode = this->bulkTransfer(HANTEK_EP_IN, data + packet * this->inPacketLength, qMin(length - received, (unsigned long int) this->inPacketLength), attempts, HANTEK_TIMEOUT_MULTI);
396 397 #endif
397 398 if(errorCode > 0)
398 399 received += errorCode;
... ... @@ -413,7 +414,7 @@ namespace Hantek {
413 414 /// \param index The index field of the packet.
414 415 /// \param attempts The number of attempts, that are done on timeouts.
415 416 /// \return Number of transferred bytes on success, libusb error code on error.
416   - int Device::controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) {
  417 + int Device::controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts) {
417 418 if(!this->handle)
418 419 return LIBUSB_ERROR_NO_DEVICE;
419 420  
... ... @@ -438,7 +439,7 @@ namespace Hantek {
438 439 /// \param index The index field of the packet.
439 440 /// \param attempts The number of attempts, that are done on timeouts.
440 441 /// \return Number of sent bytes on success, libusb error code on error.
441   - int Device::controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) {
  442 + int Device::controlWrite(unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts) {
442 443 if(!this->handle)
443 444 return LIBUSB_ERROR_NO_DEVICE;
444 445  
... ... @@ -453,7 +454,7 @@ namespace Hantek {
453 454 /// \param index The index field of the packet.
454 455 /// \param attempts The number of attempts, that are done on timeouts.
455 456 /// \return Number of received bytes on success, libusb error code on error.
456   - int Device::controlRead(unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts) {
  457 + int Device::controlRead(unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts) {
457 458 if(!this->handle)
458 459 return LIBUSB_ERROR_NO_DEVICE;
459 460  
... ...
openhantek/src/hantek/device.h
... ... @@ -4,10 +4,8 @@
4 4 /// \file hantek/device.h
5 5 /// \brief Declares the Hantek::Device class.
6 6 //
7   -// Copyright (C) 2008, 2009 Oleg Khudyakov
8   -// prcoder@potrebitel.ru
9   -// Copyright (C) 2010 Oliver Haag
10   -// oliver.haag@gmail.com
  7 +/// \copyright (c) 2008, 2009 Oleg Khudyakov <prcoder@potrebitel.ru>
  8 +/// \copyright (c) 2010 - 2012 Oliver Haag <oliver.haag@gmail.com>
11 9 //
12 10 // This program is free software: you can redistribute it and/or modify it
13 11 // under the terms of the GNU General Public License as published by the Free
... ... @@ -62,17 +60,17 @@ namespace Hantek {
62 60  
63 61 // Various methods to handle USB transfers
64 62 #if LIBUSB_VERSION != 0
65   - int bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
  63 + int bulkTransfer(unsigned char endpoint, unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS, unsigned int timeout = HANTEK_TIMEOUT);
66 64 #endif
67   - int bulkWrite(unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
68   - int bulkRead(unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
  65 + int bulkWrite(unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS);
  66 + int bulkRead(unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS);
69 67  
70   - int bulkCommand(Helper::DataArray<unsigned char> *command, int attempts = HANTEK_ATTEMPTS_DEFAULT);
71   - int bulkReadMulti(unsigned char *data, unsigned int length, int attempts = HANTEK_ATTEMPTS_DEFAULT);
  68 + int bulkCommand(Helper::DataArray<unsigned char> *command, int attempts = HANTEK_ATTEMPTS);
  69 + int bulkReadMulti(unsigned char *data, unsigned long int length, int attempts = HANTEK_ATTEMPTS_MULTI);
72 70  
73   - int controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned int length, int value, int index, int attempts = HANTEK_ATTEMPTS_DEFAULT);
74   - int controlWrite(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS_DEFAULT);
75   - int controlRead(unsigned char request, unsigned char *data, unsigned int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS_DEFAULT);
  71 + int controlTransfer(unsigned char type, unsigned char request, unsigned char *data, unsigned long int length, int value, int index, int attempts = HANTEK_ATTEMPTS);
  72 + int controlWrite(unsigned char request, unsigned char *data, unsigned long int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS);
  73 + int controlRead(unsigned char request, unsigned char *data, unsigned long int length, int value = 0, int index = 0, int attempts = HANTEK_ATTEMPTS);
76 74  
77 75 int getConnectionSpeed();
78 76 Model getModel();
... ...
openhantek/src/hantek/types.cpp
... ... @@ -101,24 +101,26 @@ namespace Hantek {
101 101 }
102 102  
103 103 /// \brief Sets the data bytes to the specified values.
104   - /// \param samplerateSlow The SamplerateSlow value.
  104 + /// \param downsampler The Downsampler value.
105 105 /// \param triggerPosition The trigger position value.
106 106 /// \param triggerSource The trigger source id (Tsr1).
107 107 /// \param recordLength The record length id (Tsr1).
108   - /// \param samplerateFast The samplerateFast value (Tsr1).
  108 + /// \param samplerateId The samplerateId value (Tsr1).
  109 + /// \param downsamplingMode The downsamplingMode value (Tsr1).
109 110 /// \param usedChannels The enabled channels (Tsr2).
110 111 /// \param fastRate The fastRate state (Tsr2).
111 112 /// \param triggerSlope The triggerSlope value (Tsr2).
112   - 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<unsigned char>(12) {
  113 + 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<unsigned char>(12) {
113 114 this->init();
114 115  
115 116 this->setTriggerSource(triggerSource);
116 117 this->setRecordLength(recordLength);
117   - this->setSamplerateFast(samplerateFast);
  118 + this->setSamplerateId(samplerateId);
  119 + this->setDownsamplingMode(downsamplingMode);
118 120 this->setUsedChannels(usedChannels);
119 121 this->setFastRate(fastRate);
120 122 this->setTriggerSlope(triggerSlope);
121   - this->setSamplerateSlow(samplerateSlow);
  123 + this->setDownsampler(downsampler);
122 124 this->setTriggerPosition(triggerPosition);
123 125 }
124 126  
... ... @@ -146,16 +148,28 @@ namespace Hantek {
146 148 ((Tsr1Bits *) &(this->array[2]))->recordLength = value;
147 149 }
148 150  
149   - /// \brief Get the samplerateFast value in Tsr1Bits.
150   - /// \return The samplerateFast value.
151   - unsigned char BulkSetTriggerAndSamplerate::getSamplerateFast() {
152   - return ((Tsr1Bits *) &(this->array[2]))->samplerateFast;
  151 + /// \brief Get the samplerateId value in Tsr1Bits.
  152 + /// \return The samplerateId value.
  153 + unsigned char BulkSetTriggerAndSamplerate::getSamplerateId() {
  154 + return ((Tsr1Bits *) &(this->array[2]))->samplerateId;
  155 + }
  156 +
  157 + /// \brief Set the samplerateId in Tsr1Bits to the given value.
  158 + /// \param value The new samplerateId value.
  159 + void BulkSetTriggerAndSamplerate::setSamplerateId(unsigned char value) {
  160 + ((Tsr1Bits *) &(this->array[2]))->samplerateId = value;
153 161 }
154 162  
155   - /// \brief Set the samplerateFast in Tsr1Bits to the given value.
156   - /// \param value The new samplerateFast value.
157   - void BulkSetTriggerAndSamplerate::setSamplerateFast(unsigned char value) {
158   - ((Tsr1Bits *) &(this->array[2]))->samplerateFast = value;
  163 + /// \brief Get the downsamplerMode value in Tsr1Bits.
  164 + /// \return The downsamplerMode value.
  165 + bool BulkSetTriggerAndSamplerate::getDownsamplingMode() {
  166 + return ((Tsr1Bits *) &(this->array[2]))->downsamplingMode == 1;
  167 + }
  168 +
  169 + /// \brief Set the downsamplerMode in Tsr1Bits to the given value.
  170 + /// \param downsampling The new downsamplerMode value.
  171 + void BulkSetTriggerAndSamplerate::setDownsamplingMode(bool downsampling) {
  172 + ((Tsr1Bits *) &(this->array[2]))->downsamplingMode = downsampling ? 1 : 0;
159 173 }
160 174  
161 175 /// \brief Get the usedChannels value in Tsr2Bits.
... ... @@ -194,17 +208,17 @@ namespace Hantek {
194 208 ((Tsr2Bits *) &(this->array[3]))->triggerSlope = slope;
195 209 }
196 210  
197   - /// \brief Get the SamplerateSlow value.
198   - /// \return The SamplerateSlow value.
199   - unsigned short int BulkSetTriggerAndSamplerate::getSamplerateSlow() {
  211 + /// \brief Get the Downsampler value.
  212 + /// \return The Downsampler value.
  213 + unsigned short int BulkSetTriggerAndSamplerate::getDownsampler() {
200 214 return (unsigned short int) this->array[4] | ((unsigned short int) this->array[5] << 8);
201 215 }
202 216  
203   - /// \brief Set the SamplerateSlow to the given value.
204   - /// \param samplerate The new SamplerateSlow value.
205   - void BulkSetTriggerAndSamplerate::setSamplerateSlow(unsigned short int samplerate) {
206   - this->array[4] = (unsigned char) samplerate;
207   - this->array[5] = (unsigned char) (samplerate >> 8);
  217 + /// \brief Set the Downsampler to the given value.
  218 + /// \param downsampler The new Downsampler value.
  219 + void BulkSetTriggerAndSamplerate::setDownsampler(unsigned short int downsampler) {
  220 + this->array[4] = (unsigned char) downsampler;
  221 + this->array[5] = (unsigned char) (downsampler >> 8);
208 222 }
209 223  
210 224 /// \brief Get the TriggerPosition value.
... ... @@ -328,8 +342,6 @@ namespace Hantek {
328 342 /// \brief Initialize the array to the needed values.
329 343 void BulkSetGain::init() {
330 344 this->array[0] = BULK_SETGAIN;
331   - this->array[1] = 0x0f;
332   - ((GainBits *) &(this->array[2]))->reserved = 3;
333 345 }
334 346  
335 347  
... ... @@ -363,7 +375,6 @@ namespace Hantek {
363 375 /// \brief Initialize the array to the needed values.
364 376 void BulkSetLogicalData::init() {
365 377 this->array[0] = BULK_SETLOGICALDATA;
366   - this->array[1] = 0x0f;
367 378 }
368 379  
369 380  
... ... @@ -378,45 +389,33 @@ namespace Hantek {
378 389 //////////////////////////////////////////////////////////////////////////////
379 390 // class BulkSetFilter2250
380 391 /// \brief Sets the data array to needed values.
381   - BulkSetFilter2250::BulkSetFilter2250() : Helper::DataArray<unsigned char>(4) {
  392 + BulkSetChannels2250::BulkSetChannels2250() : Helper::DataArray<unsigned char>(4) {
382 393 this->init();
383 394 }
384 395  
385 396 /// \brief Sets the used channels.
386   - /// \param channel1 true if channel 1 is filtered.
387   - /// \param channel2 true if channel 2 is filtered.
388   - BulkSetFilter2250::BulkSetFilter2250(bool channel1, bool channel2) : Helper::DataArray<unsigned char>(4) {
  397 + /// \param usedChannels The UsedChannels value.
  398 + BulkSetChannels2250::BulkSetChannels2250(unsigned char usedChannels) : Helper::DataArray<unsigned char>(4) {
389 399 this->init();
390 400  
391   - this->setChannel(0, channel1);
392   - this->setChannel(1, channel2);
  401 + this->setUsedChannels(usedChannels);
393 402 }
394 403  
395   - /// \brief Gets the filtering state of one channel.
396   - /// \param channel The channel whose filtering state should be returned.
397   - /// \return The filtering state of the channel.
398   - bool BulkSetFilter2250::getChannel(unsigned int channel) {
399   - FilterBits *filterBits = (FilterBits *) &(this->array[2]);
400   - if(channel == 0)
401   - return filterBits->channel1 == 1;
402   - else
403   - return filterBits->channel2 == 1;
  404 + /// \brief Get the UsedChannels value
  405 + /// \return The UsedChannels value.
  406 + unsigned char BulkSetChannels2250::getUsedChannels() {
  407 + return this->array[2];
404 408 }
405 409  
406   - /// \brief Enables/disables filtering of one channel.
407   - /// \param channel The channel that should be set.
408   - /// \param filtered true if the channel should be filtered.
409   - void BulkSetFilter2250::setChannel(unsigned int channel, bool filtered) {
410   - FilterBits *filterBits = (FilterBits *) &(this->array[2]);
411   - if(channel == 0)
412   - filterBits->channel1 = filtered ? 1 : 0;
413   - else
414   - filterBits->channel2 = filtered ? 1 : 0;
  410 + /// \brief Set the UsedChannels to the given value.
  411 + /// \param value The new UsedChannels value.
  412 + void BulkSetChannels2250::setUsedChannels(unsigned char value) {
  413 + this->array[2] = value;
415 414 }
416 415  
417 416 /// \brief Initialize the array to the needed values.
418   - void BulkSetFilter2250::init() {
419   - this->array[0] = BULK_BSETFILTER;
  417 + void BulkSetChannels2250::init() {
  418 + this->array[0] = BULK_BSETCHANNELS;
420 419 }
421 420  
422 421  
... ...
openhantek/src/hantek/types.h
... ... @@ -36,7 +36,9 @@
36 36 #define HANTEK_EP_OUT 0x02 ///< OUT Endpoint for bulk transfers
37 37 #define HANTEK_EP_IN 0x86 ///< IN Endpoint for bulk transfers
38 38 #define HANTEK_TIMEOUT 500 ///< Timeout for USB transfers in ms
39   -#define HANTEK_ATTEMPTS_DEFAULT 3 ///< The number of transfer attempts
  39 +#define HANTEK_TIMEOUT_MULTI 10 ///< Timeout for multi packet USB transfers in ms
  40 +#define HANTEK_ATTEMPTS 3 ///< The number of transfer attempts
  41 +#define HANTEK_ATTEMPTS_MULTI 1 ///< The number of multi packet transfer attempts
40 42  
41 43 #define HANTEK_CHANNELS 2 ///< Number of physical channels
42 44 #define HANTEK_SPECIAL_CHANNELS 2 ///< Number of special channels
... ... @@ -57,7 +59,7 @@ namespace Hantek {
57 59 /// <table>
58 60 /// <tr>
59 61 /// <td>0x00</td>
60   - /// <td>0x0f</td>
  62 + /// <td>0x00</td>
61 63 /// <td>FilterBits</td>
62 64 /// <td>0x00</td>
63 65 /// <td>0x00</td>
... ... @@ -67,6 +69,8 @@ namespace Hantek {
67 69 /// </tr>
68 70 /// </table>
69 71 /// </p>
  72 + /// <p>
  73 + /// This command is used by the official %Hantek software, but doesn't seem to be used by the device.
70 74 /// <p><br /></p>
71 75 BULK_SETFILTER,
72 76  
... ... @@ -79,8 +83,8 @@ namespace Hantek {
79 83 /// <td>0x00</td>
80 84 /// <td>Tsr1Bits</td>
81 85 /// <td>Tsr2Bits</td>
82   - /// <td>SamplerateSlow[0]</td>
83   - /// <td>SamplerateSlow[1]</td>
  86 + /// <td>Downsampler[0]</td>
  87 + /// <td>Downsampler[1]</td>
84 88 /// </tr>
85 89 /// </table>
86 90 /// <table>
... ... @@ -95,11 +99,20 @@ namespace Hantek {
95 99 /// </table>
96 100 /// </p>
97 101 /// <p>
98   - /// 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.<br />
99   - /// Without using fast rate mode, the samplerate is:<br />
100   - /// <i>Samplerate = SamplerateMax / (1comp(SamplerateSlow) * 2 + Tsr1Bits.samplerateFast)</i><br />
101   - /// SamplerateMax is 50 MHz for the DSO-2090.<br />
102   - /// 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.
  102 + /// The samplerate is set relative to the base samplerate by a divider or to a maximum samplerate.<br />
  103 + /// This divider is set by Tsr1Bits.samplerateId for values up to 5 with to the following values:
  104 + /// <table>
  105 + /// <tr>
  106 + /// <td><b>Tsr1Bits.samplerateId</b></td><td>0</td><td>1</td><td>2</td><td>3</td>
  107 + /// </tr>
  108 + /// <tr>
  109 + /// <td><b>Samplerate</b></td><td>Max</td><td>Base</td><td>Base / 2</td><td>Base / 5</td>
  110 + /// </tr>
  111 + /// </table>
  112 + /// 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:<br />
  113 + /// <i>Downsampler = 1comp((Base / Samplerate / 2) - 2)</i><br />
  114 + /// 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.<br />
  115 + /// 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.
103 116 /// </p>
104 117 /// <p>
105 118 /// 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 {
225 238 /// <table>
226 239 /// <tr>
227 240 /// <td>0x07</td>
228   - /// <td>0x0f</td>
  241 + /// <td>0x00</td>
229 242 /// <td>GainBits</td>
230 243 /// <td>0x00</td>
231 244 /// <td>0x00</td>
... ... @@ -245,7 +258,7 @@ namespace Hantek {
245 258 /// <table>
246 259 /// <tr>
247 260 /// <td>0x08</td>
248   - /// <td>0x0f</td>
  261 + /// <td>0x00</td>
249 262 /// <td>Data | 0x01</td>
250 263 /// <td>0x00</td>
251 264 /// <td>0x00</td>
... ... @@ -293,20 +306,20 @@ namespace Hantek {
293 306 /// <p><br /></p>
294 307 BULK_AUNKNOWN,
295 308  
296   - /// BulkSetFilter2250 [<em>::MODEL_DSO2250</em>]
  309 + /// BulkSetChannels2250 [<em>::MODEL_DSO2250</em>]
297 310 /// <p>
298 311 /// This command sets the activated channels for the DSO-2250:
299 312 /// <table>
300 313 /// <tr>
301 314 /// <td>0x0b</td>
302 315 /// <td>0x00</td>
303   - /// <td>FilterBits</td>
  316 + /// <td>BUsedChannels</td>
304 317 /// <td>0x00</td>
305 318 /// </tr>
306 319 /// </table>
307 320 /// </p>
308 321 /// <p><br /></p>
309   - BULK_BSETFILTER,
  322 + BULK_BSETCHANNELS,
310 323  
311 324 /// BulkSetTrigger2250 [<em>::MODEL_DSO2250</em>]
312 325 /// <p>
... ... @@ -314,10 +327,10 @@ namespace Hantek {
314 327 /// <table>
315 328 /// <tr>
316 329 /// <td>0x0c</td>
317   - /// <td>0x0f</td>
  330 + /// <td>0x00</td>
318 331 /// <td>CTriggerBits</td>
319 332 /// <td>0x00</td>
320   - /// <td>0x02</td>
  333 + /// <td>0x00</td>
321 334 /// <td>0x00</td>
322 335 /// <td>0x00</td>
323 336 /// <td>0x00</td>
... ... @@ -340,9 +353,10 @@ namespace Hantek {
340 353 /// </table>
341 354 /// </p>
342 355 /// <p>
343   - /// The values are similar to the ones used with ::BULK_SETTRIGGERANDSAMPLERATE. The formula is a bit different here:<br />
  356 + /// 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.<br />
  357 + /// Without using fast rate mode, the samplerate is:<br />
344 358 /// <i>Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + 4 - SamplerateFast)</i><br />
345   - /// 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.
  359 + /// 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.
346 360 /// </p>
347 361 /// <p><br /></p>
348 362 BULK_CSETTRIGGERORSAMPLERATE,
... ... @@ -397,17 +411,17 @@ namespace Hantek {
397 411 /// <td>0x00</td>
398 412 /// <td>ESamplerateBits</td>
399 413 /// <td>0x00</td>
400   - /// <td>SamplerateSlow[0]</td>
401   - /// <td>SamplerateSlow[1]</td>
  414 + /// <td>Samplerate[0]</td>
  415 + /// <td>Samplerate[1]</td>
402 416 /// <td>0x00</td>
403 417 /// <td>0x00</td>
404 418 /// </tr>
405 419 /// </table>
406 420 /// </p>
407 421 /// <p>
408   - /// The values are similar to the ones used with ::BULK_SETTRIGGERANDSAMPLERATE. The formula is a bit different here:<br />
409   - /// <i>Samplerate = SamplerateMax / (2comp(SamplerateSlow) * 2 + ESamplerateBits.samplerateFast)</i><br />
410   - /// 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.
  422 + /// The downsampler can be activated by setting ESamplerateBits.downsampling = 1. If this is the case, the value of Downsampler is given by:<br />
  423 + /// <i>Downsampler = 1comp((Base / Samplerate) - 2)</i><br />
  424 + /// 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.
411 425 /// </p>
412 426 /// <p><br /></p>
413 427 /// BulkSetTrigger5200 [<em>::MODEL_DSO5200, ::MODEL_DSO5200A</em>]
... ... @@ -436,25 +450,25 @@ namespace Hantek {
436 450 /// <tr>
437 451 /// <td>0x0f</td>
438 452 /// <td>0x00</td>
439   - /// <td>TriggerPositionPre[0]</td>
440   - /// <td>TriggerPositionPre[1]</td>
441   - /// <td>FBuffer1Bits</td>
  453 + /// <td>TriggerPositionPost[0]</td>
  454 + /// <td>TriggerPositionPost[1]</td>
  455 + /// <td>TriggerPositionPost[2]</td>
442 456 /// <td>0x00</td>
443 457 /// </tr>
444 458 /// </table>
445 459 /// <table>
446 460 /// <tr>
447   - /// <td>TriggerPositionPost[0]</td>
448   - /// <td>TriggerPositionPost[1]</td>
449   - /// <td>FBuffer1Bits</td>
  461 + /// <td>TriggerPositionPre[0]</td>
  462 + /// <td>TriggerPositionPre[1]</td>
  463 + /// <td>TriggerPositionPre[2]</td>
  464 + /// <td>0x00</td>
450 465 /// <td>0x00</td>
451   - /// <td>FBuffer2Bits</td>
452 466 /// <td>0x00</td>
453 467 /// </tr>
454 468 /// </table>
455 469 /// </p>
456 470 /// <p>
457   - /// 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%.
  471 + /// 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%.
458 472 /// </p>
459 473 /// <p><br /></p>
460 474 BULK_FSETBUFFER,
... ... @@ -703,6 +717,16 @@ namespace Hantek {
703 717 };
704 718  
705 719 //////////////////////////////////////////////////////////////////////////////
  720 + /// \enum BUsedChannels hantek/types.h
  721 + /// \brief The enabled channels for the DSO-2250.
  722 + enum BUsedChannels {
  723 + BUSED_CH1, ///< Only channel 1 is activated
  724 + BUSED_NONE, ///< No channels are activated
  725 + BUSED_CH1CH2, ///< Channel 1 and 2 are both activated
  726 + BUSED_CH2 ///< Only channel 2 is activated
  727 + };
  728 +
  729 + //////////////////////////////////////////////////////////////////////////////
706 730 /// \enum DTriggerPositionUsed hantek/types.h
707 731 /// \brief The trigger position states for the 0x0d command.
708 732 enum DTriggerPositionUsed {
... ... @@ -711,14 +735,6 @@ namespace Hantek {
711 735 };
712 736  
713 737 //////////////////////////////////////////////////////////////////////////////
714   - /// \enum FTriggerPositionUsed hantek/types.h
715   - /// \brief The trigger position states for the 0x0f command.
716   - enum FTriggerPositionUsed {
717   - FTRIGGERPOSITION_OFF = 0, ///< Used for Roll mode
718   - FTRIGGERPOSITION_ON = 3 ///< Used for normal operation
719   - };
720   -
721   - //////////////////////////////////////////////////////////////////////////////
722 738 /// \struct FilterBits hantek/types.h
723 739 /// \brief The bits for BULK_SETFILTER.
724 740 struct FilterBits {
... ... @@ -743,7 +759,8 @@ namespace Hantek {
743 759 struct Tsr1Bits {
744 760 unsigned char triggerSource:2; ///< The trigger source, see Hantek::TriggerSource
745 761 unsigned char recordLength:3; ///< See ::RecordLengthId
746   - unsigned char samplerateFast:3; ///< samplerate value for fast sampling rates
  762 + unsigned char samplerateId:2; ///< Samplerate ID when downsampler is disabled
  763 + unsigned char downsamplingMode:1; ///< true, if Downsampler is used
747 764 };
748 765  
749 766 //////////////////////////////////////////////////////////////////////////////
... ... @@ -795,23 +812,6 @@ namespace Hantek {
795 812 };
796 813  
797 814 //////////////////////////////////////////////////////////////////////////////
798   - /// \struct FBuffer1Bits hantek/types.h
799   - /// \brief Buffer mode bits for 0x0f command (Byte 1).
800   - struct FBuffer1Bits {
801   - unsigned char triggerPositionUsed:2; ///< See ::DTriggerPositionUsed
802   - unsigned char largeBuffer:1; ///< false, if ::RecordLengthId is ::RECORDLENGTHID_LARGE
803   - unsigned char reserved:5; ///< Unused bits
804   - };
805   -
806   - //////////////////////////////////////////////////////////////////////////////
807   - /// \struct FBuffer2Bits hantek/types.h
808   - /// \brief Buffer mode bits for 0x0f command (Byte 2).
809   - struct FBuffer2Bits {
810   - unsigned char reserved:7; ///< Unused bits
811   - unsigned char slowBuffer:1; ///< false, if ::RecordLengthId is ::RECORDLENGTHID_SMALL
812   - };
813   -
814   - //////////////////////////////////////////////////////////////////////////////
815 815 /// \class BulkSetFilter hantek/types.h
816 816 /// \brief The BULK_SETFILTER builder.
817 817 class BulkSetFilter : public Helper::DataArray<unsigned char> {
... ... @@ -834,22 +834,24 @@ namespace Hantek {
834 834 class BulkSetTriggerAndSamplerate : public Helper::DataArray<unsigned char> {
835 835 public:
836 836 BulkSetTriggerAndSamplerate();
837   - 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);
  837 + 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);
838 838  
839 839 unsigned char getTriggerSource();
840 840 void setTriggerSource(unsigned char value);
841 841 unsigned char getRecordLength();
842 842 void setRecordLength(unsigned char value);
843   - unsigned char getSamplerateFast();
844   - void setSamplerateFast(unsigned char value);
  843 + unsigned char getSamplerateId();
  844 + void setSamplerateId(unsigned char value);
  845 + bool getDownsamplingMode();
  846 + void setDownsamplingMode(bool downsampling);
845 847 unsigned char getUsedChannels();
846 848 void setUsedChannels(unsigned char value);
847 849 bool getFastRate();
848 850 void setFastRate(bool fastRate);
849 851 unsigned char getTriggerSlope();
850 852 void setTriggerSlope(unsigned char slope);
851   - unsigned short int getSamplerateSlow();
852   - void setSamplerateSlow(unsigned short int samplerate);
  853 + unsigned short int getDownsampler();
  854 + void setDownsampler(unsigned short int downsampler);
853 855 unsigned long int getTriggerPosition();
854 856 void setTriggerPosition(unsigned long int position);
855 857  
... ... @@ -947,15 +949,15 @@ namespace Hantek {
947 949 };
948 950  
949 951 //////////////////////////////////////////////////////////////////////////////
950   - /// \class BulkSetFilter2250 hantek/types.h
  952 + /// \class BulkSetChannels2250 hantek/types.h
951 953 /// \brief The DSO-2250 BULK_BSETFILTER builder.
952   - class BulkSetFilter2250 : public Helper::DataArray<unsigned char> {
  954 + class BulkSetChannels2250 : public Helper::DataArray<unsigned char> {
953 955 public:
954   - BulkSetFilter2250();
955   - BulkSetFilter2250(bool channel1, bool channel2);
  956 + BulkSetChannels2250();
  957 + BulkSetChannels2250(unsigned char usedChannels);
956 958  
957   - bool getChannel(unsigned int channel);
958   - void setChannel(unsigned int channel, bool filtered);
  959 + unsigned char getUsedChannels();
  960 + void setUsedChannels(unsigned char value);
959 961  
960 962 private:
961 963 void init();
... ...
openhantek/src/openhantek.cpp
... ... @@ -92,61 +92,12 @@ OpenHantekMainWindow::OpenHantekMainWindow(QWidget *parent, Qt::WindowFlags flag
92 92 this->settings->options.window.position = this->pos();
93 93 this->settings->options.window.size = this->size();
94 94  
95   - // Connect general signals
96   - connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
97   - //connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
98   - connect(this->dsoControl, SIGNAL(statusMessage(QString, int)), this->statusBar(), SLOT(showMessage(QString, int)));
99   - connect(this->dsoControl, SIGNAL(samplesAvailable(const QList<double *> *, const QList<unsigned int> *, double, QMutex *)), this->dataAnalyzer, SLOT(analyze(const QList<double *> *, const QList<unsigned int> *, double, QMutex *)));
100   -
101   - // Connect signals to DSO controller and widget
102   - //connect(this->horizontalDock, SIGNAL(formatChanged(HorizontalFormat)), this->dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
103   - connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this, SLOT(updateTimebase()));
104   - connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this->dsoWidget, SLOT(updateTimebase()));
105   - connect(this->horizontalDock, SIGNAL(frequencybaseChanged(double)), this->dsoWidget, SLOT(updateFrequencybase()));
106   -
107   - connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoControl, SLOT(setTriggerMode(Dso::TriggerMode)));
108   - connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoWidget, SLOT(updateTriggerMode()));
109   - connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoControl, SLOT(setTriggerSource(bool, unsigned int)));
110   - connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoWidget, SLOT(updateTriggerSource()));
111   - connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoControl, SLOT(setTriggerSlope(Dso::Slope)));
112   - connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoWidget, SLOT(updateTriggerSlope()));
113   - connect(this->dsoWidget, SIGNAL(triggerPositionChanged(double)), this->dsoControl, SLOT(setPretriggerPosition(double)));
114   - connect(this->dsoWidget, SIGNAL(triggerLevelChanged(unsigned int, double)), this->dsoControl, SLOT(setTriggerLevel(unsigned int, double)));
115   -
116   - connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
117   - connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateVoltageUsed(unsigned int, bool)));
118   - connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoControl, SLOT(setCoupling(unsigned int, Dso::Coupling)));
119   - connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoWidget, SLOT(updateVoltageCoupling(unsigned int)));
120   - connect(this->voltageDock, SIGNAL(modeChanged(Dso::MathMode)), this->dsoWidget, SLOT(updateMathMode()));
121   - connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this, SLOT(updateVoltageGain(unsigned int)));
122   - connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this->dsoWidget, SLOT(updateVoltageGain(unsigned int)));
123   - connect(this->dsoWidget, SIGNAL(offsetChanged(unsigned int, double)), this, SLOT(updateOffset(unsigned int)));
124   -
125   - connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
126   - connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool)));
127   - connect(this->spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)), this->dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int)));
128   -
129   - // Started/stopped signals from oscilloscope
130   - connect(this->dsoControl, SIGNAL(samplingStarted()), this, SLOT(started()));
131   - connect(this->dsoControl, SIGNAL(samplingStopped()), this, SLOT(stopped()));
  95 + // Connect all signals
  96 + this->connectSignals();
132 97  
133 98 // Set up the oscilloscope
134 99 this->dsoControl->connectDevice();
135   -
136   - for(unsigned int channel = 0; channel < this->settings->scope.physicalChannels; ++channel) {
137   - this->dsoControl->setCoupling(channel, (Dso::Coupling) this->settings->scope.voltage[channel].misc);
138   - this->updateVoltageGain(channel);
139   - this->updateOffset(channel);
140   - this->dsoControl->setTriggerLevel(channel, this->settings->scope.voltage[channel].trigger);
141   - }
142   - this->updateUsed(this->settings->scope.physicalChannels);
143   - this->dsoControl->setRecordLength(this->settings->scope.horizontal.samples);
144   - this->updateTimebase();
145   - this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode);
146   - this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
147   - this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope);
148   - this->dsoControl->setTriggerSource(this->settings->scope.trigger.special, this->settings->scope.trigger.source);
149   -
  100 + this->initializeDevice();
150 101 this->dsoControl->startSampling();
151 102 }
152 103  
... ... @@ -202,21 +153,6 @@ void OpenHantekMainWindow::createActions() {
202 153 this->startStopAction = new QAction(this);
203 154 this->startStopAction->setShortcut(tr("Space"));
204 155 this->stopped();
205   -
206   - this->recordLengthActionGroup = new QActionGroup(this);
207   - connect(this->recordLengthActionGroup, SIGNAL(selected(QAction *)), this, SLOT(recordLengthSelected(QAction *)));
208   -
209   - this->recordLengthSmallAction = new QAction(tr("&Small"), this);
210   - this->recordLengthSmallAction->setActionGroup(this->recordLengthActionGroup);
211   - this->recordLengthSmallAction->setCheckable(true);
212   - this->recordLengthSmallAction->setChecked(this->settings->scope.horizontal.samples == 10240);
213   - this->recordLengthSmallAction->setStatusTip(tr("10240 Samples"));
214   -
215   - this->recordLengthLargeAction = new QAction(tr("&Large"), this);
216   - this->recordLengthLargeAction->setActionGroup(this->recordLengthActionGroup);
217   - this->recordLengthLargeAction->setCheckable(true);
218   - this->recordLengthLargeAction->setChecked(this->settings->scope.horizontal.samples != 10240);
219   - this->recordLengthLargeAction->setStatusTip(tr("32768 Samples"));
220 156  
221 157 this->digitalPhosphorAction = new QAction(QIcon(":actions/digitalphosphor.png"), tr("Digital &phosphor"), this);
222 158 this->digitalPhosphorAction->setCheckable(true);
... ... @@ -276,12 +212,9 @@ void OpenHantekMainWindow::createMenus() {
276 212 this->oscilloscopeMenu->addSeparator();
277 213 this->oscilloscopeMenu->addAction(this->startStopAction);
278 214 #ifdef DEBUG
  215 + this->oscilloscopeMenu->addSeparator();
279 216 this->oscilloscopeMenu->addAction(this->commandAction);
280 217 #endif
281   - this->oscilloscopeMenu->addSeparator();
282   - this->recordLengthMenu = this->oscilloscopeMenu->addMenu(tr("&Record length"));
283   - this->recordLengthMenu->addAction(this->recordLengthSmallAction);
284   - this->recordLengthMenu->addAction(this->recordLengthLargeAction);
285 218  
286 219 this->menuBar()->addSeparator();
287 220  
... ... @@ -337,6 +270,82 @@ void OpenHantekMainWindow::createDockWindows()
337 270 this->voltageDock = new VoltageDock(this->settings);
338 271 }
339 272  
  273 +/// \brief Connect general signals and device management signals.
  274 +void OpenHantekMainWindow::connectSignals() {
  275 + // Connect general signals
  276 + connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
  277 + //connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
  278 + connect(this->dsoControl, SIGNAL(statusMessage(QString, int)), this->statusBar(), SLOT(showMessage(QString, int)));
  279 + connect(this->dsoControl, SIGNAL(samplesAvailable(const QList<double *> *, const QList<unsigned long int> *, double, QMutex *)), this->dataAnalyzer, SLOT(analyze(const QList<double *> *, const QList<unsigned long int> *, double, QMutex *)));
  280 +
  281 + // Connect signals to DSO controller and widget
  282 + connect(this->horizontalDock, SIGNAL(samplerateChanged(double)), this, SLOT(samplerateSelected()));
  283 + connect(this->horizontalDock, SIGNAL(timebaseChanged(double)), this, SLOT(timebaseSelected()));
  284 + connect(this->horizontalDock, SIGNAL(frequencybaseChanged(double)), this->dsoWidget, SLOT(updateFrequencybase(double)));
  285 + connect(this->horizontalDock, SIGNAL(recordLengthChanged(unsigned long)), this, SLOT(recordLengthSelected(unsigned long)));
  286 + //connect(this->horizontalDock, SIGNAL(formatChanged(HorizontalFormat)), this->dsoWidget, SLOT(horizontalFormatChanged(HorizontalFormat)));
  287 +
  288 + connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoControl, SLOT(setTriggerMode(Dso::TriggerMode)));
  289 + connect(this->triggerDock, SIGNAL(modeChanged(Dso::TriggerMode)), this->dsoWidget, SLOT(updateTriggerMode()));
  290 + connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoControl, SLOT(setTriggerSource(bool, unsigned int)));
  291 + connect(this->triggerDock, SIGNAL(sourceChanged(bool, unsigned int)), this->dsoWidget, SLOT(updateTriggerSource()));
  292 + connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoControl, SLOT(setTriggerSlope(Dso::Slope)));
  293 + connect(this->triggerDock, SIGNAL(slopeChanged(Dso::Slope)), this->dsoWidget, SLOT(updateTriggerSlope()));
  294 + connect(this->dsoWidget, SIGNAL(triggerPositionChanged(double)), this->dsoControl, SLOT(setPretriggerPosition(double)));
  295 + connect(this->dsoWidget, SIGNAL(triggerLevelChanged(unsigned int, double)), this->dsoControl, SLOT(setTriggerLevel(unsigned int, double)));
  296 +
  297 + connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
  298 + connect(this->voltageDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateVoltageUsed(unsigned int, bool)));
  299 + connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoControl, SLOT(setCoupling(unsigned int, Dso::Coupling)));
  300 + connect(this->voltageDock, SIGNAL(couplingChanged(unsigned int, Dso::Coupling)), this->dsoWidget, SLOT(updateVoltageCoupling(unsigned int)));
  301 + connect(this->voltageDock, SIGNAL(modeChanged(Dso::MathMode)), this->dsoWidget, SLOT(updateMathMode()));
  302 + connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this, SLOT(updateVoltageGain(unsigned int)));
  303 + connect(this->voltageDock, SIGNAL(gainChanged(unsigned int, double)), this->dsoWidget, SLOT(updateVoltageGain(unsigned int)));
  304 + connect(this->dsoWidget, SIGNAL(offsetChanged(unsigned int, double)), this, SLOT(updateOffset(unsigned int)));
  305 +
  306 + connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this, SLOT(updateUsed(unsigned int)));
  307 + connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool)));
  308 + connect(this->spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)), this->dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int)));
  309 +
  310 + // Started/stopped signals from oscilloscope
  311 + connect(this->dsoControl, SIGNAL(samplingStarted()), this, SLOT(started()));
  312 + connect(this->dsoControl, SIGNAL(samplingStopped()), this, SLOT(stopped()));
  313 +
  314 + //connect(this->dsoControl, SIGNAL(recordLengthChanged(unsigned long)), this, SLOT(recordLengthChanged()));
  315 + connect(this->dsoControl, SIGNAL(recordTimeChanged(double)), this, SLOT(recordTimeChanged(double)));
  316 + connect(this->dsoControl, SIGNAL(samplerateChanged(double)), this, SLOT(samplerateChanged(double)));
  317 +
  318 + connect(this->dsoControl, SIGNAL(availableRecordLengthsChanged(QList<unsigned long int>)), this->horizontalDock, SLOT(availableRecordLengthsChanged(QList<unsigned long int>)));
  319 + connect(this->dsoControl, SIGNAL(samplerateLimitsChanged(double, double)), this->horizontalDock, SLOT(samplerateLimitsChanged(double, double)));
  320 +}
  321 +
  322 +/// \brief Initialize the device with the current settings.
  323 +void OpenHantekMainWindow::initializeDevice() {
  324 + for(unsigned int channel = 0; channel < this->settings->scope.physicalChannels; ++channel) {
  325 + this->dsoControl->setCoupling(channel, (Dso::Coupling) this->settings->scope.voltage[channel].misc);
  326 + this->updateVoltageGain(channel);
  327 + this->updateOffset(channel);
  328 + this->dsoControl->setTriggerLevel(channel, this->settings->scope.voltage[channel].trigger);
  329 + }
  330 + this->updateUsed(this->settings->scope.physicalChannels);
  331 + if(this->dsoControl->getAvailableRecordLengths()->isEmpty())
  332 + this->dsoControl->setRecordLength(this->settings->scope.horizontal.recordLength);
  333 + else
  334 + this->dsoControl->setRecordLength(this->dsoControl->getAvailableRecordLengths()->indexOf(this->settings->scope.horizontal.recordLength));
  335 + if(this->settings->scope.horizontal.samplerateSet)
  336 + this->samplerateSelected();
  337 + else
  338 + this->timebaseSelected();
  339 + this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode);
  340 + this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
  341 + this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope);
  342 + this->dsoControl->setTriggerSource(this->settings->scope.trigger.special, this->settings->scope.trigger.source);
  343 +
  344 + // Apply the limits to the dock widgets
  345 + this->horizontalDock->availableRecordLengthsChanged(*this->dsoControl->getAvailableRecordLengths());
  346 + this->horizontalDock->samplerateLimitsChanged(this->dsoControl->getMinSamplerate(), this->dsoControl->getMaxSamplerate());
  347 +}
  348 +
340 349 /// \brief Read the settings from an ini file.
341 350 /// \param fileName Optional filename to export the settings to a specific file.
342 351 /// \return 0 on success, negative on error.
... ... @@ -598,11 +607,47 @@ void OpenHantekMainWindow::updateSettings() {
598 607 }
599 608 }
600 609  
  610 +/// \brief The oscilloscope changed the record time.
  611 +/// \param duration The new record time duration in seconds.
  612 +void OpenHantekMainWindow::recordTimeChanged(double duration) {
  613 + if(this->settings->scope.horizontal.samplerateSet) {
  614 + // The samplerate was set, let's adapt the timebase accordingly
  615 + this->settings->scope.horizontal.timebase = duration / DIVS_TIME;
  616 + this->horizontalDock->setTimebase(this->settings->scope.horizontal.timebase);
  617 + }
  618 +
  619 + // The trigger position should be kept at the same place but the timebase has changed
  620 + this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
  621 +
  622 + this->dsoWidget->updateTimebase(this->settings->scope.horizontal.timebase);
  623 +}
  624 +
  625 +/// \brief The oscilloscope changed the samplerate.
  626 +/// \param samplerate The new samplerate in samples per second.
  627 +void OpenHantekMainWindow::samplerateChanged(double samplerate) {
  628 + if(!this->settings->scope.horizontal.samplerateSet) {
  629 + // The timebase was set, let's adapt the samplerate accordingly
  630 + this->settings->scope.horizontal.samplerate = samplerate;
  631 + this->horizontalDock->setSamplerate(samplerate);
  632 + }
  633 +
  634 + this->dsoWidget->updateSamplerate(samplerate);
  635 +}
  636 +
601 637 /// \brief Apply new record length to settings.
602   -/// \param action The selected record length menu item.
603   -void OpenHantekMainWindow::recordLengthSelected(QAction *action) {
604   - this->settings->scope.horizontal.samples = (action == this->recordLengthSmallAction) ? 10240 : 32768;
605   - this->dsoControl->setRecordLength(this->settings->scope.horizontal.samples);
  638 +/// \param recordLength The selected record length in samples.
  639 +void OpenHantekMainWindow::recordLengthSelected(unsigned long recordLength) {
  640 + this->dsoControl->setRecordLength(recordLength);
  641 +}
  642 +
  643 +/// \brief Sets the samplerate of the oscilloscope.
  644 +void OpenHantekMainWindow::samplerateSelected() {
  645 + this->dsoControl->setSamplerate(this->settings->scope.horizontal.samplerate);
  646 +}
  647 +
  648 +/// \brief Sets the record time of the oscilloscope.
  649 +void OpenHantekMainWindow::timebaseSelected() {
  650 + this->dsoControl->setRecordTime(this->settings->scope.horizontal.timebase * DIVS_TIME);
606 651 }
607 652  
608 653 /// \brief Sets the offset of the oscilloscope for the given channel.
... ... @@ -614,15 +659,6 @@ void OpenHantekMainWindow::updateOffset(unsigned int channel) {
614 659 this->dsoControl->setOffset(channel, (this->settings->scope.voltage[channel].offset / DIVS_VOLTAGE) + 0.5);
615 660 }
616 661  
617   -/// \brief Sets the samplerate of the oscilloscope.
618   -void OpenHantekMainWindow::updateTimebase() {
619   - this->settings->scope.horizontal.samplerate = this->dsoControl->setSamplerate(1e3 / this->settings->scope.horizontal.timebase);
620   - this->dsoWidget->updateSamplerate();
621   -
622   - // The trigger position should be kept at the same place but the timebase has changed
623   - this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
624   -}
625   -
626 662 /// \brief Sets the state of the given oscilloscope channel.
627 663 /// \param channel The channel whose state has changed.
628 664 void OpenHantekMainWindow::updateUsed(unsigned int channel) {
... ...
openhantek/src/openhantek.h
... ... @@ -65,6 +65,10 @@ class OpenHantekMainWindow : public QMainWindow {
65 65 void createToolBars();
66 66 void createStatusBar();
67 67 void createDockWindows();
  68 +
  69 + // Device management
  70 + void connectSignals();
  71 + void initializeDevice();
68 72  
69 73 // Settings
70 74 int readSettings(const QString &fileName = QString());
... ... @@ -81,8 +85,6 @@ class OpenHantekMainWindow : public QMainWindow {
81 85  
82 86 QAction *configAction;
83 87 QAction *startStopAction;
84   - QActionGroup *recordLengthActionGroup;
85   - QAction *recordLengthSmallAction, *recordLengthLargeAction;
86 88 QAction *digitalPhosphorAction, *zoomAction;
87 89  
88 90 QAction *aboutAction, *aboutQtAction;
... ... @@ -94,7 +96,7 @@ class OpenHantekMainWindow : public QMainWindow {
94 96 // Menus
95 97 QMenu *fileMenu;
96 98 QMenu *viewMenu, *dockMenu, *toolbarMenu;
97   - QMenu *oscilloscopeMenu, *recordLengthMenu;
  99 + QMenu *oscilloscopeMenu;
98 100 QMenu *helpMenu;
99 101  
100 102 // Toolbars
... ... @@ -143,9 +145,12 @@ class OpenHantekMainWindow : public QMainWindow {
143 145 void applySettings();
144 146 void updateSettings();
145 147  
146   - void recordLengthSelected(QAction *action);
  148 + void recordTimeChanged(double duration);
  149 + void samplerateChanged(double samplerate);
  150 + void recordLengthSelected(unsigned long recordLength);
  151 + void samplerateSelected();
  152 + void timebaseSelected();
147 153 void updateOffset(unsigned int channel);
148   - void updateTimebase();
149 154 void updateUsed(unsigned int channel);
150 155 void updateVoltageGain(unsigned int channel);
151 156  
... ...
openhantek/src/settings.cpp
... ... @@ -64,8 +64,9 @@ DsoSettings::DsoSettings(QWidget *parent) : QObject(parent) {
64 64 this->scope.horizontal.marker[0] = -1.0;
65 65 this->scope.horizontal.marker[1] = 1.0;
66 66 this->scope.horizontal.timebase = 1e-3;
67   - this->scope.horizontal.samples = 10240;
  67 + this->scope.horizontal.recordLength = 0;
68 68 this->scope.horizontal.samplerate = 1e6;
  69 + this->scope.horizontal.samplerateSet = false;
69 70 // Trigger
70 71 this->scope.trigger.filter = true;
71 72 this->scope.trigger.mode = Dso::TRIGGERMODE_NORMAL;
... ... @@ -276,6 +277,12 @@ int DsoSettings::load(const QString &amp;fileName) {
276 277 }
277 278 if(settingsLoader->contains("timebase"))
278 279 this->scope.horizontal.timebase = settingsLoader->value("timebase").toDouble();
  280 + if(settingsLoader->contains("recordLength"))
  281 + this->scope.horizontal.recordLength = settingsLoader->value("recordLength").toUInt();
  282 + if(settingsLoader->contains("samplerate"))
  283 + this->scope.horizontal.samplerate = settingsLoader->value("samplerate").toDouble();
  284 + if(settingsLoader->contains("samplerateSet"))
  285 + this->scope.horizontal.samplerateSet = settingsLoader->value("samplerateSet").toBool();
279 286 settingsLoader->endGroup();
280 287 // Trigger
281 288 settingsLoader->beginGroup("trigger");
... ... @@ -449,6 +456,9 @@ int DsoSettings::save(const QString &amp;fileName) {
449 456 for(int marker = 0; marker < 2; ++marker)
450 457 settingsSaver->setValue(QString("marker%1").arg(marker), this->scope.horizontal.marker[marker]);
451 458 settingsSaver->setValue("timebase", this->scope.horizontal.timebase);
  459 + settingsSaver->setValue("recordLength", (unsigned int) this->scope.horizontal.recordLength);
  460 + settingsSaver->setValue("samplerate", this->scope.horizontal.samplerate);
  461 + settingsSaver->setValue("samplerateSet", this->scope.horizontal.samplerateSet);
452 462 settingsSaver->endGroup();
453 463 // Trigger
454 464 settingsSaver->beginGroup("trigger");
... ... @@ -457,6 +467,7 @@ int DsoSettings::save(const QString &amp;fileName) {
457 467 settingsSaver->setValue("position", this->scope.trigger.position);
458 468 settingsSaver->setValue("slope", this->scope.trigger.slope);
459 469 settingsSaver->setValue("source", this->scope.trigger.source);
  470 + settingsSaver->setValue("special", this->scope.trigger.special);
460 471 settingsSaver->endGroup();
461 472 // Spectrum
462 473 for(int channel = 0; channel < this->scope.spectrum.count(); ++channel) {
... ...
openhantek/src/settings.h
... ... @@ -93,8 +93,9 @@ struct DsoSettingsScopeHorizontal {
93 93 double frequencybase; ///< Frequencybase in Hz/div
94 94 double marker[2]; ///< Marker positions in div
95 95 double timebase; ///< Timebase in s/div
96   - unsigned long int samples; ///< Sample count
97   - unsigned long int samplerate; ///< The samplerate of the oscilloscope in S
  96 + unsigned long int recordLength; ///< Sample count
  97 + double samplerate; ///< The samplerate of the oscilloscope in S
  98 + bool samplerateSet; ///< The samplerate was set by the user, not the timebase
98 99 };
99 100  
100 101 ////////////////////////////////////////////////////////////////////////////////
... ... @@ -105,8 +106,8 @@ struct DsoSettingsScopeTrigger {
105 106 Dso::TriggerMode mode; ///< Automatic, normal or single trigger
106 107 double position; ///< Horizontal position for pretrigger
107 108 Dso::Slope slope; ///< Rising or falling edge causes trigger
108   - bool special; ///< true if the trigger source is not a standard channel
109 109 unsigned int source; ///< Channel that is used as trigger source
  110 + bool special; ///< true if the trigger source is not a standard channel
110 111 };
111 112  
112 113 ////////////////////////////////////////////////////////////////////////////////
... ...
openhantek/translations/openhantek_de.ts
... ... @@ -270,67 +270,62 @@
270 270 <context>
271 271 <name>DsoWidget</name>
272 272 <message>
273   - <location filename="../src/dsowidget.cpp" line="284"/>
  273 + <location filename="../src/dsowidget.cpp" line="285"/>
274 274 <source>Zoom x%L1</source>
275 275 <translation>Zoom x%L1</translation>
276 276 </message>
277 277 <message>
278   - <location filename="../src/dsowidget.cpp" line="285"/>
279 278 <location filename="../src/dsowidget.cpp" line="286"/>
280   - <location filename="../src/dsowidget.cpp" line="297"/>
281   - <location filename="../src/dsowidget.cpp" line="323"/>
282   - <location filename="../src/dsowidget.cpp" line="330"/>
283   - <location filename="../src/dsowidget.cpp" line="340"/>
  279 + <location filename="../src/dsowidget.cpp" line="287"/>
  280 + <location filename="../src/dsowidget.cpp" line="298"/>
  281 + <location filename="../src/dsowidget.cpp" line="324"/>
  282 + <location filename="../src/dsowidget.cpp" line="332"/>
  283 + <location filename="../src/dsowidget.cpp" line="344"/>
284 284 <source>/div</source>
285 285 <translation>/div</translation>
286 286 </message>
287 287 <message>
288   - <location filename="../src/dsowidget.cpp" line="437"/>
  288 + <location filename="../src/dsowidget.cpp" line="441"/>
289 289 <source>Portable Document Format (*.pdf)</source>
290 290 <translation>Portables Dokumentenformat (*.pdf)</translation>
291 291 </message>
292 292 <message>
293   - <location filename="../src/dsowidget.cpp" line="438"/>
  293 + <location filename="../src/dsowidget.cpp" line="442"/>
294 294 <source>PostScript (*.ps)</source>
295 295 <translation>PostScript (*.ps)</translation>
296 296 </message>
297 297 <message>
298   - <location filename="../src/dsowidget.cpp" line="442"/>
  298 + <location filename="../src/dsowidget.cpp" line="446"/>
299 299 <source>Export file...</source>
300 300 <translation>Datei exportieren...</translation>
301 301 </message>
302 302 <message>
303   - <location filename="../src/dsowidget.cpp" line="477"/>
  303 + <location filename="../src/dsowidget.cpp" line="481"/>
304 304 <source>Marker 1/2</source>
305 305 <translation>Marker 1/2</translation>
306 306 </message>
307 307 <message>
308   - <location filename="../src/dsowidget.cpp" line="309"/>
  308 + <location filename="../src/dsowidget.cpp" line="310"/>
309 309 <source>%L1%</source>
310 310 <translation>%L1%</translation>
311 311 </message>
312 312 <message>
313   - <location filename="../src/dsowidget.cpp" line="310"/>
  313 + <location filename="../src/dsowidget.cpp" line="311"/>
314 314 <source>%1 %2 %3 %4</source>
315 315 <translation>%1 %2 %3 %4</translation>
316 316 </message>
317 317 <message>
318   - <location filename="../src/dsowidget.cpp" line="335"/>
  318 + <location filename="../src/dsowidget.cpp" line="338"/>
319 319 <source>/s</source>
320 320 <translation>/s</translation>
321 321 </message>
322 322 <message>
323   - <location filename="../src/dsowidget.cpp" line="429"/>
324   - <source>%1 S</source>
325   - <translation>%1 S</translation>
326   - </message>
327   - <message>
328   - <location filename="../src/dsowidget.cpp" line="439"/>
  323 + <location filename="../src/dsowidget.cpp" line="443"/>
329 324 <source>Image (*.png *.xpm *.jpg)</source>
330 325 <translation>Bild (*.png *.xpm *.jpg)</translation>
331 326 </message>
332 327 <message>
333   - <location filename="../src/dsowidget.cpp" line="440"/>
  328 + <location filename="../src/dsowidget.cpp" line="444"/>
334 329 <source>Comma-Separated Values (*.csv)</source>
335 330 <translation>Kommagetrennte Werte (*.csv)</translation>
336 331 </message>
... ... @@ -343,42 +338,42 @@
343 338 <translation>Oszillograph drucken</translation>
344 339 </message>
345 340 <message>
346   - <location filename="../src/exporter.cpp" line="127"/>
  341 + <location filename="../src/exporter.cpp" line="129"/>
347 342 <source>%L1%</source>
348 343 <translation>%L1%</translation>
349 344 </message>
350 345 <message>
351   - <location filename="../src/exporter.cpp" line="128"/>
  346 + <location filename="../src/exporter.cpp" line="130"/>
352 347 <source>%1 %2 %3 %4</source>
353 348 <translation>%1 %2 %3 %4</translation>
354 349 </message>
355 350 <message>
356   - <location filename="../src/exporter.cpp" line="132"/>
  351 + <location filename="../src/exporter.cpp" line="134"/>
357 352 <source>%1 S</source>
358 353 <translation>%1 S</translation>
359 354 </message>
360 355 <message>
361   - <location filename="../src/exporter.cpp" line="134"/>
  356 + <location filename="../src/exporter.cpp" line="136"/>
362 357 <source>/s</source>
363 358 <translation>/s</translation>
364 359 </message>
365 360 <message>
366   - <location filename="../src/exporter.cpp" line="136"/>
367 361 <location filename="../src/exporter.cpp" line="138"/>
368   - <location filename="../src/exporter.cpp" line="158"/>
369   - <location filename="../src/exporter.cpp" line="161"/>
370   - <location filename="../src/exporter.cpp" line="191"/>
371   - <location filename="../src/exporter.cpp" line="192"/>
  362 + <location filename="../src/exporter.cpp" line="140"/>
  363 + <location filename="../src/exporter.cpp" line="160"/>
  364 + <location filename="../src/exporter.cpp" line="163"/>
  365 + <location filename="../src/exporter.cpp" line="193"/>
  366 + <location filename="../src/exporter.cpp" line="194"/>
372 367 <source>/div</source>
373 368 <translation>/div</translation>
374 369 </message>
375 370 <message>
376   - <location filename="../src/exporter.cpp" line="186"/>
  371 + <location filename="../src/exporter.cpp" line="188"/>
377 372 <source>Zoom x%L1</source>
378 373 <translation>Zoom x%L1</translation>
379 374 </message>
380 375 <message>
381   - <location filename="../src/exporter.cpp" line="198"/>
  376 + <location filename="../src/exporter.cpp" line="200"/>
382 377 <source>Marker 1/2</source>
383 378 <translation>Marker 1/2</translation>
384 379 </message>
... ... @@ -386,27 +381,27 @@
386 381 <context>
387 382 <name>Hantek::Control</name>
388 383 <message>
389   - <location filename="../src/hantek/control.cpp" line="56"/>
  384 + <location filename="../src/hantek/control.cpp" line="92"/>
390 385 <source>EXT</source>
391 386 <translation>EXT</translation>
392 387 </message>
393 388 <message>
394   - <location filename="../src/hantek/control.cpp" line="56"/>
  389 + <location filename="../src/hantek/control.cpp" line="92"/>
395 390 <source>EXT/10</source>
396 391 <translation>EXT/10</translation>
397 392 </message>
398 393 <message>
399   - <location filename="../src/hantek/control.cpp" line="268"/>
  394 + <location filename="../src/hantek/control.cpp" line="322"/>
400 395 <source>The device has been disconnected</source>
401 396 <translation>Die Verbindung zum Gerรคt wurde getrennt</translation>
402 397 </message>
403 398 <message>
404   - <location filename="../src/hantek/control.cpp" line="527"/>
  399 + <location filename="../src/hantek/control.cpp" line="875"/>
405 400 <source>Unknown model</source>
406 401 <translation>Unbekanntes Modell</translation>
407 402 </message>
408 403 <message>
409   - <location filename="../src/hantek/control.cpp" line="562"/>
  404 + <location filename="../src/hantek/control.cpp" line="985"/>
410 405 <source>Couldn&apos;t get channel level data from oscilloscope</source>
411 406 <translation>Konnte Kanalpegeldaten des Oszilloskops nicht lesen</translation>
412 407 </message>
... ... @@ -414,41 +409,41 @@
414 409 <context>
415 410 <name>Hantek::Device</name>
416 411 <message>
417   - <location filename="../src/hantek/device.cpp" line="71"/>
  412 + <location filename="../src/hantek/device.cpp" line="72"/>
418 413 <source>Can&apos;t search for Hantek oscilloscopes: %1</source>
419 414 <translation>Suche nach Hantek Oszilloskopen fehlgeschlagen: %1</translation>
420 415 </message>
421 416 <message>
422   - <location filename="../src/hantek/device.cpp" line="129"/>
423   - <location filename="../src/hantek/device.cpp" line="210"/>
  417 + <location filename="../src/hantek/device.cpp" line="123"/>
  418 + <location filename="../src/hantek/device.cpp" line="204"/>
424 419 <source>Failed to claim interface %1 of device %2: %3</source>
425 420 <translation>Anforderung der Schnittstelle %1 des Gerรคtes %2 fehlgeschlagen: %3</translation>
426 421 </message>
427 422 <message>
428   - <location filename="../src/hantek/device.cpp" line="149"/>
429   - <location filename="../src/hantek/device.cpp" line="230"/>
  423 + <location filename="../src/hantek/device.cpp" line="143"/>
  424 + <location filename="../src/hantek/device.cpp" line="224"/>
430 425 <source>Device found: Hantek %1 (%2)</source>
431 426 <translation>Gerรคt gefunden: Hantek %1 (%2)</translation>
432 427 </message>
433 428 <message>
434   - <location filename="../src/hantek/device.cpp" line="156"/>
  429 + <location filename="../src/hantek/device.cpp" line="150"/>
435 430 <source>Couldn&apos;t open device %1</source>
436 431 <translation>Konnte Gerรคt %1 nicht รถffnen</translation>
437 432 </message>
438 433 <message>
439   - <location filename="../src/hantek/device.cpp" line="159"/>
440   - <location filename="../src/hantek/device.cpp" line="244"/>
  434 + <location filename="../src/hantek/device.cpp" line="153"/>
  435 + <location filename="../src/hantek/device.cpp" line="238"/>
441 436 <source>No Hantek oscilloscope found</source>
442 437 <translation>Keine Hantek Oszilloskope gefunden</translation>
443 438 </message>
444 439 <message>
445   - <location filename="../src/hantek/device.cpp" line="82"/>
446   - <location filename="../src/hantek/device.cpp" line="169"/>
  440 + <location filename="../src/hantek/device.cpp" line="83"/>
  441 + <location filename="../src/hantek/device.cpp" line="163"/>
447 442 <source>Failed to get device list: %1</source>
448 443 <translation>Abrufen der Gerรคteliste fehlgeschlagen: %1</translation>
449 444 </message>
450 445 <message>
451   - <location filename="../src/hantek/device.cpp" line="240"/>
  446 + <location filename="../src/hantek/device.cpp" line="234"/>
452 447 <source>Couldn&apos;t open device %1: %2</source>
453 448 <translation>Konnte Gerรคt %1 nicht รถffnen: %2</translation>
454 449 </message>
... ... @@ -456,25 +451,41 @@
456 451 <context>
457 452 <name>HorizontalDock</name>
458 453 <message>
459   - <location filename="../src/dockwindows.cpp" line="44"/>
  454 + <location filename="../src/dockwindows.cpp" line="45"/>
460 455 <source>Horizontal</source>
461 456 <translation>Horizontal</translation>
462 457 </message>
463 458 <message>
464   - <location filename="../src/dockwindows.cpp" line="63"/>
  459 + <location filename="../src/dockwindows.cpp" line="49"/>
  460 + <source>Samplerate</source>
  461 + <translation>Samplerate</translation>
  462 + </message>
  463 + <message>
  464 + <location filename="../src/dockwindows.cpp" line="58"/>
465 465 <source>Timebase</source>
466 466 <translation>Zeitbasis</translation>
467 467 </message>
468 468 <message>
469   - <location filename="../src/dockwindows.cpp" line="67"/>
  469 + <location filename="../src/dockwindows.cpp" line="64"/>
470 470 <source>Frequencybase</source>
471 471 <translation>Frequenzbasis</translation>
472 472 </message>
473 473 <message>
474   - <location filename="../src/dockwindows.cpp" line="71"/>
  474 + <location filename="../src/dockwindows.cpp" line="69"/>
  475 + <source>Record length</source>
  476 + <translation>Satzlรคnge</translation>
  477 + </message>
  478 + <message>
  479 + <location filename="../src/dockwindows.cpp" line="72"/>
475 480 <source>Format</source>
476 481 <translation>Format</translation>
477 482 </message>
  483 + <message>
  484 + <location filename="../src/dockwindows.cpp" line="187"/>
  485 + <location filename="../src/dockwindows.cpp" line="190"/>
  486 + <source>Roll</source>
  487 + <translation>Rollen</translation>
  488 + </message>
478 489 </context>
479 490 <context>
480 491 <name>OpenHantekMainWindow</name>
... ... @@ -484,289 +495,264 @@
484 495 <translation>OpenHantek</translation>
485 496 </message>
486 497 <message>
487   - <location filename="../src/openhantek.cpp" line="168"/>
  498 + <location filename="../src/openhantek.cpp" line="119"/>
488 499 <source>&amp;Open...</source>
489 500 <translation>&amp;ร–ffnen...</translation>
490 501 </message>
491 502 <message>
492   - <location filename="../src/openhantek.cpp" line="169"/>
  503 + <location filename="../src/openhantek.cpp" line="120"/>
493 504 <source>Ctrl+O</source>
494 505 <translation>Strg+O</translation>
495 506 </message>
496 507 <message>
497   - <location filename="../src/openhantek.cpp" line="170"/>
  508 + <location filename="../src/openhantek.cpp" line="121"/>
498 509 <source>Open saved settings</source>
499 510 <translation>Gespeicherte Einstellungen รถffnen</translation>
500 511 </message>
501 512 <message>
502   - <location filename="../src/openhantek.cpp" line="173"/>
  513 + <location filename="../src/openhantek.cpp" line="124"/>
503 514 <source>&amp;Save</source>
504 515 <translation>&amp;Speichern</translation>
505 516 </message>
506 517 <message>
507   - <location filename="../src/openhantek.cpp" line="174"/>
508   - <location filename="../src/openhantek.cpp" line="198"/>
  518 + <location filename="../src/openhantek.cpp" line="125"/>
  519 + <location filename="../src/openhantek.cpp" line="149"/>
509 520 <source>Ctrl+S</source>
510 521 <translation>Strg+S</translation>
511 522 </message>
512 523 <message>
513   - <location filename="../src/openhantek.cpp" line="175"/>
  524 + <location filename="../src/openhantek.cpp" line="126"/>
514 525 <source>Save the current settings</source>
515 526 <translation>Aktuelle Einstellungen speichern</translation>
516 527 </message>
517 528 <message>
518   - <location filename="../src/openhantek.cpp" line="178"/>
  529 + <location filename="../src/openhantek.cpp" line="129"/>
519 530 <source>Save &amp;as...</source>
520 531 <translation>Speichern &amp;unter...</translation>
521 532 </message>
522 533 <message>
523   - <location filename="../src/openhantek.cpp" line="179"/>
  534 + <location filename="../src/openhantek.cpp" line="130"/>
524 535 <source>Save the current settings to another file</source>
525 536 <translation>Aktuelle Einstellungen in anderer Datei speichern</translation>
526 537 </message>
527 538 <message>
528   - <location filename="../src/openhantek.cpp" line="182"/>
  539 + <location filename="../src/openhantek.cpp" line="133"/>
529 540 <source>&amp;Print...</source>
530 541 <translation>&amp;Drucken...</translation>
531 542 </message>
532 543 <message>
533   - <location filename="../src/openhantek.cpp" line="183"/>
  544 + <location filename="../src/openhantek.cpp" line="134"/>
534 545 <source>Ctrl+P</source>
535 546 <translation>Strg+P</translation>
536 547 </message>
537 548 <message>
538   - <location filename="../src/openhantek.cpp" line="184"/>
  549 + <location filename="../src/openhantek.cpp" line="135"/>
539 550 <source>Print the oscilloscope screen</source>
540 551 <translation>Den Oscilloskopbildschirm drucken</translation>
541 552 </message>
542 553 <message>
543   - <location filename="../src/openhantek.cpp" line="187"/>
  554 + <location filename="../src/openhantek.cpp" line="138"/>
544 555 <source>&amp;Export as...</source>
545 556 <translation>&amp;Exportieren als...</translation>
546 557 </message>
547 558 <message>
548   - <location filename="../src/openhantek.cpp" line="188"/>
  559 + <location filename="../src/openhantek.cpp" line="139"/>
549 560 <source>Ctrl+E</source>
550 561 <translation>Strg+E</translation>
551 562 </message>
552 563 <message>
553   - <location filename="../src/openhantek.cpp" line="189"/>
  564 + <location filename="../src/openhantek.cpp" line="140"/>
554 565 <source>Export the oscilloscope data to a file</source>
555 566 <translation>Die Oszilloskopdaten in eine Datei exportieren</translation>
556 567 </message>
557 568 <message>
558   - <location filename="../src/openhantek.cpp" line="192"/>
  569 + <location filename="../src/openhantek.cpp" line="143"/>
559 570 <source>E&amp;xit</source>
560 571 <translation>&amp;Beenden</translation>
561 572 </message>
562 573 <message>
563   - <location filename="../src/openhantek.cpp" line="193"/>
  574 + <location filename="../src/openhantek.cpp" line="144"/>
564 575 <source>Ctrl+Q</source>
565 576 <translation>Strg+Q</translation>
566 577 </message>
567 578 <message>
568   - <location filename="../src/openhantek.cpp" line="194"/>
  579 + <location filename="../src/openhantek.cpp" line="145"/>
569 580 <source>Exit the application</source>
570 581 <translation>Anwendung beenden</translation>
571 582 </message>
572 583 <message>
573   - <location filename="../src/openhantek.cpp" line="197"/>
  584 + <location filename="../src/openhantek.cpp" line="148"/>
574 585 <source>&amp;Settings</source>
575 586 <translation>&amp;Einstellungen</translation>
576 587 </message>
577 588 <message>
578   - <location filename="../src/openhantek.cpp" line="199"/>
  589 + <location filename="../src/openhantek.cpp" line="150"/>
579 590 <source>Configure the oscilloscope</source>
580 591 <translation>Das Oszilloskop konfigurieren</translation>
581 592 </message>
582 593 <message>
583   - <location filename="../src/openhantek.cpp" line="243"/>
  594 + <location filename="../src/openhantek.cpp" line="179"/>
584 595 <source>Send command</source>
585 596 <translation>Befehl senden</translation>
586 597 </message>
587 598 <message>
588   - <location filename="../src/openhantek.cpp" line="244"/>
  599 + <location filename="../src/openhantek.cpp" line="180"/>
589 600 <source>Shift+C</source>
590 601 <translation>Shift+C</translation>
591 602 </message>
592 603 <message>
593   - <location filename="../src/openhantek.cpp" line="264"/>
  604 + <location filename="../src/openhantek.cpp" line="200"/>
594 605 <source>&amp;Docking windows</source>
595 606 <translation>&amp;Dockfenster</translation>
596 607 </message>
597 608 <message>
598   - <location filename="../src/openhantek.cpp" line="269"/>
  609 + <location filename="../src/openhantek.cpp" line="205"/>
599 610 <source>&amp;Toolbars</source>
600 611 <translation>&amp;Werkzeugleisten</translation>
601 612 </message>
602 613 <message>
603   - <location filename="../src/openhantek.cpp" line="380"/>
604   - <location filename="../src/openhantek.cpp" line="400"/>
  614 + <location filename="../src/openhantek.cpp" line="389"/>
  615 + <location filename="../src/openhantek.cpp" line="409"/>
605 616 <source>Settings (*.ini)</source>
606 617 <translation>Einstellungen (*.ini)</translation>
607 618 </message>
608 619 <message>
609   - <location filename="../src/openhantek.cpp" line="400"/>
  620 + <location filename="../src/openhantek.cpp" line="409"/>
610 621 <source>Save settings</source>
611 622 <translation>Einstellungen speichern</translation>
612 623 </message>
613 624 <message>
614   - <location filename="../src/openhantek.cpp" line="414"/>
  625 + <location filename="../src/openhantek.cpp" line="423"/>
615 626 <source>&amp;Stop</source>
616 627 <translation>&amp;Stop</translation>
617 628 </message>
618 629 <message>
619   - <location filename="../src/openhantek.cpp" line="463"/>
  630 + <location filename="../src/openhantek.cpp" line="472"/>
620 631 <source>&lt;p&gt;This is a open source software for Hantek USB oscilloscopes.&lt;/p&gt;&lt;p&gt;Copyright &amp;copy; 2010, 2011 Oliver Haag &amp;lt;oliver.haag@gmail.com&amp;gt;&lt;/p&gt;</source>
621 632 <translation>&lt;p&gt;Dies ist ein Open-Source Programm fรผr Hantek USB Oszilloskope.&lt;/p&gt;&lt;p&gt;Copyright &amp;copy; 2010, 2011 Oliver Haag &amp;lt;oliver.haag@gmail.com&amp;gt;&lt;/p&gt;</translation>
622 633 </message>
623 634 <message>
624   - <location filename="../src/openhantek.cpp" line="662"/>
  635 + <location filename="../src/openhantek.cpp" line="698"/>
625 636 <source>Invalid command</source>
626 637 <translation>Ungรผltiger Befehl</translation>
627 638 </message>
628 639 <message>
629   - <location filename="../src/openhantek.cpp" line="203"/>
  640 + <location filename="../src/openhantek.cpp" line="154"/>
630 641 <source>Space</source>
631 642 <translation>Leertaste</translation>
632 643 </message>
633 644 <message>
634   - <location filename="../src/openhantek.cpp" line="416"/>
  645 + <location filename="../src/openhantek.cpp" line="425"/>
635 646 <source>Stop the oscilloscope</source>
636 647 <translation>Das Oszilloskop anhalten</translation>
637 648 </message>
638 649 <message>
639   - <location filename="../src/openhantek.cpp" line="209"/>
640   - <source>&amp;Small</source>
641   - <translation>&amp;Klein</translation>
642   - </message>
643   - <message>
644   - <location filename="../src/openhantek.cpp" line="213"/>
645   - <source>10240 Samples</source>
646   - <translation>10240 Werte</translation>
647   - </message>
648   - <message>
649   - <location filename="../src/openhantek.cpp" line="215"/>
650   - <source>&amp;Large</source>
651   - <translation>&amp;GroรŸ</translation>
652   - </message>
653   - <message>
654   - <location filename="../src/openhantek.cpp" line="219"/>
655   - <source>32768 Samples</source>
656   - <translation>32768 Werte</translation>
657   - </message>
658   - <message>
659   - <location filename="../src/openhantek.cpp" line="221"/>
  650 + <location filename="../src/openhantek.cpp" line="157"/>
660 651 <source>Digital &amp;phosphor</source>
661 652 <translation>Digitaler &amp;Phosphor</translation>
662 653 </message>
663 654 <message>
664   - <location filename="../src/openhantek.cpp" line="227"/>
  655 + <location filename="../src/openhantek.cpp" line="163"/>
665 656 <source>&amp;Zoom</source>
666 657 <translation>&amp;Zoom</translation>
667 658 </message>
668 659 <message>
669   - <location filename="../src/openhantek.cpp" line="234"/>
  660 + <location filename="../src/openhantek.cpp" line="170"/>
670 661 <source>&amp;About</source>
671 662 <translation>&amp;รœber</translation>
672 663 </message>
673 664 <message>
674   - <location filename="../src/openhantek.cpp" line="235"/>
  665 + <location filename="../src/openhantek.cpp" line="171"/>
675 666 <source>Show information about this program</source>
676 667 <translation>Zeige Informationen รผber dieses Programm</translation>
677 668 </message>
678 669 <message>
679   - <location filename="../src/openhantek.cpp" line="238"/>
  670 + <location filename="../src/openhantek.cpp" line="174"/>
680 671 <source>About &amp;Qt</source>
681 672 <translation>รœber &amp;Qt</translation>
682 673 </message>
683 674 <message>
684   - <location filename="../src/openhantek.cpp" line="239"/>
  675 + <location filename="../src/openhantek.cpp" line="175"/>
685 676 <source>Show the Qt library&apos;s About box</source>
686 677 <translation>Zeige Dialog zur Qt Bibliothek</translation>
687 678 </message>
688 679 <message>
689   - <location filename="../src/openhantek.cpp" line="250"/>
  680 + <location filename="../src/openhantek.cpp" line="186"/>
690 681 <source>&amp;File</source>
691 682 <translation>&amp;Datei</translation>
692 683 </message>
693 684 <message>
694   - <location filename="../src/openhantek.cpp" line="260"/>
  685 + <location filename="../src/openhantek.cpp" line="196"/>
695 686 <source>&amp;View</source>
696 687 <translation>&amp;Ansicht</translation>
697 688 </message>
698 689 <message>
699   - <location filename="../src/openhantek.cpp" line="274"/>
  690 + <location filename="../src/openhantek.cpp" line="210"/>
700 691 <source>&amp;Oscilloscope</source>
701 692 <translation>&amp;Oszilloskop</translation>
702 693 </message>
703 694 <message>
704   - <location filename="../src/openhantek.cpp" line="282"/>
705   - <source>&amp;Buffer size</source>
706   - <translation>&amp;PuffergrรถรŸe</translation>
707   - </message>
708   - <message>
709   - <location filename="../src/openhantek.cpp" line="288"/>
  695 + <location filename="../src/openhantek.cpp" line="221"/>
710 696 <source>&amp;Help</source>
711 697 <translation>&amp;Hilfe</translation>
712 698 </message>
713 699 <message>
714   - <location filename="../src/openhantek.cpp" line="295"/>
  700 + <location filename="../src/openhantek.cpp" line="228"/>
715 701 <source>File</source>
716 702 <translation>Datei</translation>
717 703 </message>
718 704 <message>
719   - <location filename="../src/openhantek.cpp" line="304"/>
  705 + <location filename="../src/openhantek.cpp" line="237"/>
720 706 <source>Oscilloscope</source>
721 707 <translation>Oszilloskop</translation>
722 708 </message>
723 709 <message>
724   - <location filename="../src/openhantek.cpp" line="307"/>
  710 + <location filename="../src/openhantek.cpp" line="240"/>
725 711 <source>View</source>
726 712 <translation>Ansicht</translation>
727 713 </message>
728 714 <message>
729   - <location filename="../src/openhantek.cpp" line="322"/>
  715 + <location filename="../src/openhantek.cpp" line="255"/>
730 716 <source>Ready</source>
731 717 <translation>Bereit</translation>
732 718 </message>
733 719 <message>
734   - <location filename="../src/openhantek.cpp" line="380"/>
  720 + <location filename="../src/openhantek.cpp" line="389"/>
735 721 <source>Open file</source>
736 722 <translation>Datei รถffnen</translation>
737 723 </message>
738 724 <message>
739   - <location filename="../src/openhantek.cpp" line="424"/>
  725 + <location filename="../src/openhantek.cpp" line="433"/>
740 726 <source>&amp;Start</source>
741 727 <translation>&amp;Start</translation>
742 728 </message>
743 729 <message>
744   - <location filename="../src/openhantek.cpp" line="426"/>
  730 + <location filename="../src/openhantek.cpp" line="435"/>
745 731 <source>Start the oscilloscope</source>
746 732 <translation>Startet das Oszilloskop</translation>
747 733 </message>
748 734 <message>
749   - <location filename="../src/openhantek.cpp" line="446"/>
  735 + <location filename="../src/openhantek.cpp" line="455"/>
750 736 <source>Disable fading of previous graphs</source>
751 737 <translation>Nachleuchten von vorigen Graphen deaktivieren</translation>
752 738 </message>
753 739 <message>
754   - <location filename="../src/openhantek.cpp" line="448"/>
  740 + <location filename="../src/openhantek.cpp" line="457"/>
755 741 <source>Enable fading of previous graphs</source>
756 742 <translation>Nachleuchten von vorigen Graphen aktivieren</translation>
757 743 </message>
758 744 <message>
759   - <location filename="../src/openhantek.cpp" line="456"/>
  745 + <location filename="../src/openhantek.cpp" line="465"/>
760 746 <source>Hide magnified scope</source>
761 747 <translation>VergrรถรŸerte Anzeige ausblenden</translation>
762 748 </message>
763 749 <message>
764   - <location filename="../src/openhantek.cpp" line="458"/>
  750 + <location filename="../src/openhantek.cpp" line="467"/>
765 751 <source>Show magnified scope</source>
766 752 <translation>VergrรถรŸerte Anzeige anzeigen</translation>
767 753 </message>
768 754 <message>
769   - <location filename="../src/openhantek.cpp" line="463"/>
  755 + <location filename="../src/openhantek.cpp" line="472"/>
770 756 <source>About OpenHantek %1</source>
771 757 <translation>*ber OpenHantek %1</translation>
772 758 </message>
... ... @@ -774,187 +760,187 @@
774 760 <context>
775 761 <name>QApplication</name>
776 762 <message>
777   - <location filename="../src/helper.cpp" line="47"/>
  763 + <location filename="../src/helper.cpp" line="49"/>
778 764 <source>Success (no error)</source>
779 765 <translation>Erfolgreich (Kein Fehler)</translation>
780 766 </message>
781 767 <message>
782   - <location filename="../src/helper.cpp" line="49"/>
  768 + <location filename="../src/helper.cpp" line="51"/>
783 769 <source>Input/output error</source>
784 770 <translation>Ein-/Ausgabe Fehler</translation>
785 771 </message>
786 772 <message>
787   - <location filename="../src/helper.cpp" line="51"/>
  773 + <location filename="../src/helper.cpp" line="53"/>
788 774 <source>Invalid parameter</source>
789 775 <translation>Ungรผltiger Parameter</translation>
790 776 </message>
791 777 <message>
792   - <location filename="../src/helper.cpp" line="53"/>
  778 + <location filename="../src/helper.cpp" line="55"/>
793 779 <source>Access denied (insufficient permissions)</source>
794 780 <translation>Zugriff verweigert (Unzureichende Berechtigungen)</translation>
795 781 </message>
796 782 <message>
797   - <location filename="../src/helper.cpp" line="55"/>
  783 + <location filename="../src/helper.cpp" line="57"/>
798 784 <source>No such device (it may have been disconnected)</source>
799 785 <translation>Gerรคt nicht vorhanden (Mรถglicherweise wurde es abgesteckt)</translation>
800 786 </message>
801 787 <message>
802   - <location filename="../src/helper.cpp" line="57"/>
  788 + <location filename="../src/helper.cpp" line="59"/>
803 789 <source>Entity not found</source>
804 790 <translation>Datensatz nicht gefunden</translation>
805 791 </message>
806 792 <message>
807   - <location filename="../src/helper.cpp" line="59"/>
  793 + <location filename="../src/helper.cpp" line="61"/>
808 794 <source>Resource busy</source>
809 795 <translation>Quelle belegt</translation>
810 796 </message>
811 797 <message>
812   - <location filename="../src/helper.cpp" line="61"/>
  798 + <location filename="../src/helper.cpp" line="63"/>
813 799 <source>Operation timed out</source>
814 800 <translation>Zeitรผberschreitung</translation>
815 801 </message>
816 802 <message>
817   - <location filename="../src/helper.cpp" line="63"/>
  803 + <location filename="../src/helper.cpp" line="65"/>
818 804 <source>Overflow</source>
819 805 <translation>รœberlauf</translation>
820 806 </message>
821 807 <message>
822   - <location filename="../src/helper.cpp" line="65"/>
  808 + <location filename="../src/helper.cpp" line="67"/>
823 809 <source>Pipe error</source>
824 810 <translation>Leitungsfehler</translation>
825 811 </message>
826 812 <message>
827   - <location filename="../src/helper.cpp" line="67"/>
  813 + <location filename="../src/helper.cpp" line="69"/>
828 814 <source>System call interrupted (perhaps due to signal)</source>
829 815 <translation>Systemaufruf unterbrochen (Mรถglicherweise aufgrund eines Signals)</translation>
830 816 </message>
831 817 <message>
832   - <location filename="../src/helper.cpp" line="69"/>
  818 + <location filename="../src/helper.cpp" line="71"/>
833 819 <source>Insufficient memory</source>
834 820 <translation>Unzureichender Speicher</translation>
835 821 </message>
836 822 <message>
837   - <location filename="../src/helper.cpp" line="71"/>
  823 + <location filename="../src/helper.cpp" line="73"/>
838 824 <source>Operation not supported or unimplemented on this platform</source>
839 825 <translation>Vorgang auf diesem System nicht unterstรผtzt oder nicht implementiert</translation>
840 826 </message>
841 827 <message>
842   - <location filename="../src/helper.cpp" line="73"/>
  828 + <location filename="../src/helper.cpp" line="75"/>
843 829 <source>Other error</source>
844 830 <translation>Anderer Fehler</translation>
845 831 </message>
846 832 <message>
847   - <location filename="../src/helper.cpp" line="90"/>
  833 + <location filename="../src/helper.cpp" line="92"/>
848 834 <source>%L1 ยตV</source>
849 835 <translation>%L1 ยตV</translation>
850 836 </message>
851 837 <message>
852   - <location filename="../src/helper.cpp" line="92"/>
  838 + <location filename="../src/helper.cpp" line="94"/>
853 839 <source>%L1 mV</source>
854 840 <translation>%L1 mV</translation>
855 841 </message>
856 842 <message>
857   - <location filename="../src/helper.cpp" line="94"/>
  843 + <location filename="../src/helper.cpp" line="96"/>
858 844 <source>%L1 V</source>
859 845 <translation>%L1 V</translation>
860 846 </message>
861 847 <message>
862   - <location filename="../src/helper.cpp" line="98"/>
  848 + <location filename="../src/helper.cpp" line="100"/>
863 849 <source>%L1 dB</source>
864 850 <translation>%L1 dB</translation>
865 851 </message>
866 852 <message>
867   - <location filename="../src/helper.cpp" line="103"/>
  853 + <location filename="../src/helper.cpp" line="105"/>
868 854 <source>%L1 ps</source>
869 855 <translation>%L1 ps</translation>
870 856 </message>
871 857 <message>
872   - <location filename="../src/helper.cpp" line="105"/>
  858 + <location filename="../src/helper.cpp" line="107"/>
873 859 <source>%L1 ns</source>
874 860 <translation>%L1 ns</translation>
875 861 </message>
876 862 <message>
877   - <location filename="../src/helper.cpp" line="107"/>
  863 + <location filename="../src/helper.cpp" line="109"/>
878 864 <source>%L1 ยตs</source>
879 865 <translation>%L1 ยตs</translation>
880 866 </message>
881 867 <message>
882   - <location filename="../src/helper.cpp" line="109"/>
  868 + <location filename="../src/helper.cpp" line="111"/>
883 869 <source>%L1 ms</source>
884 870 <translation>%L1 ms</translation>
885 871 </message>
886 872 <message>
887   - <location filename="../src/helper.cpp" line="111"/>
  873 + <location filename="../src/helper.cpp" line="113"/>
888 874 <source>%L1 s</source>
889 875 <translation>%L1 s</translation>
890 876 </message>
891 877 <message>
892   - <location filename="../src/helper.cpp" line="113"/>
  878 + <location filename="../src/helper.cpp" line="115"/>
893 879 <source>%L1 min</source>
894 880 <translation>%L1 min</translation>
895 881 </message>
896 882 <message>
897   - <location filename="../src/helper.cpp" line="115"/>
  883 + <location filename="../src/helper.cpp" line="117"/>
898 884 <source>%L1 h</source>
899 885 <translation>%L1 h</translation>
900 886 </message>
901 887 <message>
902   - <location filename="../src/helper.cpp" line="121"/>
  888 + <location filename="../src/helper.cpp" line="123"/>
903 889 <source>%L1 Hz</source>
904 890 <translation>%L1 Hz</translation>
905 891 </message>
906 892 <message>
907   - <location filename="../src/helper.cpp" line="123"/>
  893 + <location filename="../src/helper.cpp" line="125"/>
908 894 <source>%L1 kHz</source>
909 895 <translation>%L1 kHz</translation>
910 896 </message>
911 897 <message>
912   - <location filename="../src/helper.cpp" line="125"/>
  898 + <location filename="../src/helper.cpp" line="127"/>
913 899 <source>%L1 MHz</source>
914 900 <translation>%L1 MHz</translation>
915 901 </message>
916 902 <message>
917   - <location filename="../src/helper.cpp" line="127"/>
  903 + <location filename="../src/helper.cpp" line="129"/>
918 904 <source>%L1 GHz</source>
919 905 <translation>%L1 GHz</translation>
920 906 </message>
921 907 <message>
922   - <location filename="../src/helper.cpp" line="133"/>
  908 + <location filename="../src/helper.cpp" line="135"/>
923 909 <source>%L1 S</source>
924 910 <translation>%L1 S</translation>
925 911 </message>
926 912 <message>
927   - <location filename="../src/helper.cpp" line="135"/>
  913 + <location filename="../src/helper.cpp" line="137"/>
928 914 <source>%L1 kS</source>
929 915 <translation>%L1 kS</translation>
930 916 </message>
931 917 <message>
932   - <location filename="../src/helper.cpp" line="137"/>
  918 + <location filename="../src/helper.cpp" line="139"/>
933 919 <source>%L1 MS</source>
934 920 <translation>%L1 MS</translation>
935 921 </message>
936 922 <message>
937   - <location filename="../src/helper.cpp" line="139"/>
  923 + <location filename="../src/helper.cpp" line="141"/>
938 924 <source>%L1 GS</source>
939 925 <translation>%L1 GS</translation>
940 926 </message>
941 927 <message>
942   - <location filename="../src/settings.cpp" line="145"/>
  928 + <location filename="../src/settings.cpp" line="146"/>
943 929 <source>CH%1</source>
944 930 <translation>CH%1</translation>
945 931 </message>
946 932 <message>
947   - <location filename="../src/settings.cpp" line="135"/>
  933 + <location filename="../src/settings.cpp" line="136"/>
948 934 <source>SP%1</source>
949 935 <translation>SP%1</translation>
950 936 </message>
951 937 <message>
952   - <location filename="../src/settings.cpp" line="179"/>
  938 + <location filename="../src/settings.cpp" line="180"/>
953 939 <source>MATH</source>
954 940 <translation>MATH</translation>
955 941 </message>
956 942 <message>
957   - <location filename="../src/settings.cpp" line="170"/>
  943 + <location filename="../src/settings.cpp" line="171"/>
958 944 <source>SPM</source>
959 945 <translation>SPM</translation>
960 946 </message>
... ... @@ -1112,7 +1098,7 @@
1112 1098 <context>
1113 1099 <name>SpectrumDock</name>
1114 1100 <message>
1115   - <location filename="../src/dockwindows.cpp" line="320"/>
  1101 + <location filename="../src/dockwindows.cpp" line="405"/>
1116 1102 <source>Spectrum</source>
1117 1103 <translation>Spektrum</translation>
1118 1104 </message>
... ... @@ -1120,27 +1106,27 @@
1120 1106 <context>
1121 1107 <name>TriggerDock</name>
1122 1108 <message>
1123   - <location filename="../src/dockwindows.cpp" line="180"/>
  1109 + <location filename="../src/dockwindows.cpp" line="265"/>
1124 1110 <source>Trigger</source>
1125 1111 <translation>Trigger</translation>
1126 1112 </message>
1127 1113 <message>
1128   - <location filename="../src/dockwindows.cpp" line="185"/>
  1114 + <location filename="../src/dockwindows.cpp" line="270"/>
1129 1115 <source>CH%1</source>
1130 1116 <translation>CH%1</translation>
1131 1117 </message>
1132 1118 <message>
1133   - <location filename="../src/dockwindows.cpp" line="189"/>
  1119 + <location filename="../src/dockwindows.cpp" line="274"/>
1134 1120 <source>Mode</source>
1135 1121 <translation>Modus</translation>
1136 1122 </message>
1137 1123 <message>
1138   - <location filename="../src/dockwindows.cpp" line="194"/>
  1124 + <location filename="../src/dockwindows.cpp" line="279"/>
1139 1125 <source>Slope</source>
1140 1126 <translation>Flanke</translation>
1141 1127 </message>
1142 1128 <message>
1143   - <location filename="../src/dockwindows.cpp" line="199"/>
  1129 + <location filename="../src/dockwindows.cpp" line="284"/>
1144 1130 <source>Source</source>
1145 1131 <translation>Quelle</translation>
1146 1132 </message>
... ... @@ -1148,7 +1134,7 @@
1148 1134 <context>
1149 1135 <name>VoltageDock</name>
1150 1136 <message>
1151   - <location filename="../src/dockwindows.cpp" line="445"/>
  1137 + <location filename="../src/dockwindows.cpp" line="530"/>
1152 1138 <source>Voltage</source>
1153 1139 <translation>Spannung</translation>
1154 1140 </message>
... ...