Commit c3b8187182560bc9edd5bfe8352f869fced243b2
1 parent
a29b1fc2
Implemented single trigger mode and fixed a bug
Showing
7 changed files
with
112 additions
and
89 deletions
openhantek/ChangeLog
| ... | ... | @@ -32,4 +32,8 @@ |
| 32 | 32 | 2010-08-16 Oliver Haag <oliver.haag@gmail.com> |
| 33 | 33 | * Completed libusb 0.1 downwards compatibility mode (env LIBUSB_VERSION=0) |
| 34 | 34 | * Bugfix: Grid of scopes drawn even if there aren't any graphs available |
| 35 | -* Implemented basics of the XY-mode | |
| 36 | 35 | \ No newline at end of file |
| 36 | +* Implemented basics of the XY-mode | |
| 37 | + | |
| 38 | +2010-08-18 Oliver Haag <oliver.haag@gmail.com> | |
| 39 | +* Bugfix: Trigger levels weren't sent to the oscilloscope | |
| 40 | +* Implemented single trigger mode | ... | ... |
openhantek/src/dsocontrol.cpp
| ... | ... | @@ -36,11 +36,13 @@ DsoControl::DsoControl(QObject *parent) : QThread(parent) { |
| 36 | 36 | /// \brief Start sampling process. |
| 37 | 37 | void DsoControl::startSampling() { |
| 38 | 38 | this->sampling = true; |
| 39 | + emit samplingStarted(); | |
| 39 | 40 | } |
| 40 | 41 | |
| 41 | 42 | /// \brief Stop sampling process. |
| 42 | 43 | void DsoControl::stopSampling() { |
| 43 | 44 | this->sampling = false; |
| 45 | + emit samplingStopped(); | |
| 44 | 46 | } |
| 45 | 47 | |
| 46 | 48 | /// \brief Get a list of the names of the special trigger sources. | ... | ... |
openhantek/src/dsocontrol.h
| ... | ... | @@ -46,9 +46,6 @@ class DsoControl : public QThread { |
| 46 | 46 | public: |
| 47 | 47 | DsoControl(QObject *parent = 0); |
| 48 | 48 | |
| 49 | - virtual void startSampling(); | |
| 50 | - virtual void stopSampling(); | |
| 51 | - | |
| 52 | 49 | virtual unsigned int getChannelCount() = 0; ///< Get the number of channels for this oscilloscope |
| 53 | 50 | |
| 54 | 51 | const QStringList *getSpecialTriggerSources(); |
| ... | ... | @@ -62,6 +59,8 @@ class DsoControl : public QThread { |
| 62 | 59 | signals: |
| 63 | 60 | void deviceConnected(); ///< The oscilloscope device has been disconnected |
| 64 | 61 | void deviceDisconnected(); ///< The oscilloscope device has been connected |
| 62 | + void samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger | |
| 63 | + void samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger | |
| 65 | 64 | void statusMessage(const QString &message, int timeout); ///< Status message about the oscilloscope |
| 66 | 65 | void samplesAvailable(const QList<double *> *data, const QList<unsigned int> *size, double samplerate, QMutex *mutex); ///< New sample data is available |
| 67 | 66 | |
| ... | ... | @@ -69,6 +68,9 @@ class DsoControl : public QThread { |
| 69 | 68 | virtual void connectDevice(); |
| 70 | 69 | virtual void disconnectDevice(); |
| 71 | 70 | |
| 71 | + virtual void startSampling(); | |
| 72 | + virtual void stopSampling(); | |
| 73 | + | |
| 72 | 74 | virtual unsigned long int setSamplerate(unsigned long int samplerate) = 0; ///< Set the samplerate that should be met |
| 73 | 75 | virtual double setBufferSize(unsigned int size) = 0; ///< Set the needed buffer size |
| 74 | 76 | ... | ... |
openhantek/src/hantek/control.cpp
| ... | ... | @@ -150,6 +150,7 @@ namespace Hantek { |
| 150 | 150 | // The control loop is running until the device is disconnected |
| 151 | 151 | int captureState = CAPTURE_WAITING; |
| 152 | 152 | bool samplingStarted = false; |
| 153 | + Dso::TriggerMode lastTriggerMode = (Dso::TriggerMode) -1; | |
| 153 | 154 | |
| 154 | 155 | while(captureState != LIBUSB_ERROR_NO_DEVICE && !this->terminate) { |
| 155 | 156 | // Send all pending bulk commands |
| ... | ... | @@ -196,23 +197,33 @@ namespace Hantek { |
| 196 | 197 | /// \todo Maybe the time interval could be improved... |
| 197 | 198 | this->msleep(50); |
| 198 | 199 | |
| 199 | - if(!this->sampling) | |
| 200 | + if(!this->sampling) { | |
| 201 | + samplingStarted = false; | |
| 200 | 202 | continue; |
| 203 | + } | |
| 204 | + | |
| 201 | 205 | captureState = this->getCaptureState(); |
| 202 | 206 | switch(captureState) { |
| 203 | 207 | case CAPTURE_READY: |
| 204 | 208 | case CAPTURE_READY5200: |
| 205 | - samplingStarted = false; | |
| 206 | - | |
| 207 | - errorCode = this->getSamples(); | |
| 209 | + // Get data and process it, if we're still sampling | |
| 210 | + errorCode = this->getSamples(samplingStarted); | |
| 208 | 211 | if(errorCode < 0) |
| 209 | 212 | qDebug("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data()); |
| 210 | 213 | |
| 214 | + // Check if we're in single trigger mode | |
| 215 | + if(this->triggerMode == Dso::TRIGGERMODE_SINGLE && samplingStarted) | |
| 216 | + this->stopSampling(); | |
| 217 | + | |
| 218 | + // Sampling completed, restart it when necessary | |
| 219 | + samplingStarted = false; | |
| 220 | + | |
| 211 | 221 | // Start next capture if necessary by leaving out the break statement |
| 212 | 222 | if(!this->sampling) |
| 213 | 223 | break; |
| 224 | + | |
| 214 | 225 | case CAPTURE_WAITING: |
| 215 | - if(samplingStarted) | |
| 226 | + if(samplingStarted && lastTriggerMode == this->triggerMode) | |
| 216 | 227 | break; |
| 217 | 228 | |
| 218 | 229 | // Start capturing |
| ... | ... | @@ -236,7 +247,9 @@ namespace Hantek { |
| 236 | 247 | captureState = LIBUSB_ERROR_NO_DEVICE; |
| 237 | 248 | } |
| 238 | 249 | samplingStarted = true; |
| 250 | + lastTriggerMode = this->triggerMode; | |
| 239 | 251 | break; |
| 252 | + | |
| 240 | 253 | case CAPTURE_SAMPLING: |
| 241 | 254 | break; |
| 242 | 255 | default: |
| ... | ... | @@ -304,92 +317,97 @@ namespace Hantek { |
| 304 | 317 | |
| 305 | 318 | /// \brief Gets sample data from the oscilloscope and converts it. |
| 306 | 319 | /// \return 0 on success, libusb error code on error. |
| 307 | - int Control::getSamples() { | |
| 320 | + int Control::getSamples(bool process) { | |
| 308 | 321 | int errorCode; |
| 309 | 322 | |
| 323 | + // Request data | |
| 310 | 324 | errorCode = this->device->bulkCommand(this->command[COMMAND_GETDATA], 1); |
| 311 | 325 | if(errorCode < 0) |
| 312 | 326 | return errorCode; |
| 313 | 327 | |
| 328 | + // Save raw data to temporary buffer | |
| 314 | 329 | unsigned int dataCount = this->bufferSize * HANTEK_CHANNELS; |
| 315 | 330 | unsigned char data[dataCount]; |
| 316 | 331 | errorCode = this->device->bulkReadMulti(data, dataCount); |
| 317 | 332 | if(errorCode < 0) |
| 318 | 333 | return errorCode; |
| 319 | 334 | |
| 320 | - this->samplesMutex.lock(); | |
| 321 | - | |
| 322 | - // Convert channel data | |
| 323 | - if(((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getFastRate()) { | |
| 324 | - // Fast rate mode, one channel is using all buffers | |
| 325 | - int channel; | |
| 326 | - if(((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getUsedChannel() == USED_CH1) | |
| 327 | - channel = 0; | |
| 328 | - else | |
| 329 | - channel = 1; | |
| 330 | - | |
| 331 | - | |
| 332 | - // Clear unused channels | |
| 333 | - for(int channelCounter = 0; channelCounter < HANTEK_CHANNELS; channelCounter++) | |
| 334 | - if(channelCounter != channel && this->samples[channelCounter]) { | |
| 335 | - | |
| 336 | - delete this->samples[channelCounter]; | |
| 337 | - this->samples[channelCounter] = 0; | |
| 338 | - } | |
| 335 | + // Process the data only if we want it | |
| 336 | + if(process) { | |
| 337 | + this->samplesMutex.lock(); | |
| 339 | 338 | |
| 340 | - if(channel < HANTEK_CHANNELS) { | |
| 341 | - // Reallocate memory for samples if the sample count has changed | |
| 342 | - if(!this->samples[channel] || this->samplesSize[channel] != dataCount) { | |
| 343 | - if(this->samples[channel]) | |
| 344 | - delete this->samples[channel]; | |
| 345 | - this->samples[channel] = new double[dataCount]; | |
| 346 | - this->samplesSize[channel] = dataCount; | |
| 347 | - } | |
| 339 | + // Convert channel data | |
| 340 | + if(((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getFastRate()) { | |
| 341 | + // Fast rate mode, one channel is using all buffers | |
| 342 | + int channel; | |
| 343 | + if(((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getUsedChannel() == USED_CH1) | |
| 344 | + channel = 0; | |
| 345 | + else | |
| 346 | + channel = 1; | |
| 348 | 347 | |
| 349 | - // Convert data from the oscilloscope and write it into the sample buffer | |
| 350 | - unsigned int bufferPosition = this->triggerPoint; | |
| 351 | - for(unsigned int realPosition = 0; realPosition < dataCount; realPosition++, bufferPosition++) { | |
| 352 | - if(bufferPosition >= dataCount) | |
| 353 | - bufferPosition %= dataCount; | |
| 354 | - | |
| 355 | - this->samples[channel][realPosition] = ((double) data[bufferPosition] / 0xff - this->offsetReal[channel]) * this->gainSteps[this->gain[channel]]; | |
| 356 | - } | |
| 357 | - } | |
| 358 | - } | |
| 359 | - else { | |
| 360 | - // Normal mode, channel are using their separate buffers | |
| 361 | - unsigned char usedChannels = ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getUsedChannel(); | |
| 362 | - for(int channel = 0; channel < HANTEK_CHANNELS; channel++) { | |
| 363 | - if(usedChannels == USED_CH1CH2 || channel == usedChannels) { | |
| 348 | + | |
| 349 | + // Clear unused channels | |
| 350 | + for(int channelCounter = 0; channelCounter < HANTEK_CHANNELS; channelCounter++) | |
| 351 | + if(channelCounter != channel && this->samples[channelCounter]) { | |
| 352 | + | |
| 353 | + delete this->samples[channelCounter]; | |
| 354 | + this->samples[channelCounter] = 0; | |
| 355 | + } | |
| 356 | + | |
| 357 | + if(channel < HANTEK_CHANNELS) { | |
| 364 | 358 | // Reallocate memory for samples if the sample count has changed |
| 365 | - if(!this->samples[channel] || this->samplesSize[channel] != this->bufferSize) { | |
| 359 | + if(!this->samples[channel] || this->samplesSize[channel] != dataCount) { | |
| 366 | 360 | if(this->samples[channel]) |
| 367 | 361 | delete this->samples[channel]; |
| 368 | - this->samples[channel] = new double[this->bufferSize]; | |
| 369 | - this->samplesSize[channel] = this->bufferSize; | |
| 362 | + this->samples[channel] = new double[dataCount]; | |
| 363 | + this->samplesSize[channel] = dataCount; | |
| 370 | 364 | } |
| 371 | 365 | |
| 372 | 366 | // Convert data from the oscilloscope and write it into the sample buffer |
| 373 | - unsigned int bufferPosition = this->triggerPoint * 2; | |
| 374 | - for(unsigned int realPosition = 0; realPosition < this->bufferSize; realPosition++, bufferPosition += 2) { | |
| 367 | + unsigned int bufferPosition = this->triggerPoint; | |
| 368 | + for(unsigned int realPosition = 0; realPosition < dataCount; realPosition++, bufferPosition++) { | |
| 375 | 369 | if(bufferPosition >= dataCount) |
| 376 | 370 | bufferPosition %= dataCount; |
| 377 | 371 | |
| 378 | - this->samples[channel][realPosition] = ((double) data[bufferPosition + HANTEK_CHANNELS - 1 - channel] / 256.0 - this->offsetReal[channel]) * this->gainSteps[this->gain[channel]]; | |
| 372 | + this->samples[channel][realPosition] = ((double) data[bufferPosition] / 0xff - this->offsetReal[channel]) * this->gainSteps[this->gain[channel]]; | |
| 379 | 373 | } |
| 380 | 374 | } |
| 381 | - else if(this->samples[channel]) { | |
| 382 | - // Clear unused channels | |
| 383 | - delete this->samples[channel]; | |
| 384 | - this->samples[channel] = 0; | |
| 385 | - this->samplesSize[channel] = 0; | |
| 375 | + } | |
| 376 | + else { | |
| 377 | + // Normal mode, channel are using their separate buffers | |
| 378 | + unsigned char usedChannels = ((CommandSetTriggerAndSamplerate *) this->command[COMMAND_SETTRIGGERANDSAMPLERATE])->getUsedChannel(); | |
| 379 | + for(int channel = 0; channel < HANTEK_CHANNELS; channel++) { | |
| 380 | + if(usedChannels == USED_CH1CH2 || channel == usedChannels) { | |
| 381 | + // Reallocate memory for samples if the sample count has changed | |
| 382 | + if(!this->samples[channel] || this->samplesSize[channel] != this->bufferSize) { | |
| 383 | + if(this->samples[channel]) | |
| 384 | + delete this->samples[channel]; | |
| 385 | + this->samples[channel] = new double[this->bufferSize]; | |
| 386 | + this->samplesSize[channel] = this->bufferSize; | |
| 387 | + } | |
| 388 | + | |
| 389 | + // Convert data from the oscilloscope and write it into the sample buffer | |
| 390 | + unsigned int bufferPosition = this->triggerPoint * 2; | |
| 391 | + for(unsigned int realPosition = 0; realPosition < this->bufferSize; realPosition++, bufferPosition += 2) { | |
| 392 | + if(bufferPosition >= dataCount) | |
| 393 | + bufferPosition %= dataCount; | |
| 394 | + | |
| 395 | + this->samples[channel][realPosition] = ((double) data[bufferPosition + HANTEK_CHANNELS - 1 - channel] / 256.0 - this->offsetReal[channel]) * this->gainSteps[this->gain[channel]]; | |
| 396 | + } | |
| 397 | + } | |
| 398 | + else if(this->samples[channel]) { | |
| 399 | + // Clear unused channels | |
| 400 | + delete this->samples[channel]; | |
| 401 | + this->samples[channel] = 0; | |
| 402 | + this->samplesSize[channel] = 0; | |
| 403 | + } | |
| 386 | 404 | } |
| 387 | 405 | } |
| 406 | + | |
| 407 | + this->samplesMutex.unlock(); | |
| 408 | + emit samplesAvailable(&(this->samples), &(this->samplesSize), this->samplerateSteps[this->samplerate], &(this->samplesMutex)); | |
| 388 | 409 | } |
| 389 | 410 | |
| 390 | - this->samplesMutex.unlock(); | |
| 391 | - emit samplesAvailable(&(this->samples), &(this->samplesSize), this->samplerateSteps[this->samplerate], &(this->samplesMutex)); | |
| 392 | - | |
| 393 | 411 | return 0; |
| 394 | 412 | } |
| 395 | 413 | |
| ... | ... | @@ -610,7 +628,7 @@ namespace Hantek { |
| 610 | 628 | // Calculate the trigger level value (0x00 - 0xfe) |
| 611 | 629 | unsigned short int levelValue = (this->offsetReal[channel] + level / this->gainSteps[this->gain[channel]]) * 0xfe + 0.5; |
| 612 | 630 | |
| 613 | - if(this->triggerSpecial && channel == this->triggerSource) { | |
| 631 | + if(!this->triggerSpecial && channel == this->triggerSource) { | |
| 614 | 632 | // SetOffset control command for trigger level |
| 615 | 633 | ((ControlSetOffset *) this->control[CONTROLINDEX_SETOFFSET])->setTrigger(levelValue); |
| 616 | 634 | this->controlPending[CONTROLINDEX_SETOFFSET] = true; | ... | ... |
openhantek/src/hantek/control.h
openhantek/src/openhantek.cpp
| ... | ... | @@ -124,6 +124,10 @@ OpenHantekMainWindow::OpenHantekMainWindow(QWidget *parent, Qt::WindowFlags flag |
| 124 | 124 | connect(this->spectrumDock, SIGNAL(usedChanged(unsigned int, bool)), this->dsoWidget, SLOT(updateSpectrumUsed(unsigned int, bool))); |
| 125 | 125 | connect(this->spectrumDock, SIGNAL(magnitudeChanged(unsigned int, double)), this->dsoWidget, SLOT(updateSpectrumMagnitude(unsigned int))); |
| 126 | 126 | |
| 127 | + // Started/stopped signals from oscilloscope | |
| 128 | + connect(this->dsoControl, SIGNAL(samplingStarted()), this, SLOT(started())); | |
| 129 | + connect(this->dsoControl, SIGNAL(samplingStopped()), this, SLOT(stopped())); | |
| 130 | + | |
| 127 | 131 | // Set up the oscilloscope |
| 128 | 132 | for(unsigned int channel = 0; channel < this->settings->scope.physicalChannels; channel++) { |
| 129 | 133 | this->dsoControl->setCoupling(channel, (Dso::Coupling) this->settings->scope.voltage[channel].misc); |
| ... | ... | @@ -191,10 +195,9 @@ void OpenHantekMainWindow::createActions() { |
| 191 | 195 | this->configAction->setStatusTip(tr("Configure the oscilloscope")); |
| 192 | 196 | connect(this->configAction, SIGNAL(triggered()), this, SLOT(config())); |
| 193 | 197 | |
| 194 | - this->startStopAction = new QAction(QIcon(":actions/stop.png"), tr("&Stop"), this); | |
| 198 | + this->startStopAction = new QAction(this); | |
| 195 | 199 | this->startStopAction->setShortcut(tr("Space")); |
| 196 | - this->startStopAction->setStatusTip(tr("Stop the oscilloscope")); | |
| 197 | - connect(this->startStopAction, SIGNAL(triggered()), this, SLOT(stop())); | |
| 200 | + this->stopped(); | |
| 198 | 201 | |
| 199 | 202 | this->bufferSizeActionGroup = new QActionGroup(this); |
| 200 | 203 | connect(this->bufferSizeActionGroup, SIGNAL(selected(QAction *)), this, SLOT(bufferSizeSelected(QAction *))); |
| ... | ... | @@ -541,7 +544,7 @@ bool OpenHantekMainWindow::save() { |
| 541 | 544 | if (this->currentFile.isEmpty()) { |
| 542 | 545 | return saveAs(); |
| 543 | 546 | } else { |
| 544 | - return false; // TODO | |
| 547 | + return false; /// \todo Saving of individual setting files | |
| 545 | 548 | } |
| 546 | 549 | } |
| 547 | 550 | |
| ... | ... | @@ -552,33 +555,27 @@ bool OpenHantekMainWindow::saveAs() { |
| 552 | 555 | if (fileName.isEmpty()) |
| 553 | 556 | return false; |
| 554 | 557 | |
| 555 | - return false; // TODO | |
| 558 | + return false; /// \todo Saving of individual setting files | |
| 556 | 559 | } |
| 557 | 560 | |
| 558 | -/// \brief Start the oscilloscope. | |
| 559 | -void OpenHantekMainWindow::start() { | |
| 561 | +/// \brief The oscilloscope started sampling. | |
| 562 | +void OpenHantekMainWindow::started() { | |
| 560 | 563 | this->startStopAction->setText(tr("&Stop")); |
| 561 | 564 | this->startStopAction->setIcon(QIcon(":actions/stop.png")); |
| 562 | 565 | this->startStopAction->setStatusTip(tr("Stop the oscilloscope")); |
| 563 | 566 | |
| 564 | - disconnect(this->startStopAction, SIGNAL(triggered()), this, SLOT(start())); | |
| 565 | - connect(this->startStopAction, SIGNAL(triggered()), this, SLOT(stop())); | |
| 566 | - connect(this->dsoControl, SIGNAL(disconnected()), this, SLOT(stopped())); | |
| 567 | - | |
| 568 | - this->dsoControl->startSampling(); | |
| 567 | + disconnect(this->startStopAction, SIGNAL(triggered()), this->dsoControl, SLOT(startSampling())); | |
| 568 | + connect(this->startStopAction, SIGNAL(triggered()), this->dsoControl, SLOT(stopSampling())); | |
| 569 | 569 | } |
| 570 | 570 | |
| 571 | -/// \brief Stop the oscilloscope. | |
| 572 | -void OpenHantekMainWindow::stop() { | |
| 571 | +/// \brief The oscilloscope stopped sampling. | |
| 572 | +void OpenHantekMainWindow::stopped() { | |
| 573 | 573 | this->startStopAction->setText(tr("&Start")); |
| 574 | 574 | this->startStopAction->setIcon(QIcon(":actions/start.png")); |
| 575 | 575 | this->startStopAction->setStatusTip(tr("Start the oscilloscope")); |
| 576 | 576 | |
| 577 | - disconnect(this->startStopAction, SIGNAL(triggered()), this, SLOT(stop())); | |
| 578 | - disconnect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped())); | |
| 579 | - connect(this->startStopAction, SIGNAL(triggered()), this, SLOT(start())); | |
| 580 | - | |
| 581 | - this->dsoControl->stopSampling(); | |
| 577 | + disconnect(this->startStopAction, SIGNAL(triggered()), this->dsoControl, SLOT(stopSampling())); | |
| 578 | + connect(this->startStopAction, SIGNAL(triggered()), this->dsoControl, SLOT(startSampling())); | |
| 582 | 579 | } |
| 583 | 580 | |
| 584 | 581 | /// \brief Configure the oscilloscope. | ... | ... |
openhantek/src/openhantek.h
| ... | ... | @@ -118,8 +118,8 @@ class OpenHantekMainWindow : public QMainWindow { |
| 118 | 118 | void digitalPhosphor(bool enabled); |
| 119 | 119 | void zoom(bool enabled); |
| 120 | 120 | // Oscilloscope control |
| 121 | - void start(); | |
| 122 | - void stop(); | |
| 121 | + void started(); | |
| 122 | + void stopped(); | |
| 123 | 123 | // Other |
| 124 | 124 | void config(); |
| 125 | 125 | void about(); | ... | ... |