Commit c3b8187182560bc9edd5bfe8352f869fced243b2

Authored by oliverhaag
1 parent a29b1fc2

Implemented single trigger mode and fixed a bug

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
... ... @@ -69,7 +69,7 @@ namespace Hantek {
69 69  
70 70 unsigned int calculateTriggerPoint(unsigned int value);
71 71 int getCaptureState();
72   - int getSamples();
  72 + int getSamples(bool process);
73 73  
74 74 Device *device; ///< The USB device for the oscilloscope
75 75  
... ...
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();
... ...