Commit 45479282876370e5670dd5ebff24cd8e6dba0e43

Authored by oliverhaag
1 parent fba5d6e4

Roll-mode support

openhantek/ChangeLog
... ... @@ -203,3 +203,8 @@
203 203 2012-12-04 Oliver Haag <oliver.haag@gmail.com>
204 204 * Workaround for stacked QGLWidget on Mac OS X
205 205 * Bugfix: Check for connected scope on setSamplerate/setRecordTime
  206 +
  207 +2013-03-12 Oliver Haag <oliver.haag@gmail.com>
  208 +* Use std::vector instead of QList
  209 +* Experimental Roll-mode support
  210 +* QThread::msleep is too unprecise, causing problems in Roll-mode
... ...
openhantek/src/dataanalyzer.cpp
... ... @@ -38,7 +38,22 @@
38 38  
39 39  
40 40 ////////////////////////////////////////////////////////////////////////////////
41   -// class HorizontalDock
  41 +// struct SampleValues
  42 +/// \brief Initializes the members to their default values.
  43 +SampleValues::SampleValues() {
  44 + this->interval = 0.0;
  45 +}
  46 +
  47 +////////////////////////////////////////////////////////////////////////////////
  48 +// struct AnalyzedData
  49 +/// \brief Initializes the members to their default values.
  50 +AnalyzedData::AnalyzedData() {
  51 + this->amplitude = 0.0;
  52 + this->frequency = 0.0;
  53 +}
  54 +
  55 +////////////////////////////////////////////////////////////////////////////////
  56 +// class DataAnalyzer
