Commit d52c9b8280c05d6b0add84dd2005024eb25db356
1 parent
8ee5d2fc
Record length and samplerate can be set
Showing
21 changed files
with
1150 additions
and
724 deletions
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 &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 &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 &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'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'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'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'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>&Open...</source> |
| 489 | 500 | <translation>&ร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>&Save</source> |
| 504 | 515 | <translation>&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 &as...</source> |
| 520 | 531 | <translation>Speichern &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>&Print...</source> |
| 530 | 541 | <translation>&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>&Export as...</source> |
| 545 | 556 | <translation>&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&xit</source> |
| 560 | 571 | <translation>&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>&Settings</source> |
| 575 | 586 | <translation>&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>&Docking windows</source> |
| 595 | 606 | <translation>&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>&Toolbars</source> |
| 600 | 611 | <translation>&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>&Stop</source> |
| 616 | 627 | <translation>&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><p>This is a open source software for Hantek USB oscilloscopes.</p><p>Copyright &copy; 2010, 2011 Oliver Haag &lt;oliver.haag@gmail.com&gt;</p></source> |
| 621 | 632 | <translation><p>Dies ist ein Open-Source Programm fรผr Hantek USB Oszilloskope.</p><p>Copyright &copy; 2010, 2011 Oliver Haag &lt;oliver.haag@gmail.com&gt;</p></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>&Small</source> | |
| 641 | - <translation>&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>&Large</source> | |
| 651 | - <translation>&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 &phosphor</source> |
| 661 | 652 | <translation>Digitaler &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>&Zoom</source> |
| 666 | 657 | <translation>&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>&About</source> |
| 671 | 662 | <translation>&ร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 &Qt</source> |
| 681 | 672 | <translation>รber &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'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>&File</source> |
| 691 | 682 | <translation>&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>&View</source> |
| 696 | 687 | <translation>&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>&Oscilloscope</source> |
| 701 | 692 | <translation>&Oszilloskop</translation> |
| 702 | 693 | </message> |
| 703 | 694 | <message> |
| 704 | - <location filename="../src/openhantek.cpp" line="282"/> | |
| 705 | - <source>&Buffer size</source> | |
| 706 | - <translation>&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>&Help</source> |
| 711 | 697 | <translation>&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>&Start</source> |
| 741 | 727 | <translation>&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> | ... | ... |