42 57 /// \brief Initializes the buffers and other variables.
43 58 /// \param settings The settings that should be used.
44 59 /// \param parent The parent widget.
... ... @@ -59,24 +74,16 @@ DataAnalyzer::DataAnalyzer(DsoSettings *settings, QObject *parent) : QThread(par
59 74  
60 75 /// \brief Deallocates the buffers.
61 76 DataAnalyzer::~DataAnalyzer() {
62   - for(int channel = 0; channel < this->analyzedData.count(); ++channel) {
63   - AnalyzedData *channelData = this->analyzedData[channel];
64   -
65   - if(channelData->samples.voltage.sample)
66   - delete[] channelData->samples.voltage.sample;
67   - if(channelData->samples.spectrum.sample)
68   - delete[] channelData->samples.spectrum.sample;
69   - }
70 77 }
71 78  
72 79 /// \brief Returns the analyzed data.
73 80 /// \param channel Channel, whose data should be returned.
74 81 /// \return Analyzed data as AnalyzedData struct.
75   -const AnalyzedData *DataAnalyzer::data(int channel) const {
76   - if(channel < 0 || channel >= this->analyzedData.count())
  82 +AnalyzedData const *DataAnalyzer::data(unsigned int channel) const {
  83 + if(channel >= this->analyzedData.size())
77 84 return 0;
78 85  
79   - return this->analyzedData[channel];
  86 + return &this->analyzedData[channel];
80 87 }
81 88  
82 89 /// \brief Returns the sample count of the analyzed data.
... ... @@ -96,96 +103,79 @@ void DataAnalyzer::run() {
96 103 this->analyzedDataMutex->lock();
97 104  
98 105 unsigned int maxSamples = 0;
99   - unsigned int channelCount = (unsigned int) this->settings->scope.voltage.count();
  106 + unsigned int channelCount = (unsigned int) this->settings->scope.voltage.size();
100 107  
101 108 // Adapt the number of channels for analyzed data
102   - for(unsigned int channel = this->analyzedData.count(); channel < channelCount; ++channel) {
103   - AnalyzedData *channelData = new AnalyzedData;
104   - channelData->samples.voltage.count = 0;
105   - channelData->samples.voltage.interval = 0;
106   - channelData->samples.voltage.sample = 0;
107   - channelData->samples.spectrum.count = 0;
108   - channelData->samples.spectrum.interval = 0;
109   - channelData->samples.spectrum.sample = 0;
110   - channelData->amplitude = 0;
111   - channelData->frequency = 0;
112   - this->analyzedData.append(channelData);
113   - }
114   - for(unsigned int channel = this->analyzedData.count(); channel > channelCount; --channel) {
115   - AnalyzedData *channelData = this->analyzedData.last();
116   - if(channelData->samples.voltage.sample)
117   - delete[] channelData->samples.voltage.sample;
118   - if(channelData->samples.spectrum.sample)
119   - delete[] channelData->samples.spectrum.sample;
120   - this->analyzedData.removeLast();
121   - }
  109 + this->analyzedData.resize(channelCount);
122 110  
123 111 for(unsigned int channel = 0; channel < channelCount; ++channel) {
124   - AnalyzedData *channelData = this->analyzedData[channel];
  112 + AnalyzedData *const channelData = &this->analyzedData[channel];
125 113  
126 114 if( // Check...
127 115 ( // ...if we got data for this channel...
128 116 channel < this->settings->scope.physicalChannels &&
129   - channel < (unsigned int) this->waitingData.count() &&
130   - this->waitingData[channel]) ||
  117 + channel < (unsigned int) this->waitingData->size() &&
  118 + !this->waitingData->at(channel).empty()) ||
131 119 ( // ...or if it's a math channel that can be calculated
132 120 channel >= this->settings->scope.physicalChannels &&
133 121 (this->settings->scope.voltage[channel].used || this->settings->scope.spectrum[channel].used) &&
134   - this->analyzedData.count() >= 2 &&
135   - this->analyzedData[0]->samples.voltage.sample &&
136   - this->analyzedData[1]->samples.voltage.sample
  122 + this->analyzedData.size() >= 2 &&
  123 + !this->analyzedData[0].samples.voltage.sample.empty() &&
  124 + !this->analyzedData[1].samples.voltage.sample.empty()
137 125 )
138 126 ) {
139 127 // Set sampling interval
140   - channelData->samples.voltage.interval = 1.0 / this->waitingDataSamplerate;
  128 + const double interval = 1.0 / this->waitingDataSamplerate;
  129 + if(interval != channelData->samples.voltage.interval) {
  130 + channelData->samples.voltage.interval = interval;
  131 + if(this->waitingDataAppend) // Clear roll buffer if the samplerate changed
  132 + channelData->samples.voltage.sample.clear();
  133 + }
  134 +
141 135  
142 136 unsigned int size;
143 137 if(channel < this->settings->scope.physicalChannels) {
144   - size = this->waitingDataSize[channel];
  138 + size = this->waitingData->at(channel).size();
  139 + if(this->waitingDataAppend)
  140 + size += channelData->samples.voltage.sample.size();
145 141 if(size > maxSamples)
146 142 maxSamples = size;
147 143 }
148 144 else
149 145 size = maxSamples;
150   - // Reallocate memory for samples if the sample count has changed
151   - if(channelData->samples.voltage.count != size) {
152   - channelData->samples.voltage.count = size;
153   - if(channelData->samples.voltage.sample)
154   - delete[] channelData->samples.voltage.sample;
155   - channelData->samples.voltage.sample = new double[size];
156   - }
157 146  
158 147 // Physical channels
159 148 if(channel < this->settings->scope.physicalChannels) {
160 149 // Copy the buffer of the oscilloscope into the sample buffer
161   - if(channel < (unsigned int) this->waitingData.count())
162   - for(unsigned int position = 0; position < this->waitingDataSize[channel]; ++position)
163   - channelData->samples.voltage.sample[position] = this->waitingData[channel][position];
  150 + if(this->waitingDataAppend)
  151 + channelData->samples.voltage.sample.insert(channelData->samples.voltage.sample.end(), this->waitingData->at(channel).begin(), this->waitingData->at(channel).end());
  152 + else
  153 + channelData->samples.voltage.sample = this->waitingData->at(channel);
164 154 }
165 155 // Math channel
166 156 else {
  157 + // Resize the sample vector
  158 + channelData->samples.voltage.sample.resize(size);
167 159 // Set sampling interval
168   - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.interval = this->analyzedData[0]->samples.voltage.interval;
  160 + this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.interval = this->analyzedData[0].samples.voltage.interval;
169 161  
170   - // Reallocate memory for samples if the sample count has changed
171   - if(this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count != this->analyzedData[0]->samples.voltage.count) {
172   - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count = this->analyzedData[0]->samples.voltage.count;
173   - if(this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample)
174   - delete[] this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample;
175   - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample = new double[this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count];
176   - }
  162 + // Resize the sample vector
  163 + this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.sample.resize(qMin(this->analyzedData[0].samples.voltage.sample.size(), this->analyzedData[1].samples.voltage.sample.size()));
177 164  
178 165 // 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) {
  166 + std::vector<double>::const_iterator ch1Iterator = this->analyzedData[0].samples.voltage.sample.begin();
  167 + std::vector<double>::const_iterator ch2Iterator = this->analyzedData[1].samples.voltage.sample.begin();
  168 + std::vector<double> &resultData = this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.sample;
  169 + for(std::vector<double>::iterator resultIterator = resultData.begin(); resultIterator != resultData.end(); ++resultIterator) {
180 170 switch(this->settings->scope.voltage[this->settings->scope.physicalChannels].misc) {
181 171 case Dso::MATHMODE_1ADD2:
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];
  172 + *(resultIterator++) = *(ch1Iterator++) + *(ch2Iterator++);
183 173 break;
184 174 case Dso::MATHMODE_1SUB2:
185   - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample[realPosition] = this->analyzedData[0]->samples.voltage.sample[realPosition] - this->analyzedData[1]->samples.voltage.sample[realPosition];
  175 + *(resultIterator++) = *(ch1Iterator++) - *(ch2Iterator++);
186 176 break;
187 177 case Dso::MATHMODE_2SUB1:
188   - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample[realPosition] = this->analyzedData[1]->samples.voltage.sample[realPosition] - this->analyzedData[0]->samples.voltage.sample[realPosition];
  178 + *(resultIterator++) = *(ch2Iterator++) - *(ch1Iterator++);
189 179 break;
190 180 }
191 181 }
... ... @@ -193,12 +183,8 @@ void DataAnalyzer::run() {
193 183 }
194 184 else {
195 185 // Clear unused channels
196   - channelData->samples.voltage.count = 0;
197   - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.interval = 0;
198   - if(channelData->samples.voltage.sample) {
199   - delete[] channelData->samples.voltage.sample;
200   - channelData->samples.voltage.sample = 0;
201   - }
  186 + channelData->samples.voltage.sample.clear();
  187 + this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.interval = 0;
202 188 }
203 189 }
204 190  
... ... @@ -209,14 +195,15 @@ void DataAnalyzer::run() {
209 195  
210 196  
211 197 // Calculate frequencies, peak-to-peak voltages and spectrums
212   - for(int channel = 0; channel < this->analyzedData.count(); ++channel) {
213   - AnalyzedData *channelData = this->analyzedData[channel];
  198 + for(unsigned int channel = 0; channel < this->analyzedData.size(); ++channel) {
  199 + AnalyzedData *const channelData = &this->analyzedData[channel];
214 200  
215   - if(channelData->samples.voltage.sample) {
  201 + if(!channelData->samples.voltage.sample.empty()) {
216 202 // Calculate new window
217   - if(this->lastWindow != this->settings->scope.spectrumWindow || this->lastRecordLength != channelData->samples.voltage.count) {
218   - if(this->lastRecordLength != channelData->samples.voltage.count) {
219   - this->lastRecordLength = channelData->samples.voltage.count;
  203 + unsigned int sampleCount = channelData->samples.voltage.sample.size();
  204 + if(this->lastWindow != this->settings->scope.spectrumWindow || this->lastRecordLength != sampleCount) {
  205 + if(this->lastRecordLength != sampleCount) {
  206 + this->lastRecordLength = sampleCount;
220 207  
221 208 if(this->window)
222 209 fftw_free(this->window);
... ... @@ -303,28 +290,23 @@ void DataAnalyzer::run() {
303 290 }
304 291  
305 292 // Set sampling interval
306   - channelData->samples.spectrum.interval = 1.0 / channelData->samples.voltage.interval / channelData->samples.voltage.count;
  293 + channelData->samples.spectrum.interval = 1.0 / channelData->samples.voltage.interval / sampleCount;
307 294  
308 295 // Number of real/complex samples
309   - unsigned int dftLength = channelData->samples.voltage.count / 2;
  296 + unsigned int dftLength = sampleCount / 2;
310 297  
311 298 // Reallocate memory for samples if the sample count has changed
312   - if(channelData->samples.spectrum.count != dftLength) {
313   - channelData->samples.spectrum.count = dftLength;
314   - if(channelData->samples.spectrum.sample)
315   - delete[] channelData->samples.spectrum.sample;
316   - channelData->samples.spectrum.sample = new double[channelData->samples.voltage.count];
317   - }
  299 + channelData->samples.spectrum.sample.resize(sampleCount);
318 300  
319 301 // Create sample buffer and apply window
320   - double *windowedValues = new double[channelData->samples.voltage.count];
321   - for(unsigned int position = 0; position < channelData->samples.voltage.count; ++position)
  302 + double *windowedValues = new double[sampleCount];
  303 + for(unsigned int position = 0; position < sampleCount; ++position)
322 304 windowedValues[position] = this->window[position] * channelData->samples.voltage.sample[position];
323 305  
324 306 // Do discrete real to half-complex transformation
325 307 /// \todo Check if record length is multiple of 2
326 308 /// \todo Reuse plan and use FFTW_MEASURE to get fastest algorithm
327   - fftw_plan fftPlan = fftw_plan_r2r_1d(channelData->samples.voltage.count, windowedValues, channelData->samples.spectrum.sample, FFTW_R2HC, FFTW_ESTIMATE);
  309 + fftw_plan fftPlan = fftw_plan_r2r_1d(sampleCount, windowedValues, &channelData->samples.spectrum.sample.front(), FFTW_R2HC, FFTW_ESTIMATE);
328 310 fftw_execute(fftPlan);
329 311 fftw_destroy_plan(fftPlan);
330 312  
... ... @@ -336,15 +318,15 @@ void DataAnalyzer::run() {
336 318 double correctionFactor = 1.0 / dftLength / dftLength;
337 319 conjugateComplex[0] = (channelData->samples.spectrum.sample[0] * channelData->samples.spectrum.sample[0]) * correctionFactor;
338 320 for(position = 1; position < dftLength; ++position)
339   - conjugateComplex[position] = (channelData->samples.spectrum.sample[position] * channelData->samples.spectrum.sample[position] + channelData->samples.spectrum.sample[channelData->samples.voltage.count - position] * channelData->samples.spectrum.sample[channelData->samples.voltage.count - position]) * correctionFactor;
  321 + conjugateComplex[position] = (channelData->samples.spectrum.sample[position] * channelData->samples.spectrum.sample[position] + channelData->samples.spectrum.sample[sampleCount - position] * channelData->samples.spectrum.sample[sampleCount - position]) * correctionFactor;
340 322 // Complex values, all zero for autocorrelation
341 323 conjugateComplex[dftLength] = (channelData->samples.spectrum.sample[dftLength] * channelData->samples.spectrum.sample[dftLength]) * correctionFactor;
342   - for(++position; position < channelData->samples.voltage.count; ++position)
  324 + for(++position; position < sampleCount; ++position)
343 325 conjugateComplex[position] = 0;
344 326  
345 327 // Do half-complex to real inverse transformation
346   - double *correlation = new double[channelData->samples.voltage.count];
347   - fftPlan = fftw_plan_r2r_1d(channelData->samples.voltage.count, conjugateComplex, correlation, FFTW_HC2R, FFTW_ESTIMATE);
  328 + double *correlation = new double[sampleCount];
  329 + fftPlan = fftw_plan_r2r_1d(sampleCount, conjugateComplex, correlation, FFTW_HC2R, FFTW_ESTIMATE);
348 330 fftw_execute(fftPlan);
349 331 fftw_destroy_plan(fftPlan);
350 332 delete[] conjugateComplex;
... ... @@ -353,7 +335,7 @@ void DataAnalyzer::run() {
353 335 double minimalVoltage, maximalVoltage;
354 336 minimalVoltage = maximalVoltage = channelData->samples.voltage.sample[0];
355 337  
356   - for(unsigned int position = 1; position < channelData->samples.voltage.count; ++position) {
  338 + for(unsigned int position = 1; position < sampleCount; ++position) {
357 339 if(channelData->samples.voltage.sample[position] < minimalVoltage)
358 340 minimalVoltage = channelData->samples.voltage.sample[position];
359 341 else if(channelData->samples.voltage.sample[position] > maximalVoltage)
... ... @@ -367,7 +349,7 @@ void DataAnalyzer::run() {
367 349 double peakCorrelation = 0;
368 350 unsigned int peakPosition = 0;
369 351  
370   - for(unsigned int position = 1; position < channelData->samples.voltage.count / 2; ++position) {
  352 + for(unsigned int position = 1; position < sampleCount / 2; ++position) {
371 353 if(correlation[position] > peakCorrelation && correlation[position] > minimumCorrelation * 2) {
372 354 peakCorrelation = correlation[position];
373 355 peakPosition = position;
... ... @@ -388,21 +370,21 @@ void DataAnalyzer::run() {
388 370 // Convert values into dB (Relative to the reference level)
389 371 double offset = 60 - this->settings->scope.spectrumReference - 20 * log10(dftLength);
390 372 double offsetLimit = this->settings->scope.spectrumLimit - this->settings->scope.spectrumReference;
391   - for(unsigned int position = 0; position < channelData->samples.spectrum.count; ++position) {
392   - channelData->samples.spectrum.sample[position] = 20 * log10(fabs(channelData->samples.spectrum.sample[position])) + offset;
  373 + for(std::vector<double>::iterator spectrumIterator = channelData->samples.spectrum.sample.begin(); spectrumIterator != channelData->samples.spectrum.sample.end(); ++spectrumIterator) {
  374 + double value = 20 * log10(fabs(channelData->samples.spectrum.sample[position])) + offset;
393 375  
394 376 // Check if this value has to be limited
395   - if(offsetLimit > channelData->samples.spectrum.sample[position])
396   - channelData->samples.spectrum.sample[position] = offsetLimit;
  377 + if(offsetLimit > value)
  378 + value = offsetLimit;
  379 +
  380 + *spectrumIterator = value;
397 381 }
398 382 }
399 383 }
400   - else if(channelData->samples.spectrum.sample) {
  384 + else if(!channelData->samples.spectrum.sample.empty()) {
401 385 // Clear unused channels
402   - channelData->samples.spectrum.count = 0;
403 386 channelData->samples.spectrum.interval = 0;
404   - delete[] channelData->samples.spectrum.sample;
405   - channelData->samples.spectrum.sample = 0;
  387 + channelData->samples.spectrum.sample.clear();
406 388 }
407 389 }
408 390  
... ... @@ -416,19 +398,27 @@ void DataAnalyzer::run() {
416 398 /// \param data The data arrays with the input data.
417 399 /// \param size The sizes of the data arrays.
418 400 /// \param samplerate The samplerate for all input data.
  401 +/// \param append The data will be appended to the previously analyzed data (Roll mode).
419 402 /// \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) {
  403 +void DataAnalyzer::analyze(const std::vector<std::vector<double> > *data, double samplerate, bool append, QMutex *mutex) {
421 404 // Previous analysis still running, drop the new data
422   - if(this->isRunning())
  405 + if(this->isRunning()) {
  406 +#ifdef DEBUG
  407 + Helper::timestampDebug("Analyzer overload, dropping packets!");
  408 +#endif
423 409 return;
  410 + }
424 411  
425 412 // The thread will analyze it, just save the pointers
426 413 mutex->lock();
427   - this->waitingData.clear();
428   - this->waitingData.append(*data);
429   - this->waitingDataSize.clear();
430   - this->waitingDataSize.append(*size);
  414 + this->waitingData = data;
  415 + this->waitingDataAppend = append;
431 416 this->waitingDataMutex = mutex;
432 417 this->waitingDataSamplerate = samplerate;
433 418 this->start();
  419 +#ifdef DEBUG
  420 + static unsigned long id = 0;
  421 + ++id;
  422 + Helper::timestampDebug(QString("Analyzed packet %1").arg(id));
  423 +#endif
434 424 }
... ...
openhantek/src/dataanalyzer.h
... ... @@ -27,6 +27,8 @@
27 27 #define DATAANALYZER_H
28 28  
29 29  
  30 +#include <vector>
  31 +
30 32 #include <QThread>
31 33  
32 34  
... ... @@ -43,9 +45,10 @@ class QMutex;
43 45 /// \struct SampleValues dataanalyzer.h
44 46 /// \brief Struct for a array of sample values.
45 47 struct SampleValues {
46   - double *sample; ///< Pointer to the array holding the sampling data
47   - unsigned int count; ///< Number of sample values
  48 + std::vector<double> sample; ///< Vector holding the sampling data
48 49 double interval; ///< The interval between two sample values
  50 +
  51 + SampleValues();
49 52 };
50 53  
51 54 ////////////////////////////////////////////////////////////////////////////////
... ... @@ -61,8 +64,10 @@ struct SampleData {
61 64 /// \brief Struct for the analyzed data.
62 65 struct AnalyzedData {
63 66 SampleData samples; ///< Voltage and spectrum values
64   - double frequency; ///< The frequency of the signal
65 67 double amplitude; ///< The amplitude of the signal
  68 + double frequency; ///< The frequency of the signal
  69 +
  70 + AnalyzedData();
66 71 };
67 72  
68 73 ////////////////////////////////////////////////////////////////////////////////
... ... @@ -77,7 +82,7 @@ class DataAnalyzer : public QThread {
77 82 DataAnalyzer(DsoSettings *settings, QObject *parent = 0);
78 83 ~DataAnalyzer();
79 84  
80   - const AnalyzedData *data(int channel) const;
  85 + const AnalyzedData *data(unsigned int channel) const;
81 86 unsigned int sampleCount();
82 87 QMutex *mutex() const;
83 88  
... ... @@ -86,7 +91,7 @@ class DataAnalyzer : public QThread {
86 91  
87 92 DsoSettings *settings; ///< The settings provided by the parent class
88 93  
89   - QList<AnalyzedData *> analyzedData; ///< The analyzed data for each channel
  94 + std::vector<AnalyzedData> analyzedData; ///< The analyzed data for each channel
90 95 QMutex *analyzedDataMutex; ///< A mutex for the analyzed data of all channels
91 96  
92 97 unsigned int lastRecordLength; ///< The record length of the previously analyzed data
... ... @@ -94,13 +99,13 @@ class DataAnalyzer : public QThread {
94 99 Dso::WindowFunction lastWindow; ///< The previously used dft window function
95 100 double *window; ///< The array for the dft window factors
96 101  
97   - QList<double *> waitingData; ///< Pointer to input data from device
98   - QList<unsigned int> waitingDataSize; ///< Number of input data samples
  102 + const std::vector<std::vector<double> > *waitingData; ///< Pointer to input data from device
99 103 double waitingDataSamplerate; ///< The samplerate of the input data
  104 + bool waitingDataAppend; ///< true, if waiting data should be appended
100 105 QMutex *waitingDataMutex; ///< A mutex for the input data
101 106  
102 107 public slots:
103   - void analyze(const QList<double *> *data, const QList<unsigned int> *size, double samplerate, QMutex *mutex);
  108 + void analyze(const std::vector<std::vector<double> > *data, double samplerate, bool append, QMutex *mutex);
104 109  
105 110 signals:
106 111 void analyzed(unsigned long samples); ///< The data with that much samples has been analyzed
... ...
openhantek/src/dsocontrol.h
... ... @@ -27,6 +27,8 @@
27 27 #define DSOCONTROL_H
28 28  
29 29  
  30 +#include <vector>
  31 +
30 32 #include <QStringList>
31 33 #include <QThread>
32 34  
... ... @@ -65,7 +67,7 @@ class DsoControl : public QThread {
65 67 void samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger
66 68 void samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger
67 69 void statusMessage(const QString &message, int timeout); ///< Status message about the oscilloscope
68   - void samplesAvailable(const QList<double *> *data, const QList<unsigned int> *size, double samplerate, QMutex *mutex); ///< New sample data is available
  70 + void samplesAvailable(const std::vector<std::vector<double> > *data, double samplerate, bool append, QMutex *mutex); ///< New sample data is available
69 71  
70 72 void recordLengthChanged(unsigned long duration); ///< The record length has changed
71 73 void recordTimeChanged(double duration); ///< The record time duration has changed
... ...
openhantek/src/exporter.cpp
... ... @@ -231,7 +231,7 @@ bool Exporter::doExport() {
231 231 centerOffset = DIVS_TIME / horizontalFactor / 2;
232 232 }
233 233 unsigned int firstPosition = qMax((int) (centerPosition - centerOffset), 0);
234   - unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.voltage.count - 1);
  234 + unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.voltage.sample.size() - 1);
235 235  
236 236 // Draw graph
237 237 QPointF *graph = new QPointF[lastPosition - firstPosition + 1];
... ... @@ -262,7 +262,7 @@ bool Exporter::doExport() {
262 262 centerOffset = DIVS_TIME / horizontalFactor / 2;
263 263 }
264 264 unsigned int firstPosition = qMax((int) (centerPosition - centerOffset), 0);
265   - unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.spectrum.count - 1);
  265 + unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.spectrum.sample.size() - 1);
266 266  
267 267 // Draw graph
268 268 QPointF *graph = new QPointF[lastPosition - firstPosition + 1];
... ... @@ -382,7 +382,7 @@ bool Exporter::doExport() {
382 382 csvStream << "\"" << this->settings->scope.voltage[channel].name << "\"," << this->dataAnalyzer->data(channel)->samples.voltage.interval;
383 383  
384 384 // And now all sample values in volts
385   - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.count; ++position)
  385 + for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.sample.size(); ++position)
386 386 csvStream << "," << this->dataAnalyzer->data(channel)->samples.voltage.sample[position];
387 387  
388 388 // Finally a newline
... ... @@ -394,7 +394,7 @@ bool Exporter::doExport() {
394 394 csvStream << "\"" << this->settings->scope.spectrum[channel].name << "\"," << this->dataAnalyzer->data(channel)->samples.spectrum.interval;
395 395  
396 396 // And now all magnitudes in dB
397   - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.spectrum.count; ++position)
  397 + for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.spectrum.sample.size(); ++position)
398 398 csvStream << "," << this->dataAnalyzer->data(channel)->samples.spectrum.sample[position];
399 399  
400 400 // Finally a newline
... ...
openhantek/src/glgenerator.cpp
... ... @@ -33,44 +33,6 @@
33 33  
34 34  
35 35 ////////////////////////////////////////////////////////////////////////////////
36   -// class GlArray
37   -/// \brief Initializes the array.
38   -GlArray::GlArray() {
39   - this->data = 0;
40   - this->size = 0;
41   -}
42   -
43   -/// \brief Deletes the array.
44   -GlArray::~GlArray() {
45   - if(this->data)
46   - delete this->data;
47   -}
48   -
49   -/// \brief Get the size of the array.
50   -/// \return Number of array elements.
51   -unsigned int GlArray::getSize() {
52   - return this->size;
53   -}
54   -
55   -/// \brief Set the size of the array.
56   -/// Previous array contents are lost.
57   -/// \param size New number of array elements.
58   -void GlArray::setSize(unsigned int size) {
59   - if(this->size == size)
60   - return;
61   -
62   - if(this->data)
63   - delete[] this->data;
64   - if(size)
65   - this->data = new GLfloat[size];
66   - else
67   - this->data = 0;
68   -
69   - this->size = size;
70   -}
71   -
72   -
73   -////////////////////////////////////////////////////////////////////////////////
74 36 // class GlGenerator
75 37 /// \brief Initializes the scope widget.
76 38 /// \param settings The target settings object.
... ... @@ -104,12 +66,8 @@ void GlGenerator::generateGraphs() {
104 66 return;
105 67  
106 68 // Adapt the number of graphs
107   - for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
108   - for(int channel = this->vaChannel[mode].count(); channel < this->settings->scope.voltage.count(); ++channel)
109   - this->vaChannel[mode].append(QList<GlArray *>());
110   - for(int channel = this->settings->scope.voltage.count(); channel < this->vaChannel[mode].count(); ++channel)
111   - this->vaChannel[mode].removeLast();
112   - }
  69 + for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode)
  70 + this->vaChannel[mode].resize(this->settings->scope.voltage.count());
113 71  
114 72 // Set digital phosphor depth to one if we don't use it
115 73 if(this->settings->view.digitalPhosphor)
... ... @@ -119,18 +77,12 @@ void GlGenerator::generateGraphs() {
119 77  
120 78 // Handle all digital phosphor related list manipulations
121 79 for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
122   - for(int channel = 0; channel < this->vaChannel[mode].count(); ++channel) {
123   - // Resize lists for vector array if the digital phosphor depth has changed
124   - if(this->vaChannel[mode][channel].count() != this->digitalPhosphorDepth)
125   - for(int index = this->vaChannel[mode][channel].count(); index < this->digitalPhosphorDepth; ++index)
126   - this->vaChannel[mode][channel].append(new GlArray());
127   - for(int index = this->digitalPhosphorDepth; index < this->vaChannel[mode][channel].count(); ++index) {
128   - delete this->vaChannel[mode][channel].last();
129   - this->vaChannel[mode][channel].removeLast();
130   - }
131   -
  80 + for(unsigned int channel = 0; channel < this->vaChannel[mode].size(); ++channel) {
132 81 // Move the last list element to the front
133   - this->vaChannel[mode][channel].move(this->digitalPhosphorDepth -1, 0);
  82 + this->vaChannel[mode][channel].push_front(std::vector<GLfloat>());
  83 +
  84 + // Resize lists for vector array to fit the digital phosphor depth
  85 + this->vaChannel[mode][channel].resize(this->digitalPhosphorDepth);
134 86 }
135 87 }
136 88  
... ... @@ -140,21 +92,22 @@ void GlGenerator::generateGraphs() {
140 92 case Dso::GRAPHFORMAT_TY:
141 93 // Add graphs for channels
142 94 for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) {
143   - for(int channel = 0; channel < this->settings->scope.voltage.count(); ++channel) {
  95 + for(int channel = 0; channel < this->settings->scope.voltage.size(); ++channel) {
144 96 // Check if this channel is used and available at the data analyzer
145   - if(((mode == Dso::CHANNELMODE_VOLTAGE) ? this->settings->scope.voltage[channel].used : this->settings->scope.spectrum[channel].used) && this->dataAnalyzer->data(channel) && this->dataAnalyzer->data(channel)->samples.voltage.sample) {
  97 + if(((mode == Dso::CHANNELMODE_VOLTAGE) ? this->settings->scope.voltage[channel].used : this->settings->scope.spectrum[channel].used) && this->dataAnalyzer->data(channel) && !this->dataAnalyzer->data(channel)->samples.voltage.sample.empty()) {
146 98 // Check if the sample count has changed
147   - unsigned int neededSize = ((mode == Dso::CHANNELMODE_VOLTAGE) ? this->dataAnalyzer->data(channel)->samples.voltage.count : this->dataAnalyzer->data(channel)->samples.spectrum.count) * 2;
148   - for(int index = 0; index < this->digitalPhosphorDepth; ++index) {
149   - if(this->vaChannel[mode][channel][index]->getSize() != neededSize)
150   - this->vaChannel[mode][channel][index]->setSize(0);
  99 + unsigned int sampleCount = (mode == Dso::CHANNELMODE_VOLTAGE) ? this->dataAnalyzer->data(channel)->samples.voltage.sample.size() : this->dataAnalyzer->data(channel)->samples.spectrum.sample.size();
  100 + unsigned int neededSize = sampleCount * 2;
  101 + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) {
  102 + if(this->vaChannel[mode][channel][index].size() != neededSize)
  103 + this->vaChannel[mode][channel][index].clear(); // Something was changed, drop old traces
151 104 }
152 105  
153   - // Check if the array is allocated
154   - if(!this->vaChannel[mode][channel].first()->data)
155   - this->vaChannel[mode][channel].first()->setSize(neededSize);
  106 + // Set size directly to avoid reallocations
  107 + this->vaChannel[mode][channel].front().resize(neededSize);
156 108  
157   - GLfloat *vaNewChannel = this->vaChannel[mode][channel].first()->data;
  109 + // Iterator to data for direct access
  110 + std::vector<GLfloat>::iterator glIterator = this->vaChannel[mode][channel].front().begin();
158 111  
159 112 // What's the horizontal distance between sampling points?
160 113 double horizontalFactor;
... ... @@ -164,64 +117,78 @@ void GlGenerator::generateGraphs() {
164 117 horizontalFactor = this->dataAnalyzer->data(channel)->samples.spectrum.interval / this->settings->scope.horizontal.frequencybase;
165 118  
166 119 // Fill vector array
167   - unsigned int arrayPosition = 0;
168 120 if(mode == Dso::CHANNELMODE_VOLTAGE) {
169   - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.count; ++position) {
170   - vaNewChannel[arrayPosition++] = position * horizontalFactor - DIVS_TIME / 2;
171   - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(channel)->samples.voltage.sample[position] / this->settings->scope.voltage[channel].gain + this->settings->scope.voltage[channel].offset;
  121 + std::vector<double>::const_iterator dataIterator = this->dataAnalyzer->data(channel)->samples.voltage.sample.begin();
  122 + const double gain = this->settings->scope.voltage[channel].gain;
  123 + const double offset = this->settings->scope.voltage[channel].offset;
  124 +
  125 + for(unsigned int position = 0; position < sampleCount; ++position) {
  126 + *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2;
  127 + *(glIterator++) = *(dataIterator++) / gain + offset;
172 128 }
173 129 }
174 130 else {
175   - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.spectrum.count; ++position) {
176   - vaNewChannel[arrayPosition++] = position * horizontalFactor - DIVS_TIME / 2;
177   - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(channel)->samples.spectrum.sample[position] / this->settings->scope.spectrum[channel].magnitude + this->settings->scope.spectrum[channel].offset;
  131 + std::vector<double>::const_iterator dataIterator = this->dataAnalyzer->data(channel)->samples.spectrum.sample.begin();
  132 + const double magnitude = this->settings->scope.spectrum[channel].magnitude;
  133 + const double offset = this->settings->scope.spectrum[channel].offset;
  134 +
  135 + for(unsigned int position = 0; position < sampleCount; ++position) {
  136 + *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2;
  137 + *(glIterator++) = *(dataIterator++) / magnitude + offset;
178 138 }
179 139 }
180 140 }
181 141 else {
182 142 // Delete all vector arrays
183   - for(int index = 0; index < this->digitalPhosphorDepth; ++index)
184   - this->vaChannel[mode][channel][index]->setSize(0);
  143 + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index)
  144 + this->vaChannel[mode][channel][index].clear();
185 145 }
186 146 }
187 147 }
188 148 break;
189 149  
190 150 case Dso::GRAPHFORMAT_XY:
191   - for(int channel = 0; channel < this->settings->scope.voltage.count(); ++channel) {
  151 + for(int channel = 0; channel < this->settings->scope.voltage.size(); ++channel) {
192 152 // For even channel numbers check if this channel is used and this and the following channel are available at the data analyzer
193   - if(channel % 2 == 0 && channel + 1 < this->settings->scope.voltage.count() && this->settings->scope.voltage[channel].used && this->dataAnalyzer->data(channel) && this->dataAnalyzer->data(channel)->samples.voltage.sample && this->dataAnalyzer->data(channel + 1) && this->dataAnalyzer->data(channel + 1)->samples.voltage.sample) {
  153 + if(channel % 2 == 0 && channel + 1 < this->settings->scope.voltage.size() && this->settings->scope.voltage[channel].used && this->dataAnalyzer->data(channel) && !this->dataAnalyzer->data(channel)->samples.voltage.sample.empty() && this->dataAnalyzer->data(channel + 1) && !this->dataAnalyzer->data(channel + 1)->samples.voltage.sample.empty()) {
194 154 // Check if the sample count has changed
195   - unsigned int neededSize = qMin(this->dataAnalyzer->data(channel)->samples.voltage.count, this->dataAnalyzer->data(channel + 1)->samples.voltage.count) * 2;
196   - for(int index = 0; index < this->digitalPhosphorDepth; ++index) {
197   - if(this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->getSize() != neededSize)
198   - this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->setSize(0);
  155 + const unsigned int sampleCount = qMin(this->dataAnalyzer->data(channel)->samples.voltage.sample.size(), this->dataAnalyzer->data(channel + 1)->samples.voltage.sample.size());
  156 + const unsigned int neededSize = sampleCount * 2;
  157 + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) {
  158 + if(this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].size() != neededSize)
  159 + this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].clear(); // Something was changed, drop old traces
199 160 }
200 161  
201   - // Check if the array is allocated
202   - if(!this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].first()->data)
203   - this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].first()->setSize(neededSize);
  162 + // Set size directly to avoid reallocations
  163 + this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().resize(neededSize);
204 164  
205   - GLfloat *vaNewChannel = this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].first()->data;
  165 + // Iterator to data for direct access
  166 + std::vector<GLfloat>::iterator glIterator = this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().begin();
206 167  
207 168 // Fill vector array
208   - unsigned int arrayPosition = 0;
209 169 unsigned int xChannel = channel;
210 170 unsigned int yChannel = channel + 1;
211   - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.count; ++position) {
212   - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(xChannel)->samples.voltage.sample[position] / this->settings->scope.voltage[xChannel].gain + this->settings->scope.voltage[xChannel].offset;
213   - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(yChannel)->samples.voltage.sample[position] / this->settings->scope.voltage[yChannel].gain + this->settings->scope.voltage[yChannel].offset;
  171 + std::vector<double>::const_iterator xIterator = this->dataAnalyzer->data(xChannel)->samples.voltage.sample.begin();
  172 + std::vector<double>::const_iterator yIterator = this->dataAnalyzer->data(yChannel)->samples.voltage.sample.begin();
  173 + const double xGain = this->settings->scope.voltage[xChannel].gain;
  174 + const double yGain = this->settings->scope.voltage[yChannel].gain;
  175 + const double xOffset = this->settings->scope.voltage[xChannel].offset;
  176 + const double yOffset = this->settings->scope.voltage[yChannel].offset;
  177 +
  178 + for(unsigned int position = 0; position < sampleCount; ++position) {
  179 + *(glIterator++) = *(xIterator++) / xGain + xOffset;
  180 + *(glIterator++) = *(yIterator++) / yGain + yOffset;
214 181 }
215 182 }
216 183 else {
217 184 // Delete all vector arrays
218   - for(int index = 0; index < this->digitalPhosphorDepth; ++index)
219   - this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->setSize(0);
  185 + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index)
  186 + this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].clear();
220 187 }
221 188  
222 189 // Delete all spectrum graphs
223   - for(int index = 0; index < this->digitalPhosphorDepth; ++index)
224   - this->vaChannel[Dso::CHANNELMODE_SPECTRUM][channel][index]->setSize(0);
  190 + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index)
  191 + this->vaChannel[Dso::CHANNELMODE_SPECTRUM][channel][index].clear();
225 192 }
226 193 break;
227 194  
... ... @@ -237,20 +204,20 @@ void GlGenerator::generateGraphs() {
237 204 /// \brief Create the needed OpenGL vertex arrays for the grid.
238 205 void GlGenerator::generateGrid() {
239 206 // Grid
240   - this->vaGrid[0].setSize(((DIVS_TIME * DIVS_SUB - 2) * (DIVS_VOLTAGE - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2) * (DIVS_TIME - 2) - ((DIVS_TIME - 2) * (DIVS_VOLTAGE - 2))) * 2);
241   - int pointIndex = 0;
  207 + this->vaGrid[0].resize(((DIVS_TIME * DIVS_SUB - 2) * (DIVS_VOLTAGE - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2) * (DIVS_TIME - 2) - ((DIVS_TIME - 2) * (DIVS_VOLTAGE - 2))) * 2);
  208 + std::vector<GLfloat>::iterator glIterator = this->vaGrid[0].begin();
242 209 // Draw vertical lines
243 210 for(int div = 1; div < DIVS_TIME / 2; ++div) {
244 211 for(int dot = 1; dot < DIVS_VOLTAGE / 2 * DIVS_SUB; ++dot) {
245 212 float dotPosition = (float) dot / DIVS_SUB;
246   - this->vaGrid[0].data[pointIndex++] = -div;
247   - this->vaGrid[0].data[pointIndex++] = -dotPosition;
248   - this->vaGrid[0].data[pointIndex++] = -div;
249   - this->vaGrid[0].data[pointIndex++] = dotPosition;
250   - this->vaGrid[0].data[pointIndex++] = div;
251   - this->vaGrid[0].data[pointIndex++] = -dotPosition;
252   - this->vaGrid[0].data[pointIndex++] = div;
253   - this->vaGrid[0].data[pointIndex++] = dotPosition;
  213 + *(glIterator++) = -div;
  214 + *(glIterator++) = -dotPosition;
  215 + *(glIterator++) = -div;
  216 + *(glIterator++) = dotPosition;
  217 + *(glIterator++) = div;
  218 + *(glIterator++) = -dotPosition;
  219 + *(glIterator++) = div;
  220 + *(glIterator++) = dotPosition;
254 221 }
255 222 }
256 223 // Draw horizontal lines
... ... @@ -259,63 +226,64 @@ void GlGenerator::generateGrid() {
259 226 if(dot % DIVS_SUB == 0)
260 227 continue; // Already done by vertical lines
261 228 float dotPosition = (float) dot / DIVS_SUB;
262   - this->vaGrid[0].data[pointIndex++] = -dotPosition;
263   - this->vaGrid[0].data[pointIndex++] = -div;
264   - this->vaGrid[0].data[pointIndex++] = dotPosition;
265   - this->vaGrid[0].data[pointIndex++] = -div;
266   - this->vaGrid[0].data[pointIndex++] = -dotPosition;
267   - this->vaGrid[0].data[pointIndex++] = div;
268   - this->vaGrid[0].data[pointIndex++] = dotPosition;
269   - this->vaGrid[0].data[pointIndex++] = div;
  229 + *(glIterator++) = -dotPosition;
  230 + *(glIterator++) = -div;
  231 + *(glIterator++) = dotPosition;
  232 + *(glIterator++) = -div;
  233 + *(glIterator++) = -dotPosition;
  234 + *(glIterator++) = div;
  235 + *(glIterator++) = dotPosition;
  236 + *(glIterator++) = div;
270 237 }
271 238 }
272 239  
273 240 // Axes
274   - this->vaGrid[1].setSize((2 + (DIVS_TIME * DIVS_SUB - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2)) * 4);
275   - pointIndex = 0;
  241 + this->vaGrid[1].resize((2 + (DIVS_TIME * DIVS_SUB - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2)) * 4);
  242 + glIterator = this->vaGrid[1].begin();
276 243 // Horizontal axis
277   - this->vaGrid[1].data[pointIndex++] = -DIVS_TIME / 2;
278   - this->vaGrid[1].data[pointIndex++] = 0;
279   - this->vaGrid[1].data[pointIndex++] = DIVS_TIME / 2;
280   - this->vaGrid[1].data[pointIndex++] = 0;
  244 + *(glIterator++) = -DIVS_TIME / 2;
  245 + *(glIterator++) = 0;
  246 + *(glIterator++) = DIVS_TIME / 2;
  247 + *(glIterator++) = 0;
281 248 // Vertical axis
282   - this->vaGrid[1].data[pointIndex++] = 0;
283   - this->vaGrid[1].data[pointIndex++] = -DIVS_VOLTAGE / 2;
284   - this->vaGrid[1].data[pointIndex++] = 0;
285   - this->vaGrid[1].data[pointIndex++] = DIVS_VOLTAGE / 2;
  249 + *(glIterator++) = 0;
  250 + *(glIterator++) = -DIVS_VOLTAGE / 2;
  251 + *(glIterator++) = 0;
  252 + *(glIterator++) = DIVS_VOLTAGE / 2;
286 253 // Subdiv lines on horizontal axis
287 254 for(int line = 1; line < DIVS_TIME / 2 * DIVS_SUB; ++line) {
288 255 float linePosition = (float) line / DIVS_SUB;
289   - this->vaGrid[1].data[pointIndex++] = linePosition;
290   - this->vaGrid[1].data[pointIndex++] = -0.05;
291   - this->vaGrid[1].data[pointIndex++] = linePosition;
292   - this->vaGrid[1].data[pointIndex++] = 0.05;
293   - this->vaGrid[1].data[pointIndex++] = -linePosition;
294   - this->vaGrid[1].data[pointIndex++] = -0.05;
295   - this->vaGrid[1].data[pointIndex++] = -linePosition;
296   - this->vaGrid[1].data[pointIndex++] = 0.05;
  256 + *(glIterator++) = linePosition;
  257 + *(glIterator++) = -0.05;
  258 + *(glIterator++) = linePosition;
  259 + *(glIterator++) = 0.05;
  260 + *(glIterator++) = -linePosition;
  261 + *(glIterator++) = -0.05;
  262 + *(glIterator++) = -linePosition;
  263 + *(glIterator++) = 0.05;
297 264 }
298 265 // Subdiv lines on vertical axis
299 266 for(int line = 1; line < DIVS_VOLTAGE / 2 * DIVS_SUB; ++line) {
300 267 float linePosition = (float) line / DIVS_SUB;
301   - this->vaGrid[1].data[pointIndex++] = -0.05;
302   - this->vaGrid[1].data[pointIndex++] = linePosition;
303   - this->vaGrid[1].data[pointIndex++] = 0.05;
304   - this->vaGrid[1].data[pointIndex++] = linePosition;
305   - this->vaGrid[1].data[pointIndex++] = -0.05;
306   - this->vaGrid[1].data[pointIndex++] = -linePosition;
307   - this->vaGrid[1].data[pointIndex++] = 0.05;
308   - this->vaGrid[1].data[pointIndex++] = -linePosition;
  268 + *(glIterator++) = -0.05;
  269 + *(glIterator++) = linePosition;
  270 + *(glIterator++) = 0.05;
  271 + *(glIterator++) = linePosition;
  272 + *(glIterator++) = -0.05;
  273 + *(glIterator++) = -linePosition;
  274 + *(glIterator++) = 0.05;
  275 + *(glIterator++) = -linePosition;
309 276 }
310 277  
311 278 // Border
312   - this->vaGrid[2].setSize(4 * 2);
313   - this->vaGrid[2].data[0] = -DIVS_TIME / 2;
314   - this->vaGrid[2].data[1] = -DIVS_VOLTAGE / 2;
315   - this->vaGrid[2].data[2] = DIVS_TIME / 2;
316   - this->vaGrid[2].data[3] = -DIVS_VOLTAGE / 2;
317   - this->vaGrid[2].data[4] = DIVS_TIME / 2;
318   - this->vaGrid[2].data[5] = DIVS_VOLTAGE / 2;
319   - this->vaGrid[2].data[6] = -DIVS_TIME / 2;
320   - this->vaGrid[2].data[7] = DIVS_VOLTAGE / 2;
  279 + this->vaGrid[2].resize(4 * 2);
  280 + glIterator = this->vaGrid[2].begin();
  281 + *(glIterator++) = -DIVS_TIME / 2;
  282 + *(glIterator++) = -DIVS_VOLTAGE / 2;
  283 + *(glIterator++) = DIVS_TIME / 2;
  284 + *(glIterator++) = -DIVS_VOLTAGE / 2;
  285 + *(glIterator++) = DIVS_TIME / 2;
  286 + *(glIterator++) = DIVS_VOLTAGE / 2;
  287 + *(glIterator++) = -DIVS_TIME / 2;
  288 + *(glIterator++) = DIVS_VOLTAGE / 2;
321 289 }
... ...
openhantek/src/glgenerator.h
... ... @@ -29,8 +29,9 @@
29 29 #define GLGENERATOR_H
30 30  
31 31  
  32 +#include <deque>
  33 +
32 34 #include <QGLWidget>
33   -#include <QList>
34 35 #include <QObject>
35 36  
36 37  
... ... @@ -48,23 +49,6 @@ class GlScope;
48 49  
49 50  
50 51 ////////////////////////////////////////////////////////////////////////////////
51   -/// \class GlArray glgenerator.h
52   -/// \brief An array of GLfloat values and it's size.
53   -class GlArray {
54   - public:
55   - GlArray();
56   - ~GlArray();
57   -
58   - unsigned int getSize();
59   - void setSize(unsigned int size);
60   -
61   - GLfloat *data; ///< Pointer to the array
62   -
63   - protected:
64   - unsigned int size; ///< The array size (Number of GLfloat values)
65   -};
66   -
67   -////////////////////////////////////////////////////////////////////////////////
68 52 /// \class GlGenerator glgenerator.h
69 53 /// \brief Generates the vertex arrays for the GlScope classes.
70 54 class GlGenerator : public QObject {
... ... @@ -85,10 +69,10 @@ class GlGenerator : public QObject {
85 69 DataAnalyzer *dataAnalyzer;
86 70 DsoSettings *settings;
87 71  
88   - QList<QList<GlArray *> > vaChannel[Dso::CHANNELMODE_COUNT];
89   - GlArray vaGrid[3];
  72 + std::vector<std::deque<std::vector<GLfloat> > > vaChannel[Dso::CHANNELMODE_COUNT];
  73 + std::vector<GLfloat> vaGrid[3];
90 74  
91   - int digitalPhosphorDepth;
  75 + unsigned int digitalPhosphorDepth;
92 76  
93 77 public slots:
94 78 void generateGraphs();
... ...
openhantek/src/glscope.cpp
... ... @@ -96,7 +96,7 @@ void GlScope::paintGL() {
96 96 double *fadingFactor = new double[this->generator->digitalPhosphorDepth];
97 97 fadingFactor[0] = 100;
98 98 double fadingRatio = pow(10.0, 2.0 / this->generator->digitalPhosphorDepth);
99   - for(int index = 1; index < this->generator->digitalPhosphorDepth; ++index)
  99 + for(unsigned int index = 1; index < this->generator->digitalPhosphorDepth; ++index)
100 100 fadingFactor[index] = fadingFactor[index - 1] * fadingRatio;
101 101  
102 102 switch(this->settings->scope.horizontal.format) {
... ... @@ -107,13 +107,13 @@ void GlScope::paintGL() {
107 107 if((mode == Dso::CHANNELMODE_VOLTAGE) ? this->settings->scope.voltage[channel].used : this->settings->scope.spectrum[channel].used) {
108 108 // Draw graph for all available depths
109 109 for(int index = this->generator->digitalPhosphorDepth - 1; index >= 0; index--) {
110   - if(this->generator->vaChannel[mode][channel][index]->data) {
  110 + if(!this->generator->vaChannel[mode][channel][index].empty()) {
111 111 if(mode == Dso::CHANNELMODE_VOLTAGE)
112 112 this->qglColor(this->settings->view.color.screen.voltage[channel].darker(fadingFactor[index]));
113 113 else
114 114 this->qglColor(this->settings->view.color.screen.spectrum[channel].darker(fadingFactor[index]));
115   - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaChannel[mode][channel][index]->data);
116   - glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[mode][channel][index]->getSize() / 2);
  115 + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaChannel[mode][channel][index].front());
  116 + glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[mode][channel][index].size() / 2);
117 117 }
118 118 }
119 119 }
... ... @@ -127,10 +127,10 @@ void GlScope::paintGL() {
127 127 if(this->settings->scope.voltage[channel].used) {
128 128 // Draw graph for all available depths
129 129 for(int index = this->generator->digitalPhosphorDepth - 1; index >= 0; index--) {
130   - if(this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->data) {
  130 + if(!this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].empty()) {
131 131 this->qglColor(this->settings->view.color.screen.voltage[channel].darker(fadingFactor[index]));
132   - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->data);
133   - glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->getSize() / 2);
  132 + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].front());
  133 + glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].size() / 2);
134 134 }
135 135 }
136 136 }
... ... @@ -156,17 +156,17 @@ void GlScope::paintGL() {
156 156 this->qglColor(this->settings->view.color.screen.markers);
157 157  
158 158 for(int marker = 0; marker < MARKER_COUNT; ++marker) {
159   - if(!this->vaMarker[marker].data) {
160   - this->vaMarker[marker].setSize(2 * 2);
161   - this->vaMarker[marker].data[1] = - DIVS_VOLTAGE;
162   - this->vaMarker[marker].data[3] = DIVS_VOLTAGE;
  159 + if(this->vaMarker[marker].size() != 4) {
  160 + this->vaMarker[marker].resize(2 * 2);
  161 + this->vaMarker[marker][1] = -DIVS_VOLTAGE;
  162 + this->vaMarker[marker][3] = DIVS_VOLTAGE;
163 163 }
164 164  
165   - this->vaMarker[marker].data[0] = this->settings->scope.horizontal.marker[marker];
166   - this->vaMarker[marker].data[2] = this->settings->scope.horizontal.marker[marker];
  165 + this->vaMarker[marker][0] = this->settings->scope.horizontal.marker[marker];
  166 + this->vaMarker[marker][2] = this->settings->scope.horizontal.marker[marker];
167 167  
168   - glVertexPointer(2, GL_FLOAT, 0, this->vaMarker[marker].data);
169   - glDrawArrays(GL_LINES, 0, this->vaMarker[marker].getSize() / 2);
  168 + glVertexPointer(2, GL_FLOAT, 0, &this->vaMarker[marker].front());
  169 + glDrawArrays(GL_LINES, 0, this->vaMarker[marker].size() / 2);
170 170 }
171 171  
172 172 glDisable(GL_LINE_STIPPLE);
... ... @@ -215,14 +215,14 @@ void GlScope::drawGrid() {
215 215  
216 216 // Grid
217 217 this->qglColor(this->settings->view.color.screen.grid);
218   - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaGrid[0].data);
219   - glDrawArrays(GL_POINTS, 0, this->generator->vaGrid[0].getSize() / 2);
  218 + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaGrid[0].front());
  219 + glDrawArrays(GL_POINTS, 0, this->generator->vaGrid[0].size() / 2);
220 220 // Axes
221 221 this->qglColor(this->settings->view.color.screen.axes);
222   - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaGrid[1].data);
223   - glDrawArrays(GL_LINES, 0, this->generator->vaGrid[1].getSize() / 2);
  222 + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaGrid[1].front());
  223 + glDrawArrays(GL_LINES, 0, this->generator->vaGrid[1].size() / 2);
224 224 // Border
225 225 this->qglColor(this->settings->view.color.screen.border);
226   - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaGrid[2].data);
227   - glDrawArrays(GL_LINE_LOOP, 0, this->generator->vaGrid[2].getSize() / 2);
  226 + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaGrid[2].front());
  227 + glDrawArrays(GL_LINE_LOOP, 0, this->generator->vaGrid[2].size() / 2);
228 228 }
... ...
openhantek/src/glscope.h
... ... @@ -64,7 +64,7 @@ class GlScope : public QGLWidget {
64 64 GlGenerator *generator;
65 65 DsoSettings *settings;
66 66  
67   - GlArray vaMarker[2];
  67 + std::vector<GLfloat> vaMarker[2];
68 68 bool zoomed;
69 69 };
70 70  
... ...
openhantek/src/hantek/control.cpp
... ... @@ -29,6 +29,7 @@
29 29  
30 30 #include <QList>
31 31 #include <QMutex>
  32 +#include <QTime>
32 33  
33 34  
34 35 #include "hantek/control.h"
... ... @@ -110,10 +111,7 @@ namespace Hantek {
110 111 this->device = new Device(this);
111 112  
112 113 // Sample buffers
113   - for(unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
114   - this->samples.append(0);
115   - this->samplesSize.append(0);
116   - }
  114 + this->samples.resize(HANTEK_CHANNELS);
117 115  
118 116 this->previousSampleCount = 0;
119 117  
... ... @@ -162,6 +160,7 @@ namespace Hantek {
162 160  
163 161 // The control loop is running until the device is disconnected
164 162 int captureState = CAPTURE_WAITING;
  163 + int rollState = 0;
165 164 bool samplingStarted = false;
166 165 Dso::TriggerMode lastTriggerMode = (Dso::TriggerMode) -1;
167 166  
... ... @@ -172,7 +171,7 @@ namespace Hantek {
172 171 continue;
173 172  
174 173 #ifdef DEBUG
175   - qDebug("Sending bulk command:%s", Helper::hexDump(this->command[command]->data(), this->command[command]->getSize()).toLocal8Bit().data());
  174 + Helper::timestampDebug(QString("Sending bulk command:%1").arg(Helper::hexDump(this->command[command]->data(), this->command[command]->getSize())));
176 175 #endif
177 176  
178 177 errorCode = this->device->bulkCommand(this->command[command]);
... ... @@ -196,7 +195,7 @@ namespace Hantek {
196 195 continue;
197 196  
198 197 #ifdef DEBUG
199   - qDebug("Sending control command %02x:%s", this->controlCode[control], Helper::hexDump(this->control[control]->data(), this->control[control]->getSize()).toLocal8Bit().data());
  198 + Helper::timestampDebug(QString("Sending control command %1:%2").arg(QString::number(this->controlCode[control], 16), Helper::hexDump(this->control[control]->data(), this->control[control]->getSize())));
200 199 #endif
201 200  
202 201 errorCode = this->device->controlWrite(this->controlCode[control], this->control[control]->data(), this->control[control]->getSize());
... ... @@ -218,9 +217,9 @@ namespace Hantek {
218 217 // Not more often than every 10 ms though
219 218 int cycleTime;
220 219 if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] == UINT_MAX)
221   - cycleTime = qMax((int) ((double) this->device->getPacketSize() / this->settings.samplerate.current * 250), 1);
  220 + cycleTime = qMax((int) ((double) this->device->getPacketSize() / ((this->settings.samplerate.limits == &this->specification.samplerate.multi) ? 1 : HANTEK_CHANNELS) / this->settings.samplerate.current * 250), 1);
222 221 else
223   - cycleTime = qMax((unsigned int) ((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10u);
  222 + cycleTime = qMax((int) ((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10);
224 223 this->msleep(cycleTime);
225 224  
226 225 if(!this->sampling) {
... ... @@ -228,94 +227,184 @@ namespace Hantek {
228 227 continue;
229 228 }
230 229  
  230 + if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] == UINT_MAX) {
  231 + // Roll mode
  232 + captureState = CAPTURE_WAITING;
  233 +
  234 + switch(rollState) {
  235 + case ROLL_STARTSAMPLING:
  236 + // Don't iterate through roll mode steps when stopped
  237 + if(!this->sampling)
  238 + continue;
  239 +
  240 + // Sampling hasn't started, update the expected sample count
  241 + this->previousSampleCount = this->getSampleCount();
  242 +
  243 + errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
  244 + if(errorCode < 0) {
  245 + if(errorCode == LIBUSB_ERROR_NO_DEVICE)
  246 + captureState = LIBUSB_ERROR_NO_DEVICE;
  247 + break;
  248 + }
231 249 #ifdef DEBUG
232   - int lastCaptureState = captureState;
  250 + Helper::timestampDebug("Starting to capture");
233 251 #endif
234   - captureState = this->getCaptureState();
235   - if(captureState < 0)
236   - qWarning("Getting capture state failed: %s", Helper::libUsbErrorString(captureState).toLocal8Bit().data());
  252 +
  253 + samplingStarted = true;
  254 +
  255 + break;
  256 +
  257 + case ROLL_ENABLETRIGGER:
  258 + errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
  259 + if(errorCode < 0) {
  260 + if(errorCode == LIBUSB_ERROR_NO_DEVICE)
  261 + captureState = LIBUSB_ERROR_NO_DEVICE;
  262 + break;
  263 + }
237 264 #ifdef DEBUG
238   - else if(captureState != lastCaptureState)
239   - qDebug("Capture state changed to %d", captureState);
  265 + Helper::timestampDebug("Enabling trigger");
240 266 #endif
241   - switch(captureState) {
242   - case CAPTURE_READY:
243   - case CAPTURE_READY2250:
244   - case CAPTURE_READY5200:
245   - // Get data and process it, if we're still sampling
246   - errorCode = this->getSamples(samplingStarted);
247   - if(errorCode < 0)
248   - qWarning("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
  267 +
  268 + break;
  269 +
  270 + case ROLL_FORCETRIGGER:
  271 + errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
  272 + if(errorCode < 0) {
  273 + if(errorCode == LIBUSB_ERROR_NO_DEVICE)
  274 + captureState = LIBUSB_ERROR_NO_DEVICE;
  275 + break;
  276 + }
249 277 #ifdef DEBUG
250   - else
251   - qDebug("Received %d B of sampling data", errorCode);
  278 + Helper::timestampDebug("Forcing trigger");
252 279 #endif
  280 +
  281 + break;
253 282  
254   - // Check if we're in single trigger mode
255   - if(this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE && samplingStarted)
256   - this->stopSampling();
257   -
258   - // Sampling completed, restart it when necessary
259   - samplingStarted = false;
  283 + case ROLL_GETDATA:
  284 + // Get data and process it, if we're still sampling
  285 + errorCode = this->getSamples(samplingStarted);
  286 + if(errorCode < 0)
  287 + qWarning("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
  288 + #ifdef DEBUG
  289 + else
  290 + Helper::timestampDebug(QString("Received %1 B of sampling data").arg(errorCode));
  291 + #endif
  292 +
  293 + // Check if we're in single trigger mode
  294 + if(this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE && samplingStarted)
  295 + this->stopSampling();
  296 +
  297 + // Sampling completed, restart it when necessary
  298 + samplingStarted = false;
  299 +
  300 + break;
260 301  
261   - // Start next capture if necessary by leaving out the break statement
262   - if(!this->sampling)
  302 + default:
  303 +#ifdef DEBUG
  304 + Helper::timestampDebug("Roll mode state unknown");
  305 +#endif
263 306 break;
  307 + }
264 308  
265   - case CAPTURE_WAITING:
266   - // Sampling hasn't started, update the expected sample count
267   - this->previousSampleCount = this->getSampleCount();
  309 + // Go to next state, or restart if last state was reached
  310 + rollState = (rollState + 1) % ROLL_COUNT;
  311 + }
  312 + else {
  313 + // Standard mode
  314 + rollState = ROLL_STARTSAMPLING;
  315 +
  316 +#ifdef DEBUG
  317 + int lastCaptureState = captureState;
  318 +#endif
  319 + captureState = this->getCaptureState();
  320 + if(captureState < 0)
  321 + qWarning("Getting capture state failed: %s", Helper::libUsbErrorString(captureState).toLocal8Bit().data());
  322 +#ifdef DEBUG
  323 + else if(captureState != lastCaptureState)
  324 + Helper::timestampDebug(QString("Capture state changed to %1").arg(captureState));
  325 +#endif
  326 + switch(captureState) {
  327 + case CAPTURE_READY:
  328 + case CAPTURE_READY2250:
  329 + case CAPTURE_READY5200:
  330 + // Get data and process it, if we're still sampling
  331 + errorCode = this->getSamples(samplingStarted);
  332 + if(errorCode < 0)
  333 + qWarning("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data());
  334 +#ifdef DEBUG
  335 + else
  336 + Helper::timestampDebug(QString("Received %1 B of sampling data").arg(errorCode));
  337 +#endif
  338 +
  339 + // Check if we're in single trigger mode
  340 + if(this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE && samplingStarted)
  341 + this->stopSampling();
  342 +
  343 + // Sampling completed, restart it when necessary
  344 + samplingStarted = false;
  345 +
  346 + // Start next capture if necessary by leaving out the break statement
  347 + if(!this->sampling)
  348 + break;
268 349  
269   - if(samplingStarted && lastTriggerMode == this->settings.trigger.mode) {
270   - ++cycleCounter;
  350 + case CAPTURE_WAITING:
  351 + // Sampling hasn't started, update the expected sample count
  352 + this->previousSampleCount = this->getSampleCount();
271 353  
272   - if(cycleCounter == startCycle) {
273   - // Buffer refilled completely since start of sampling, enable the trigger now
274   - errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
275   - if(errorCode < 0) {
276   - if(errorCode == LIBUSB_ERROR_NO_DEVICE)
277   - captureState = LIBUSB_ERROR_NO_DEVICE;
278   - break;
  354 + if(samplingStarted && lastTriggerMode == this->settings.trigger.mode) {
  355 + ++cycleCounter;
  356 +
  357 + if(cycleCounter == startCycle && this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] != UINT_MAX) {
  358 + // Buffer refilled completely since start of sampling, enable the trigger now
  359 + errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]);
  360 + if(errorCode < 0) {
  361 + if(errorCode == LIBUSB_ERROR_NO_DEVICE)
  362 + captureState = LIBUSB_ERROR_NO_DEVICE;
  363 + break;
  364 + }
  365 +#ifdef DEBUG
  366 + Helper::timestampDebug("Enabling trigger");
  367 +#endif
279 368 }
  369 + else if(cycleCounter >= 8 + startCycle && this->settings.trigger.mode == Dso::TRIGGERMODE_AUTO) {
  370 + // Force triggering
  371 + errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
  372 + if(errorCode < 0) {
  373 + if(errorCode == LIBUSB_ERROR_NO_DEVICE)
  374 + captureState = LIBUSB_ERROR_NO_DEVICE;
  375 + break;
  376 + }
280 377 #ifdef DEBUG
281   - qDebug("Enabling trigger");
  378 + Helper::timestampDebug("Forcing trigger");
282 379 #endif
  380 + }
  381 +
  382 + if(cycleCounter < 20 || cycleCounter < 4000 / cycleTime)
  383 + break;
283 384 }
284   - else if(cycleCounter >= 8 + startCycle && this->settings.trigger.mode == Dso::TRIGGERMODE_AUTO) {
285   - // Force triggering
286   - errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]);
  385 +
  386 + // Start capturing
  387 + errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
  388 + if(errorCode < 0) {
287 389 if(errorCode == LIBUSB_ERROR_NO_DEVICE)
288 390 captureState = LIBUSB_ERROR_NO_DEVICE;
  391 + break;
  392 + }
289 393 #ifdef DEBUG
290   - qDebug("Forcing trigger");
  394 + Helper::timestampDebug("Starting to capture");
291 395 #endif
292   - }
293 396  
294   - if(cycleCounter < 20 || cycleCounter < 4000 / cycleTime)
295   - break;
296   - }
297   -
298   - // Start capturing
299   - errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]);
300   - if(errorCode < 0) {
301   - if(errorCode == LIBUSB_ERROR_NO_DEVICE)
302   - captureState = LIBUSB_ERROR_NO_DEVICE;
  397 + samplingStarted = true;
  398 + cycleCounter = 0;
  399 + startCycle = this->settings.trigger.position * 1000 / cycleTime + 1;
  400 + lastTriggerMode = this->settings.trigger.mode;
303 401 break;
304   - }
305   -#ifdef DEBUG
306   - qDebug("Starting to capture");
307   -#endif
308 402  
309   - samplingStarted = true;
310   - cycleCounter = 0;
311   - startCycle = this->settings.trigger.position * 1000 / cycleTime + 1;
312   - lastTriggerMode = this->settings.trigger.mode;
313   - break;
314   -
315   - case CAPTURE_SAMPLING:
316   - break;
317   - default:
318   - break;
  403 + case CAPTURE_SAMPLING:
  404 + break;
  405 + default:
  406 + break;
  407 + }
319 408 }
320 409 }
321 410  
... ... @@ -417,20 +506,14 @@ namespace Hantek {
417 506  
418 507 // Clear unused channels
419 508 for(int channelCounter = 0; channelCounter < HANTEK_CHANNELS; ++channelCounter)
420   - if(channelCounter != channel && this->samples[channelCounter]) {
  509 + if(channelCounter != channel) {
421 510  
422   - delete this->samples[channelCounter];
423   - this->samples[channelCounter] = 0;
  511 + this->samples[channelCounter].clear();
424 512 }
425 513  
426 514 if(channel < HANTEK_CHANNELS) {
427   - // Reallocate memory for samples if the sample count has changed
428   - if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) {
429   - if(this->samples[channel])
430   - delete this->samples[channel];
431   - this->samples[channel] = new double[sampleCount];
432   - this->samplesSize[channel] = sampleCount;
433   - }
  515 + // Resize sample vector
  516 + this->samples[channel].resize(sampleCount);
434 517  
435 518 // Convert data from the oscilloscope and write it into the sample buffer
436 519 unsigned int bufferPosition = this->settings.trigger.point * 2;
... ... @@ -464,13 +547,8 @@ namespace Hantek {
464 547 sampleCount = totalSampleCount / HANTEK_CHANNELS;
465 548 for(int channel = 0; channel < HANTEK_CHANNELS; ++channel) {
466 549 if(this->settings.voltage[channel].used) {
467   - // Reallocate memory for samples if the sample count has changed
468   - if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) {
469   - if(this->samples[channel])
470   - delete this->samples[channel];
471   - this->samples[channel] = new double[sampleCount];
472   - this->samplesSize[channel] = sampleCount;
473   - }
  550 + // Resize sample vector
  551 + this->samples[channel].resize(sampleCount);
474 552  
475 553 // Convert data from the oscilloscope and write it into the sample buffer
476 554 unsigned int bufferPosition = this->settings.trigger.point * 2;
... ... @@ -497,17 +575,20 @@ namespace Hantek {
497 575 }
498 576 }
499 577 }
500   - else if(this->samples[channel]) {
  578 + else {
501 579 // Clear unused channels
502   - delete this->samples[channel];
503   - this->samples[channel] = 0;
504   - this->samplesSize[channel] = 0;
  580 + this->samples[channel].clear();
505 581 }
506 582 }
507 583 }
508 584  
509 585 this->samplesMutex.unlock();
510   - emit samplesAvailable(&(this->samples), &(this->samplesSize), this->settings.samplerate.current, &(this->samplesMutex));
  586 +#ifdef DEBUG
  587 + static unsigned int id = 0;
  588 + ++id;
  589 + Helper::timestampDebug(QString("Received packet %1").arg(id));
  590 +#endif
  591 + emit samplesAvailable(&(this->samples), this->settings.samplerate.current, this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] == UINT_MAX, &(this->samplesMutex));
511 592 }
512 593  
513 594 return errorCode;
... ... @@ -671,6 +752,14 @@ namespace Hantek {
671 752 return 0;
672 753 }
673 754  
  755 + // Check if the divider has changed and adapt samplerate limits accordingly
  756 + if(this->specification.bufferDividers[index] != this->specification.bufferDividers[this->settings.recordLengthId]) {
  757 + this->updateSamplerateLimits();
  758 +
  759 + // Samplerate dividers changed, recalculate it
  760 + this->restoreTargets();
  761 + }
  762 +
674 763 this->settings.recordLengthId = index;
675 764  
676 765 return this->settings.samplerate.limits->recordLengths[index];
... ... @@ -777,9 +866,9 @@ namespace Hantek {
777 866  
778 867 this->settings.samplerate.downsampler = downsampler;
779 868 if(downsampler)
780   - this->settings.samplerate.current = this->settings.samplerate.limits->base / downsampler;
  869 + this->settings.samplerate.current = this->settings.samplerate.limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / downsampler;
781 870 else
782   - this->settings.samplerate.current = this->settings.samplerate.limits->max;
  871 + this->settings.samplerate.current = this->settings.samplerate.limits->max / this->specification.bufferDividers[this->settings.recordLengthId];
783 872  
784 873 // Update dependencies
785 874 this->setPretriggerPosition(this->settings.trigger.position);
... ... @@ -791,15 +880,14 @@ namespace Hantek {
791 880 }
792 881  
793 882 // Check for Roll mode
794   - if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] != UINT_MAX) {
  883 + if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] != UINT_MAX)
795 884 emit recordTimeChanged((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current);
796   - emit samplerateChanged(this->settings.samplerate.current);
797   - }
  885 + emit samplerateChanged(this->settings.samplerate.current);
798 886  
799 887 return downsampler;
800 888 }
801 889  
802   - /// \brief Try to connect to the oscilloscope.
  890 + /// \brief Restore the samplerate/timebase targets after divider updates.
803 891 void Control::restoreTargets() {
804 892 if(this->settings.samplerate.target.samplerateSet)
805 893 this->setSamplerate();
... ... @@ -807,6 +895,13 @@ namespace Hantek {
807 895 this->setRecordTime();
808 896 }
809 897  
  898 + /// \brief Update the minimum and maximum supported samplerate.
  899 + void Control::updateSamplerateLimits() {
  900 + // Works only if the minimum samplerate for normal mode is lower than for fast rate mode, which is the case for all models
  901 + ControlSamplerateLimits *limits = (this->settings.usedChannels <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single;
  902 + emit samplerateLimitsChanged((double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler / this->specification.bufferDividers[this->settings.recordLengthId], limits->max / this->specification.bufferDividers[this->settings.recordLengthId]);
  903 + }
  904 +
810 905 /// \brief Try to connect to the oscilloscope.
811 906 void Control::connectDevice() {
812 907 int errorCode;
... ... @@ -1023,7 +1118,7 @@ namespace Hantek {
1023 1118 /// \param index The record length index that should be set.
1024 1119 /// \return The record length that has been set, 0 on error.
1025 1120 unsigned int Control::setRecordLength(unsigned int index) {
1026   - if(!this->device->isConnected())
  1121 + if(!this->device->isConnected())
1027 1122 return 0;
1028 1123  
1029 1124 if(!this->updateRecordLength(index))
... ... @@ -1052,7 +1147,7 @@ namespace Hantek {
1052 1147 }
1053 1148  
1054 1149 // When possible, enable fast rate if it is required to reach the requested samplerate
1055   - bool fastRate = (this->settings.usedChannels <= 1) && (samplerate > this->specification.samplerate.single.max);
  1150 + bool fastRate = (this->settings.usedChannels <= 1) && (samplerate > this->specification.samplerate.single.max / this->specification.bufferDividers[this->settings.recordLengthId]);
1056 1151  
1057 1152 // What is the nearest, at least as high samplerate the scope can provide?
1058 1153 unsigned int downsampler = 0;
... ... @@ -1085,7 +1180,7 @@ namespace Hantek {
1085 1180 double maxSamplerate = (double) this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] / duration;
1086 1181  
1087 1182 // When possible, enable fast rate if the record time can't be set that low to improve resolution
1088   - bool fastRate = (this->settings.usedChannels <= 1) && (maxSamplerate >= this->specification.samplerate.multi.base);
  1183 + bool fastRate = (this->settings.usedChannels <= 1) && (maxSamplerate >= this->specification.samplerate.multi.base / this->specification.bufferDividers[this->settings.recordLengthId]);
1089 1184  
1090 1185 // What is the nearest, at most as high samplerate the scope can provide?
1091 1186 unsigned int downsampler = 0;
... ... @@ -1162,14 +1257,8 @@ namespace Hantek {
1162 1257 bool fastRateChanged = (this->settings.usedChannels <= 1) != (channelCount <= 1);
1163 1258 this->settings.usedChannels = channelCount;
1164 1259  
1165   - if(fastRateChanged) {
1166   - // Works only if the minimum samplerate for normal mode is lower than for fast rate mode, which is the case for all models
1167   - ControlSamplerateLimits *limits = (channelCount <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single;
1168   - emit samplerateLimitsChanged((double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler, limits->max);
1169   -
1170   - // Samplerate differs for fast rate mode, recalculate it
1171   - this->restoreTargets();
1172   - }
  1260 + if(fastRateChanged)
  1261 + this->updateSamplerateLimits();
1173 1262  
1174 1263 return Dso::ERROR_NONE;
1175 1264 }
... ... @@ -1412,6 +1501,8 @@ namespace Hantek {
1412 1501  
1413 1502 // All trigger positions are measured in samples
1414 1503 unsigned int positionSamples = position * this->settings.samplerate.current;
  1504 + unsigned int recordLength = this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId];
  1505 + bool rollMode = recordLength == UINT_MAX;
1415 1506 // Fast rate mode uses both channels
1416 1507 if(this->settings.samplerate.limits == &this->specification.samplerate.multi)
1417 1508 positionSamples /= HANTEK_CHANNELS;
... ... @@ -1419,7 +1510,7 @@ namespace Hantek {
1419 1510 switch(this->specification.command.bulk.setPretrigger) {
1420 1511 case BULK_SETTRIGGERANDSAMPLERATE: {
1421 1512 // Calculate the position value (Start point depending on record length)
1422   - unsigned int position = 0x7ffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
  1513 + unsigned int position = rollMode ? 0x1 : 0x7ffff - recordLength + positionSamples;
1423 1514  
1424 1515 // SetTriggerAndSamplerate bulk command for trigger position
1425 1516 static_cast<BulkSetTriggerAndSamplerate *>(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setTriggerPosition(position);
... ... @@ -1429,8 +1520,8 @@ namespace Hantek {
1429 1520 }
1430 1521 case BULK_FSETBUFFER: {
1431 1522 // Calculate the position values (Inverse, maximum is 0x7ffff)
1432   - unsigned int positionPre = 0x7fffful - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
1433   - unsigned int positionPost = 0x7fffful - positionSamples;
  1523 + unsigned int positionPre = 0x7ffff - recordLength + positionSamples;
  1524 + unsigned int positionPost = 0x7ffff - positionSamples;
1434 1525  
1435 1526 // SetBuffer2250 bulk command for trigger position
1436 1527 BulkSetBuffer2250 *commandSetBuffer2250 = static_cast<BulkSetBuffer2250 *>(this->command[BULK_FSETBUFFER]);
... ... @@ -1442,7 +1533,7 @@ namespace Hantek {
1442 1533 }
1443 1534 case BULK_ESETTRIGGERORSAMPLERATE: {
1444 1535 // Calculate the position values (Inverse, maximum is 0xffff)
1445   - unsigned short int positionPre = 0xffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples;
  1536 + unsigned short int positionPre = 0xffff - recordLength + positionSamples;
1446 1537 unsigned short int positionPost = 0xffff - positionSamples;
1447 1538  
1448 1539 // SetBuffer5200 bulk command for trigger position
... ...
openhantek/src/hantek/control.h
... ... @@ -53,6 +53,17 @@ namespace Hantek {
53 53 };
54 54  
55 55 //////////////////////////////////////////////////////////////////////////////
  56 + /// \enum RollState hantek/types.h
  57 + /// \brief The states of the roll cycle (Since capture state isn't valid).
  58 + enum RollState {
  59 + ROLL_STARTSAMPLING = 0, ///< Start sampling
  60 + ROLL_ENABLETRIGGER = 1, ///< Enable triggering
  61 + ROLL_FORCETRIGGER = 2, ///< Force triggering
  62 + ROLL_GETDATA = 3, ///< Request sample data
  63 + ROLL_COUNT
  64 + };
  65 +
  66 + //////////////////////////////////////////////////////////////////////////////
56 67 /// \struct ControlSpecificationCommandsBulk hantek/control.h
57 68 /// \brief Stores the bulk command codes used for this device.
58 69 struct ControlSpecificationCommandsBulk {
... ... @@ -208,6 +219,7 @@ namespace Hantek {
208 219 unsigned int updateRecordLength(unsigned int size);
209 220 unsigned int updateSamplerate(unsigned int downsampler, bool fastRate);
210 221 void restoreTargets();
  222 + void updateSamplerateLimits();
211 223  
212 224 // Communication with device
213 225 Device *device; ///< The USB device for the oscilloscope
... ... @@ -223,8 +235,7 @@ namespace Hantek {
223 235 ControlSettings settings; ///< The current settings of the device
224 236  
225 237 // Results
226   - QList<double *> samples; ///< Sample data arrays
227   - QList<unsigned int> samplesSize; ///< Number of samples data array
  238 + std::vector<std::vector<double> > samples; ///< Sample data vectors sent to the data analyzer
228 239 unsigned int previousSampleCount; ///< The expected total number of samples at the last check before sampling started
229 240 QMutex samplesMutex; ///< Mutex for the sample data
230 241  
... ...
openhantek/src/helper.h
... ... @@ -30,6 +30,7 @@
30 30 #include <cerrno>
31 31  
32 32 #include <QString>
  33 +#include <QTime>
33 34  
34 35  
35 36 #if LIBUSB_VERSION == 0
... ... @@ -71,6 +72,13 @@ namespace Helper {
71 72 #ifdef DEBUG
72 73 QString hexDump(unsigned char *data, unsigned int length);
73 74 unsigned int hexParse(const QString dump, unsigned char *data, unsigned int length);
  75 + inline void timestampDebug(QString text);
  76 +
  77 + /// \brief Print debug information with timestamp.
  78 + /// \param text Text that will be output via qDebug.
  79 + inline void timestampDebug(QString text) {
  80 + qDebug("%s: %s", QTime::currentTime().toString("hh:mm:ss.zzz").toAscii().constData(), text.toAscii().constData());
  81 + }
74 82 #endif
75 83  
76 84 //////////////////////////////////////////////////////////////////////////////
... ...
openhantek/src/openhantek.cpp
... ... @@ -276,7 +276,7 @@ void OpenHantekMainWindow::connectSignals() {
276 276 connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings()));
277 277 //connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped()));
278 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 int> *, double, QMutex *)), this->dataAnalyzer, SLOT(analyze(const QList<double *> *, const QList<unsigned int> *, double, QMutex *)));
  279 + connect(this->dsoControl, SIGNAL(samplesAvailable(const std::vector<std::vector<double> > *, double, bool, QMutex *)), this->dataAnalyzer, SLOT(analyze(const std::vector<std::vector<double> > *, double, bool, QMutex *)));
280 280  
281 281 // Connect signals to DSO controller and widget
282 282 connect(this->horizontalDock, SIGNAL(samplerateChanged(double)), this, SLOT(samplerateSelected()));
... ... @@ -334,8 +334,10 @@ void OpenHantekMainWindow::initializeDevice() {
334 334 this->timebaseSelected();
335 335 if(this->dsoControl->getAvailableRecordLengths()->isEmpty())
336 336 this->dsoControl->setRecordLength(this->settings->scope.horizontal.recordLength);
337   - else
338   - this->dsoControl->setRecordLength(this->dsoControl->getAvailableRecordLengths()->indexOf(this->settings->scope.horizontal.recordLength));
  337 + else {
  338 + int index = this->dsoControl->getAvailableRecordLengths()->indexOf(this->settings->scope.horizontal.recordLength);
  339 + this->dsoControl->setRecordLength(index < 0 ? 1 : index);
  340 + }
339 341 this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode);
340 342 this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME);
341 343 this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope);
... ... @@ -610,7 +612,7 @@ void OpenHantekMainWindow::updateSettings() {
610 612 /// \brief The oscilloscope changed the record time.
611 613 /// \param duration The new record time duration in seconds.
612 614 void OpenHantekMainWindow::recordTimeChanged(double duration) {
613   - if(this->settings->scope.horizontal.samplerateSet) {
  615 + if(this->settings->scope.horizontal.samplerateSet && this->settings->scope.horizontal.recordLength != UINT_MAX) {
614 616 // The samplerate was set, let's adapt the timebase accordingly
615 617 this->settings->scope.horizontal.timebase = duration / DIVS_TIME;
616 618 this->horizontalDock->setTimebase(this->settings->scope.horizontal.timebase);
... ... @@ -625,7 +627,7 @@ void OpenHantekMainWindow::recordTimeChanged(double duration) {
625 627 /// \brief The oscilloscope changed the samplerate.
626 628 /// \param samplerate The new samplerate in samples per second.
627 629 void OpenHantekMainWindow::samplerateChanged(double samplerate) {
628   - if(!this->settings->scope.horizontal.samplerateSet) {
  630 + if(!this->settings->scope.horizontal.samplerateSet && this->settings->scope.horizontal.recordLength != UINT_MAX) {
629 631 // The timebase was set, let's adapt the samplerate accordingly
630 632 this->settings->scope.horizontal.samplerate = samplerate;
631 633 this->horizontalDock->setSamplerate(samplerate);
... ...