diff --git a/openhantek/ChangeLog b/openhantek/ChangeLog index 9df95fa..171f309 100644 --- a/openhantek/ChangeLog +++ b/openhantek/ChangeLog @@ -203,3 +203,8 @@ 2012-12-04 Oliver Haag * Workaround for stacked QGLWidget on Mac OS X * Bugfix: Check for connected scope on setSamplerate/setRecordTime + +2013-03-12 Oliver Haag +* Use std::vector instead of QList +* Experimental Roll-mode support +* QThread::msleep is too unprecise, causing problems in Roll-mode diff --git a/openhantek/src/dataanalyzer.cpp b/openhantek/src/dataanalyzer.cpp index e0a4cc0..11f76a6 100644 --- a/openhantek/src/dataanalyzer.cpp +++ b/openhantek/src/dataanalyzer.cpp @@ -38,7 +38,22 @@ //////////////////////////////////////////////////////////////////////////////// -// class HorizontalDock +// struct SampleValues +/// \brief Initializes the members to their default values. +SampleValues::SampleValues() { + this->interval = 0.0; +} + +//////////////////////////////////////////////////////////////////////////////// +// struct AnalyzedData +/// \brief Initializes the members to their default values. +AnalyzedData::AnalyzedData() { + this->amplitude = 0.0; + this->frequency = 0.0; +} + +//////////////////////////////////////////////////////////////////////////////// +// class DataAnalyzer /// \brief Initializes the buffers and other variables. /// \param settings The settings that should be used. /// \param parent The parent widget. @@ -59,24 +74,16 @@ DataAnalyzer::DataAnalyzer(DsoSettings *settings, QObject *parent) : QThread(par /// \brief Deallocates the buffers. DataAnalyzer::~DataAnalyzer() { - for(int channel = 0; channel < this->analyzedData.count(); ++channel) { - AnalyzedData *channelData = this->analyzedData[channel]; - - if(channelData->samples.voltage.sample) - delete[] channelData->samples.voltage.sample; - if(channelData->samples.spectrum.sample) - delete[] channelData->samples.spectrum.sample; - } } /// \brief Returns the analyzed data. /// \param channel Channel, whose data should be returned. /// \return Analyzed data as AnalyzedData struct. -const AnalyzedData *DataAnalyzer::data(int channel) const { - if(channel < 0 || channel >= this->analyzedData.count()) +AnalyzedData const *DataAnalyzer::data(unsigned int channel) const { + if(channel >= this->analyzedData.size()) return 0; - return this->analyzedData[channel]; + return &this->analyzedData[channel]; } /// \brief Returns the sample count of the analyzed data. @@ -96,96 +103,79 @@ void DataAnalyzer::run() { this->analyzedDataMutex->lock(); unsigned int maxSamples = 0; - unsigned int channelCount = (unsigned int) this->settings->scope.voltage.count(); + unsigned int channelCount = (unsigned int) this->settings->scope.voltage.size(); // Adapt the number of channels for analyzed data - for(unsigned int channel = this->analyzedData.count(); channel < channelCount; ++channel) { - AnalyzedData *channelData = new AnalyzedData; - channelData->samples.voltage.count = 0; - channelData->samples.voltage.interval = 0; - channelData->samples.voltage.sample = 0; - channelData->samples.spectrum.count = 0; - channelData->samples.spectrum.interval = 0; - channelData->samples.spectrum.sample = 0; - channelData->amplitude = 0; - channelData->frequency = 0; - this->analyzedData.append(channelData); - } - for(unsigned int channel = this->analyzedData.count(); channel > channelCount; --channel) { - AnalyzedData *channelData = this->analyzedData.last(); - if(channelData->samples.voltage.sample) - delete[] channelData->samples.voltage.sample; - if(channelData->samples.spectrum.sample) - delete[] channelData->samples.spectrum.sample; - this->analyzedData.removeLast(); - } + this->analyzedData.resize(channelCount); for(unsigned int channel = 0; channel < channelCount; ++channel) { - AnalyzedData *channelData = this->analyzedData[channel]; + AnalyzedData *const channelData = &this->analyzedData[channel]; if( // Check... ( // ...if we got data for this channel... channel < this->settings->scope.physicalChannels && - channel < (unsigned int) this->waitingData.count() && - this->waitingData[channel]) || + channel < (unsigned int) this->waitingData->size() && + !this->waitingData->at(channel).empty()) || ( // ...or if it's a math channel that can be calculated channel >= this->settings->scope.physicalChannels && (this->settings->scope.voltage[channel].used || this->settings->scope.spectrum[channel].used) && - this->analyzedData.count() >= 2 && - this->analyzedData[0]->samples.voltage.sample && - this->analyzedData[1]->samples.voltage.sample + this->analyzedData.size() >= 2 && + !this->analyzedData[0].samples.voltage.sample.empty() && + !this->analyzedData[1].samples.voltage.sample.empty() ) ) { // Set sampling interval - channelData->samples.voltage.interval = 1.0 / this->waitingDataSamplerate; + const double interval = 1.0 / this->waitingDataSamplerate; + if(interval != channelData->samples.voltage.interval) { + channelData->samples.voltage.interval = interval; + if(this->waitingDataAppend) // Clear roll buffer if the samplerate changed + channelData->samples.voltage.sample.clear(); + } + unsigned int size; if(channel < this->settings->scope.physicalChannels) { - size = this->waitingDataSize[channel]; + size = this->waitingData->at(channel).size(); + if(this->waitingDataAppend) + size += channelData->samples.voltage.sample.size(); if(size > maxSamples) maxSamples = size; } else size = maxSamples; - // Reallocate memory for samples if the sample count has changed - if(channelData->samples.voltage.count != size) { - channelData->samples.voltage.count = size; - if(channelData->samples.voltage.sample) - delete[] channelData->samples.voltage.sample; - channelData->samples.voltage.sample = new double[size]; - } // Physical channels if(channel < this->settings->scope.physicalChannels) { // Copy the buffer of the oscilloscope into the sample buffer - if(channel < (unsigned int) this->waitingData.count()) - for(unsigned int position = 0; position < this->waitingDataSize[channel]; ++position) - channelData->samples.voltage.sample[position] = this->waitingData[channel][position]; + if(this->waitingDataAppend) + channelData->samples.voltage.sample.insert(channelData->samples.voltage.sample.end(), this->waitingData->at(channel).begin(), this->waitingData->at(channel).end()); + else + channelData->samples.voltage.sample = this->waitingData->at(channel); } // Math channel else { + // Resize the sample vector + channelData->samples.voltage.sample.resize(size); // Set sampling interval - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.interval = this->analyzedData[0]->samples.voltage.interval; + this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.interval = this->analyzedData[0].samples.voltage.interval; - // Reallocate memory for samples if the sample count has changed - if(this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count != this->analyzedData[0]->samples.voltage.count) { - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count = this->analyzedData[0]->samples.voltage.count; - if(this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample) - delete[] this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample; - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample = new double[this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count]; - } + // Resize the sample vector + 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())); // Calculate values and write them into the sample buffer - for(unsigned int realPosition = 0; realPosition < this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.count; ++realPosition) { + std::vector::const_iterator ch1Iterator = this->analyzedData[0].samples.voltage.sample.begin(); + std::vector::const_iterator ch2Iterator = this->analyzedData[1].samples.voltage.sample.begin(); + std::vector &resultData = this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.sample; + for(std::vector::iterator resultIterator = resultData.begin(); resultIterator != resultData.end(); ++resultIterator) { switch(this->settings->scope.voltage[this->settings->scope.physicalChannels].misc) { case Dso::MATHMODE_1ADD2: - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample[realPosition] = this->analyzedData[0]->samples.voltage.sample[realPosition] + this->analyzedData[1]->samples.voltage.sample[realPosition]; + *(resultIterator++) = *(ch1Iterator++) + *(ch2Iterator++); break; case Dso::MATHMODE_1SUB2: - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample[realPosition] = this->analyzedData[0]->samples.voltage.sample[realPosition] - this->analyzedData[1]->samples.voltage.sample[realPosition]; + *(resultIterator++) = *(ch1Iterator++) - *(ch2Iterator++); break; case Dso::MATHMODE_2SUB1: - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.sample[realPosition] = this->analyzedData[1]->samples.voltage.sample[realPosition] - this->analyzedData[0]->samples.voltage.sample[realPosition]; + *(resultIterator++) = *(ch2Iterator++) - *(ch1Iterator++); break; } } @@ -193,12 +183,8 @@ void DataAnalyzer::run() { } else { // Clear unused channels - channelData->samples.voltage.count = 0; - this->analyzedData[this->settings->scope.physicalChannels]->samples.voltage.interval = 0; - if(channelData->samples.voltage.sample) { - delete[] channelData->samples.voltage.sample; - channelData->samples.voltage.sample = 0; - } + channelData->samples.voltage.sample.clear(); + this->analyzedData[this->settings->scope.physicalChannels].samples.voltage.interval = 0; } } @@ -209,14 +195,15 @@ void DataAnalyzer::run() { // Calculate frequencies, peak-to-peak voltages and spectrums - for(int channel = 0; channel < this->analyzedData.count(); ++channel) { - AnalyzedData *channelData = this->analyzedData[channel]; + for(unsigned int channel = 0; channel < this->analyzedData.size(); ++channel) { + AnalyzedData *const channelData = &this->analyzedData[channel]; - if(channelData->samples.voltage.sample) { + if(!channelData->samples.voltage.sample.empty()) { // Calculate new window - if(this->lastWindow != this->settings->scope.spectrumWindow || this->lastRecordLength != channelData->samples.voltage.count) { - if(this->lastRecordLength != channelData->samples.voltage.count) { - this->lastRecordLength = channelData->samples.voltage.count; + unsigned int sampleCount = channelData->samples.voltage.sample.size(); + if(this->lastWindow != this->settings->scope.spectrumWindow || this->lastRecordLength != sampleCount) { + if(this->lastRecordLength != sampleCount) { + this->lastRecordLength = sampleCount; if(this->window) fftw_free(this->window); @@ -303,28 +290,23 @@ void DataAnalyzer::run() { } // Set sampling interval - channelData->samples.spectrum.interval = 1.0 / channelData->samples.voltage.interval / channelData->samples.voltage.count; + channelData->samples.spectrum.interval = 1.0 / channelData->samples.voltage.interval / sampleCount; // Number of real/complex samples - unsigned int dftLength = channelData->samples.voltage.count / 2; + unsigned int dftLength = sampleCount / 2; // Reallocate memory for samples if the sample count has changed - if(channelData->samples.spectrum.count != dftLength) { - channelData->samples.spectrum.count = dftLength; - if(channelData->samples.spectrum.sample) - delete[] channelData->samples.spectrum.sample; - channelData->samples.spectrum.sample = new double[channelData->samples.voltage.count]; - } + channelData->samples.spectrum.sample.resize(sampleCount); // Create sample buffer and apply window - double *windowedValues = new double[channelData->samples.voltage.count]; - for(unsigned int position = 0; position < channelData->samples.voltage.count; ++position) + double *windowedValues = new double[sampleCount]; + for(unsigned int position = 0; position < sampleCount; ++position) windowedValues[position] = this->window[position] * channelData->samples.voltage.sample[position]; // Do discrete real to half-complex transformation /// \todo Check if record length is multiple of 2 /// \todo Reuse plan and use FFTW_MEASURE to get fastest algorithm - fftw_plan fftPlan = fftw_plan_r2r_1d(channelData->samples.voltage.count, windowedValues, channelData->samples.spectrum.sample, FFTW_R2HC, FFTW_ESTIMATE); + fftw_plan fftPlan = fftw_plan_r2r_1d(sampleCount, windowedValues, &channelData->samples.spectrum.sample.front(), FFTW_R2HC, FFTW_ESTIMATE); fftw_execute(fftPlan); fftw_destroy_plan(fftPlan); @@ -336,15 +318,15 @@ void DataAnalyzer::run() { double correctionFactor = 1.0 / dftLength / dftLength; conjugateComplex[0] = (channelData->samples.spectrum.sample[0] * channelData->samples.spectrum.sample[0]) * correctionFactor; for(position = 1; position < dftLength; ++position) - 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; + 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; // Complex values, all zero for autocorrelation conjugateComplex[dftLength] = (channelData->samples.spectrum.sample[dftLength] * channelData->samples.spectrum.sample[dftLength]) * correctionFactor; - for(++position; position < channelData->samples.voltage.count; ++position) + for(++position; position < sampleCount; ++position) conjugateComplex[position] = 0; // Do half-complex to real inverse transformation - double *correlation = new double[channelData->samples.voltage.count]; - fftPlan = fftw_plan_r2r_1d(channelData->samples.voltage.count, conjugateComplex, correlation, FFTW_HC2R, FFTW_ESTIMATE); + double *correlation = new double[sampleCount]; + fftPlan = fftw_plan_r2r_1d(sampleCount, conjugateComplex, correlation, FFTW_HC2R, FFTW_ESTIMATE); fftw_execute(fftPlan); fftw_destroy_plan(fftPlan); delete[] conjugateComplex; @@ -353,7 +335,7 @@ void DataAnalyzer::run() { double minimalVoltage, maximalVoltage; minimalVoltage = maximalVoltage = channelData->samples.voltage.sample[0]; - for(unsigned int position = 1; position < channelData->samples.voltage.count; ++position) { + for(unsigned int position = 1; position < sampleCount; ++position) { if(channelData->samples.voltage.sample[position] < minimalVoltage) minimalVoltage = channelData->samples.voltage.sample[position]; else if(channelData->samples.voltage.sample[position] > maximalVoltage) @@ -367,7 +349,7 @@ void DataAnalyzer::run() { double peakCorrelation = 0; unsigned int peakPosition = 0; - for(unsigned int position = 1; position < channelData->samples.voltage.count / 2; ++position) { + for(unsigned int position = 1; position < sampleCount / 2; ++position) { if(correlation[position] > peakCorrelation && correlation[position] > minimumCorrelation * 2) { peakCorrelation = correlation[position]; peakPosition = position; @@ -388,21 +370,21 @@ void DataAnalyzer::run() { // Convert values into dB (Relative to the reference level) double offset = 60 - this->settings->scope.spectrumReference - 20 * log10(dftLength); double offsetLimit = this->settings->scope.spectrumLimit - this->settings->scope.spectrumReference; - for(unsigned int position = 0; position < channelData->samples.spectrum.count; ++position) { - channelData->samples.spectrum.sample[position] = 20 * log10(fabs(channelData->samples.spectrum.sample[position])) + offset; + for(std::vector::iterator spectrumIterator = channelData->samples.spectrum.sample.begin(); spectrumIterator != channelData->samples.spectrum.sample.end(); ++spectrumIterator) { + double value = 20 * log10(fabs(channelData->samples.spectrum.sample[position])) + offset; // Check if this value has to be limited - if(offsetLimit > channelData->samples.spectrum.sample[position]) - channelData->samples.spectrum.sample[position] = offsetLimit; + if(offsetLimit > value) + value = offsetLimit; + + *spectrumIterator = value; } } } - else if(channelData->samples.spectrum.sample) { + else if(!channelData->samples.spectrum.sample.empty()) { // Clear unused channels - channelData->samples.spectrum.count = 0; channelData->samples.spectrum.interval = 0; - delete[] channelData->samples.spectrum.sample; - channelData->samples.spectrum.sample = 0; + channelData->samples.spectrum.sample.clear(); } } @@ -416,19 +398,27 @@ void DataAnalyzer::run() { /// \param data The data arrays with the input data. /// \param size The sizes of the data arrays. /// \param samplerate The samplerate for all input data. +/// \param append The data will be appended to the previously analyzed data (Roll mode). /// \param mutex The mutex for all input data. -void DataAnalyzer::analyze(const QList *data, const QList *size, double samplerate, QMutex *mutex) { +void DataAnalyzer::analyze(const std::vector > *data, double samplerate, bool append, QMutex *mutex) { // Previous analysis still running, drop the new data - if(this->isRunning()) + if(this->isRunning()) { +#ifdef DEBUG + Helper::timestampDebug("Analyzer overload, dropping packets!"); +#endif return; + } // The thread will analyze it, just save the pointers mutex->lock(); - this->waitingData.clear(); - this->waitingData.append(*data); - this->waitingDataSize.clear(); - this->waitingDataSize.append(*size); + this->waitingData = data; + this->waitingDataAppend = append; this->waitingDataMutex = mutex; this->waitingDataSamplerate = samplerate; this->start(); +#ifdef DEBUG + static unsigned long id = 0; + ++id; + Helper::timestampDebug(QString("Analyzed packet %1").arg(id)); +#endif } diff --git a/openhantek/src/dataanalyzer.h b/openhantek/src/dataanalyzer.h index 8d3d02f..e7e5be5 100644 --- a/openhantek/src/dataanalyzer.h +++ b/openhantek/src/dataanalyzer.h @@ -27,6 +27,8 @@ #define DATAANALYZER_H +#include + #include @@ -43,9 +45,10 @@ class QMutex; /// \struct SampleValues dataanalyzer.h /// \brief Struct for a array of sample values. struct SampleValues { - double *sample; ///< Pointer to the array holding the sampling data - unsigned int count; ///< Number of sample values + std::vector sample; ///< Vector holding the sampling data double interval; ///< The interval between two sample values + + SampleValues(); }; //////////////////////////////////////////////////////////////////////////////// @@ -61,8 +64,10 @@ struct SampleData { /// \brief Struct for the analyzed data. struct AnalyzedData { SampleData samples; ///< Voltage and spectrum values - double frequency; ///< The frequency of the signal double amplitude; ///< The amplitude of the signal + double frequency; ///< The frequency of the signal + + AnalyzedData(); }; //////////////////////////////////////////////////////////////////////////////// @@ -77,7 +82,7 @@ class DataAnalyzer : public QThread { DataAnalyzer(DsoSettings *settings, QObject *parent = 0); ~DataAnalyzer(); - const AnalyzedData *data(int channel) const; + const AnalyzedData *data(unsigned int channel) const; unsigned int sampleCount(); QMutex *mutex() const; @@ -86,7 +91,7 @@ class DataAnalyzer : public QThread { DsoSettings *settings; ///< The settings provided by the parent class - QList analyzedData; ///< The analyzed data for each channel + std::vector analyzedData; ///< The analyzed data for each channel QMutex *analyzedDataMutex; ///< A mutex for the analyzed data of all channels unsigned int lastRecordLength; ///< The record length of the previously analyzed data @@ -94,13 +99,13 @@ class DataAnalyzer : public QThread { Dso::WindowFunction lastWindow; ///< The previously used dft window function double *window; ///< The array for the dft window factors - QList waitingData; ///< Pointer to input data from device - QList waitingDataSize; ///< Number of input data samples + const std::vector > *waitingData; ///< Pointer to input data from device double waitingDataSamplerate; ///< The samplerate of the input data + bool waitingDataAppend; ///< true, if waiting data should be appended QMutex *waitingDataMutex; ///< A mutex for the input data public slots: - void analyze(const QList *data, const QList *size, double samplerate, QMutex *mutex); + void analyze(const std::vector > *data, double samplerate, bool append, QMutex *mutex); signals: void analyzed(unsigned long samples); ///< The data with that much samples has been analyzed diff --git a/openhantek/src/dsocontrol.h b/openhantek/src/dsocontrol.h index 6890bd8..ce50dcc 100644 --- a/openhantek/src/dsocontrol.h +++ b/openhantek/src/dsocontrol.h @@ -27,6 +27,8 @@ #define DSOCONTROL_H +#include + #include #include @@ -65,7 +67,7 @@ class DsoControl : public QThread { void samplingStarted(); ///< The oscilloscope started sampling/waiting for trigger void samplingStopped(); ///< The oscilloscope stopped sampling/waiting for trigger void statusMessage(const QString &message, int timeout); ///< Status message about the oscilloscope - void samplesAvailable(const QList *data, const QList *size, double samplerate, QMutex *mutex); ///< New sample data is available + void samplesAvailable(const std::vector > *data, double samplerate, bool append, QMutex *mutex); ///< New sample data is available void recordLengthChanged(unsigned long duration); ///< The record length has changed void recordTimeChanged(double duration); ///< The record time duration has changed diff --git a/openhantek/src/exporter.cpp b/openhantek/src/exporter.cpp index bc2ffca..2631f6d 100644 --- a/openhantek/src/exporter.cpp +++ b/openhantek/src/exporter.cpp @@ -231,7 +231,7 @@ bool Exporter::doExport() { centerOffset = DIVS_TIME / horizontalFactor / 2; } unsigned int firstPosition = qMax((int) (centerPosition - centerOffset), 0); - unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.voltage.count - 1); + unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.voltage.sample.size() - 1); // Draw graph QPointF *graph = new QPointF[lastPosition - firstPosition + 1]; @@ -262,7 +262,7 @@ bool Exporter::doExport() { centerOffset = DIVS_TIME / horizontalFactor / 2; } unsigned int firstPosition = qMax((int) (centerPosition - centerOffset), 0); - unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.spectrum.count - 1); + unsigned int lastPosition = qMin((int) (centerPosition + centerOffset), (int) this->dataAnalyzer->data(channel)->samples.spectrum.sample.size() - 1); // Draw graph QPointF *graph = new QPointF[lastPosition - firstPosition + 1]; @@ -382,7 +382,7 @@ bool Exporter::doExport() { csvStream << "\"" << this->settings->scope.voltage[channel].name << "\"," << this->dataAnalyzer->data(channel)->samples.voltage.interval; // And now all sample values in volts - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.count; ++position) + for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.sample.size(); ++position) csvStream << "," << this->dataAnalyzer->data(channel)->samples.voltage.sample[position]; // Finally a newline @@ -394,7 +394,7 @@ bool Exporter::doExport() { csvStream << "\"" << this->settings->scope.spectrum[channel].name << "\"," << this->dataAnalyzer->data(channel)->samples.spectrum.interval; // And now all magnitudes in dB - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.spectrum.count; ++position) + for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.spectrum.sample.size(); ++position) csvStream << "," << this->dataAnalyzer->data(channel)->samples.spectrum.sample[position]; // Finally a newline diff --git a/openhantek/src/glgenerator.cpp b/openhantek/src/glgenerator.cpp index 3c2fcea..980b001 100644 --- a/openhantek/src/glgenerator.cpp +++ b/openhantek/src/glgenerator.cpp @@ -33,44 +33,6 @@ //////////////////////////////////////////////////////////////////////////////// -// class GlArray -/// \brief Initializes the array. -GlArray::GlArray() { - this->data = 0; - this->size = 0; -} - -/// \brief Deletes the array. -GlArray::~GlArray() { - if(this->data) - delete this->data; -} - -/// \brief Get the size of the array. -/// \return Number of array elements. -unsigned int GlArray::getSize() { - return this->size; -} - -/// \brief Set the size of the array. -/// Previous array contents are lost. -/// \param size New number of array elements. -void GlArray::setSize(unsigned int size) { - if(this->size == size) - return; - - if(this->data) - delete[] this->data; - if(size) - this->data = new GLfloat[size]; - else - this->data = 0; - - this->size = size; -} - - -//////////////////////////////////////////////////////////////////////////////// // class GlGenerator /// \brief Initializes the scope widget. /// \param settings The target settings object. @@ -104,12 +66,8 @@ void GlGenerator::generateGraphs() { return; // Adapt the number of graphs - for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { - for(int channel = this->vaChannel[mode].count(); channel < this->settings->scope.voltage.count(); ++channel) - this->vaChannel[mode].append(QList()); - for(int channel = this->settings->scope.voltage.count(); channel < this->vaChannel[mode].count(); ++channel) - this->vaChannel[mode].removeLast(); - } + for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) + this->vaChannel[mode].resize(this->settings->scope.voltage.count()); // Set digital phosphor depth to one if we don't use it if(this->settings->view.digitalPhosphor) @@ -119,18 +77,12 @@ void GlGenerator::generateGraphs() { // Handle all digital phosphor related list manipulations for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { - for(int channel = 0; channel < this->vaChannel[mode].count(); ++channel) { - // Resize lists for vector array if the digital phosphor depth has changed - if(this->vaChannel[mode][channel].count() != this->digitalPhosphorDepth) - for(int index = this->vaChannel[mode][channel].count(); index < this->digitalPhosphorDepth; ++index) - this->vaChannel[mode][channel].append(new GlArray()); - for(int index = this->digitalPhosphorDepth; index < this->vaChannel[mode][channel].count(); ++index) { - delete this->vaChannel[mode][channel].last(); - this->vaChannel[mode][channel].removeLast(); - } - + for(unsigned int channel = 0; channel < this->vaChannel[mode].size(); ++channel) { // Move the last list element to the front - this->vaChannel[mode][channel].move(this->digitalPhosphorDepth -1, 0); + this->vaChannel[mode][channel].push_front(std::vector()); + + // Resize lists for vector array to fit the digital phosphor depth + this->vaChannel[mode][channel].resize(this->digitalPhosphorDepth); } } @@ -140,21 +92,22 @@ void GlGenerator::generateGraphs() { case Dso::GRAPHFORMAT_TY: // Add graphs for channels for(int mode = Dso::CHANNELMODE_VOLTAGE; mode < Dso::CHANNELMODE_COUNT; ++mode) { - for(int channel = 0; channel < this->settings->scope.voltage.count(); ++channel) { + for(int channel = 0; channel < this->settings->scope.voltage.size(); ++channel) { // Check if this channel is used and available at the data analyzer - 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) { + 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()) { // Check if the sample count has changed - unsigned int neededSize = ((mode == Dso::CHANNELMODE_VOLTAGE) ? this->dataAnalyzer->data(channel)->samples.voltage.count : this->dataAnalyzer->data(channel)->samples.spectrum.count) * 2; - for(int index = 0; index < this->digitalPhosphorDepth; ++index) { - if(this->vaChannel[mode][channel][index]->getSize() != neededSize) - this->vaChannel[mode][channel][index]->setSize(0); + unsigned int sampleCount = (mode == Dso::CHANNELMODE_VOLTAGE) ? this->dataAnalyzer->data(channel)->samples.voltage.sample.size() : this->dataAnalyzer->data(channel)->samples.spectrum.sample.size(); + unsigned int neededSize = sampleCount * 2; + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) { + if(this->vaChannel[mode][channel][index].size() != neededSize) + this->vaChannel[mode][channel][index].clear(); // Something was changed, drop old traces } - // Check if the array is allocated - if(!this->vaChannel[mode][channel].first()->data) - this->vaChannel[mode][channel].first()->setSize(neededSize); + // Set size directly to avoid reallocations + this->vaChannel[mode][channel].front().resize(neededSize); - GLfloat *vaNewChannel = this->vaChannel[mode][channel].first()->data; + // Iterator to data for direct access + std::vector::iterator glIterator = this->vaChannel[mode][channel].front().begin(); // What's the horizontal distance between sampling points? double horizontalFactor; @@ -164,64 +117,78 @@ void GlGenerator::generateGraphs() { horizontalFactor = this->dataAnalyzer->data(channel)->samples.spectrum.interval / this->settings->scope.horizontal.frequencybase; // Fill vector array - unsigned int arrayPosition = 0; if(mode == Dso::CHANNELMODE_VOLTAGE) { - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.count; ++position) { - vaNewChannel[arrayPosition++] = position * horizontalFactor - DIVS_TIME / 2; - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(channel)->samples.voltage.sample[position] / this->settings->scope.voltage[channel].gain + this->settings->scope.voltage[channel].offset; + std::vector::const_iterator dataIterator = this->dataAnalyzer->data(channel)->samples.voltage.sample.begin(); + const double gain = this->settings->scope.voltage[channel].gain; + const double offset = this->settings->scope.voltage[channel].offset; + + for(unsigned int position = 0; position < sampleCount; ++position) { + *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2; + *(glIterator++) = *(dataIterator++) / gain + offset; } } else { - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.spectrum.count; ++position) { - vaNewChannel[arrayPosition++] = position * horizontalFactor - DIVS_TIME / 2; - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(channel)->samples.spectrum.sample[position] / this->settings->scope.spectrum[channel].magnitude + this->settings->scope.spectrum[channel].offset; + std::vector::const_iterator dataIterator = this->dataAnalyzer->data(channel)->samples.spectrum.sample.begin(); + const double magnitude = this->settings->scope.spectrum[channel].magnitude; + const double offset = this->settings->scope.spectrum[channel].offset; + + for(unsigned int position = 0; position < sampleCount; ++position) { + *(glIterator++) = position * horizontalFactor - DIVS_TIME / 2; + *(glIterator++) = *(dataIterator++) / magnitude + offset; } } } else { // Delete all vector arrays - for(int index = 0; index < this->digitalPhosphorDepth; ++index) - this->vaChannel[mode][channel][index]->setSize(0); + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) + this->vaChannel[mode][channel][index].clear(); } } } break; case Dso::GRAPHFORMAT_XY: - for(int channel = 0; channel < this->settings->scope.voltage.count(); ++channel) { + for(int channel = 0; channel < this->settings->scope.voltage.size(); ++channel) { // For even channel numbers check if this channel is used and this and the following channel are available at the data analyzer - 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) { + 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()) { // Check if the sample count has changed - unsigned int neededSize = qMin(this->dataAnalyzer->data(channel)->samples.voltage.count, this->dataAnalyzer->data(channel + 1)->samples.voltage.count) * 2; - for(int index = 0; index < this->digitalPhosphorDepth; ++index) { - if(this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->getSize() != neededSize) - this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->setSize(0); + const unsigned int sampleCount = qMin(this->dataAnalyzer->data(channel)->samples.voltage.sample.size(), this->dataAnalyzer->data(channel + 1)->samples.voltage.sample.size()); + const unsigned int neededSize = sampleCount * 2; + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) { + if(this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].size() != neededSize) + this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].clear(); // Something was changed, drop old traces } - // Check if the array is allocated - if(!this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].first()->data) - this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].first()->setSize(neededSize); + // Set size directly to avoid reallocations + this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().resize(neededSize); - GLfloat *vaNewChannel = this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].first()->data; + // Iterator to data for direct access + std::vector::iterator glIterator = this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel].front().begin(); // Fill vector array - unsigned int arrayPosition = 0; unsigned int xChannel = channel; unsigned int yChannel = channel + 1; - for(unsigned int position = 0; position < this->dataAnalyzer->data(channel)->samples.voltage.count; ++position) { - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(xChannel)->samples.voltage.sample[position] / this->settings->scope.voltage[xChannel].gain + this->settings->scope.voltage[xChannel].offset; - vaNewChannel[arrayPosition++] = this->dataAnalyzer->data(yChannel)->samples.voltage.sample[position] / this->settings->scope.voltage[yChannel].gain + this->settings->scope.voltage[yChannel].offset; + std::vector::const_iterator xIterator = this->dataAnalyzer->data(xChannel)->samples.voltage.sample.begin(); + std::vector::const_iterator yIterator = this->dataAnalyzer->data(yChannel)->samples.voltage.sample.begin(); + const double xGain = this->settings->scope.voltage[xChannel].gain; + const double yGain = this->settings->scope.voltage[yChannel].gain; + const double xOffset = this->settings->scope.voltage[xChannel].offset; + const double yOffset = this->settings->scope.voltage[yChannel].offset; + + for(unsigned int position = 0; position < sampleCount; ++position) { + *(glIterator++) = *(xIterator++) / xGain + xOffset; + *(glIterator++) = *(yIterator++) / yGain + yOffset; } } else { // Delete all vector arrays - for(int index = 0; index < this->digitalPhosphorDepth; ++index) - this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->setSize(0); + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) + this->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].clear(); } // Delete all spectrum graphs - for(int index = 0; index < this->digitalPhosphorDepth; ++index) - this->vaChannel[Dso::CHANNELMODE_SPECTRUM][channel][index]->setSize(0); + for(unsigned int index = 0; index < this->digitalPhosphorDepth; ++index) + this->vaChannel[Dso::CHANNELMODE_SPECTRUM][channel][index].clear(); } break; @@ -237,20 +204,20 @@ void GlGenerator::generateGraphs() { /// \brief Create the needed OpenGL vertex arrays for the grid. void GlGenerator::generateGrid() { // Grid - 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); - int pointIndex = 0; + 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); + std::vector::iterator glIterator = this->vaGrid[0].begin(); // Draw vertical lines for(int div = 1; div < DIVS_TIME / 2; ++div) { for(int dot = 1; dot < DIVS_VOLTAGE / 2 * DIVS_SUB; ++dot) { float dotPosition = (float) dot / DIVS_SUB; - this->vaGrid[0].data[pointIndex++] = -div; - this->vaGrid[0].data[pointIndex++] = -dotPosition; - this->vaGrid[0].data[pointIndex++] = -div; - this->vaGrid[0].data[pointIndex++] = dotPosition; - this->vaGrid[0].data[pointIndex++] = div; - this->vaGrid[0].data[pointIndex++] = -dotPosition; - this->vaGrid[0].data[pointIndex++] = div; - this->vaGrid[0].data[pointIndex++] = dotPosition; + *(glIterator++) = -div; + *(glIterator++) = -dotPosition; + *(glIterator++) = -div; + *(glIterator++) = dotPosition; + *(glIterator++) = div; + *(glIterator++) = -dotPosition; + *(glIterator++) = div; + *(glIterator++) = dotPosition; } } // Draw horizontal lines @@ -259,63 +226,64 @@ void GlGenerator::generateGrid() { if(dot % DIVS_SUB == 0) continue; // Already done by vertical lines float dotPosition = (float) dot / DIVS_SUB; - this->vaGrid[0].data[pointIndex++] = -dotPosition; - this->vaGrid[0].data[pointIndex++] = -div; - this->vaGrid[0].data[pointIndex++] = dotPosition; - this->vaGrid[0].data[pointIndex++] = -div; - this->vaGrid[0].data[pointIndex++] = -dotPosition; - this->vaGrid[0].data[pointIndex++] = div; - this->vaGrid[0].data[pointIndex++] = dotPosition; - this->vaGrid[0].data[pointIndex++] = div; + *(glIterator++) = -dotPosition; + *(glIterator++) = -div; + *(glIterator++) = dotPosition; + *(glIterator++) = -div; + *(glIterator++) = -dotPosition; + *(glIterator++) = div; + *(glIterator++) = dotPosition; + *(glIterator++) = div; } } // Axes - this->vaGrid[1].setSize((2 + (DIVS_TIME * DIVS_SUB - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2)) * 4); - pointIndex = 0; + this->vaGrid[1].resize((2 + (DIVS_TIME * DIVS_SUB - 2) + (DIVS_VOLTAGE * DIVS_SUB - 2)) * 4); + glIterator = this->vaGrid[1].begin(); // Horizontal axis - this->vaGrid[1].data[pointIndex++] = -DIVS_TIME / 2; - this->vaGrid[1].data[pointIndex++] = 0; - this->vaGrid[1].data[pointIndex++] = DIVS_TIME / 2; - this->vaGrid[1].data[pointIndex++] = 0; + *(glIterator++) = -DIVS_TIME / 2; + *(glIterator++) = 0; + *(glIterator++) = DIVS_TIME / 2; + *(glIterator++) = 0; // Vertical axis - this->vaGrid[1].data[pointIndex++] = 0; - this->vaGrid[1].data[pointIndex++] = -DIVS_VOLTAGE / 2; - this->vaGrid[1].data[pointIndex++] = 0; - this->vaGrid[1].data[pointIndex++] = DIVS_VOLTAGE / 2; + *(glIterator++) = 0; + *(glIterator++) = -DIVS_VOLTAGE / 2; + *(glIterator++) = 0; + *(glIterator++) = DIVS_VOLTAGE / 2; // Subdiv lines on horizontal axis for(int line = 1; line < DIVS_TIME / 2 * DIVS_SUB; ++line) { float linePosition = (float) line / DIVS_SUB; - this->vaGrid[1].data[pointIndex++] = linePosition; - this->vaGrid[1].data[pointIndex++] = -0.05; - this->vaGrid[1].data[pointIndex++] = linePosition; - this->vaGrid[1].data[pointIndex++] = 0.05; - this->vaGrid[1].data[pointIndex++] = -linePosition; - this->vaGrid[1].data[pointIndex++] = -0.05; - this->vaGrid[1].data[pointIndex++] = -linePosition; - this->vaGrid[1].data[pointIndex++] = 0.05; + *(glIterator++) = linePosition; + *(glIterator++) = -0.05; + *(glIterator++) = linePosition; + *(glIterator++) = 0.05; + *(glIterator++) = -linePosition; + *(glIterator++) = -0.05; + *(glIterator++) = -linePosition; + *(glIterator++) = 0.05; } // Subdiv lines on vertical axis for(int line = 1; line < DIVS_VOLTAGE / 2 * DIVS_SUB; ++line) { float linePosition = (float) line / DIVS_SUB; - this->vaGrid[1].data[pointIndex++] = -0.05; - this->vaGrid[1].data[pointIndex++] = linePosition; - this->vaGrid[1].data[pointIndex++] = 0.05; - this->vaGrid[1].data[pointIndex++] = linePosition; - this->vaGrid[1].data[pointIndex++] = -0.05; - this->vaGrid[1].data[pointIndex++] = -linePosition; - this->vaGrid[1].data[pointIndex++] = 0.05; - this->vaGrid[1].data[pointIndex++] = -linePosition; + *(glIterator++) = -0.05; + *(glIterator++) = linePosition; + *(glIterator++) = 0.05; + *(glIterator++) = linePosition; + *(glIterator++) = -0.05; + *(glIterator++) = -linePosition; + *(glIterator++) = 0.05; + *(glIterator++) = -linePosition; } // Border - this->vaGrid[2].setSize(4 * 2); - this->vaGrid[2].data[0] = -DIVS_TIME / 2; - this->vaGrid[2].data[1] = -DIVS_VOLTAGE / 2; - this->vaGrid[2].data[2] = DIVS_TIME / 2; - this->vaGrid[2].data[3] = -DIVS_VOLTAGE / 2; - this->vaGrid[2].data[4] = DIVS_TIME / 2; - this->vaGrid[2].data[5] = DIVS_VOLTAGE / 2; - this->vaGrid[2].data[6] = -DIVS_TIME / 2; - this->vaGrid[2].data[7] = DIVS_VOLTAGE / 2; + this->vaGrid[2].resize(4 * 2); + glIterator = this->vaGrid[2].begin(); + *(glIterator++) = -DIVS_TIME / 2; + *(glIterator++) = -DIVS_VOLTAGE / 2; + *(glIterator++) = DIVS_TIME / 2; + *(glIterator++) = -DIVS_VOLTAGE / 2; + *(glIterator++) = DIVS_TIME / 2; + *(glIterator++) = DIVS_VOLTAGE / 2; + *(glIterator++) = -DIVS_TIME / 2; + *(glIterator++) = DIVS_VOLTAGE / 2; } diff --git a/openhantek/src/glgenerator.h b/openhantek/src/glgenerator.h index d5f8301..5381841 100644 --- a/openhantek/src/glgenerator.h +++ b/openhantek/src/glgenerator.h @@ -29,8 +29,9 @@ #define GLGENERATOR_H +#include + #include -#include #include @@ -48,23 +49,6 @@ class GlScope; //////////////////////////////////////////////////////////////////////////////// -/// \class GlArray glgenerator.h -/// \brief An array of GLfloat values and it's size. -class GlArray { - public: - GlArray(); - ~GlArray(); - - unsigned int getSize(); - void setSize(unsigned int size); - - GLfloat *data; ///< Pointer to the array - - protected: - unsigned int size; ///< The array size (Number of GLfloat values) -}; - -//////////////////////////////////////////////////////////////////////////////// /// \class GlGenerator glgenerator.h /// \brief Generates the vertex arrays for the GlScope classes. class GlGenerator : public QObject { @@ -85,10 +69,10 @@ class GlGenerator : public QObject { DataAnalyzer *dataAnalyzer; DsoSettings *settings; - QList > vaChannel[Dso::CHANNELMODE_COUNT]; - GlArray vaGrid[3]; + std::vector > > vaChannel[Dso::CHANNELMODE_COUNT]; + std::vector vaGrid[3]; - int digitalPhosphorDepth; + unsigned int digitalPhosphorDepth; public slots: void generateGraphs(); diff --git a/openhantek/src/glscope.cpp b/openhantek/src/glscope.cpp index adcabf7..d5a0277 100644 --- a/openhantek/src/glscope.cpp +++ b/openhantek/src/glscope.cpp @@ -96,7 +96,7 @@ void GlScope::paintGL() { double *fadingFactor = new double[this->generator->digitalPhosphorDepth]; fadingFactor[0] = 100; double fadingRatio = pow(10.0, 2.0 / this->generator->digitalPhosphorDepth); - for(int index = 1; index < this->generator->digitalPhosphorDepth; ++index) + for(unsigned int index = 1; index < this->generator->digitalPhosphorDepth; ++index) fadingFactor[index] = fadingFactor[index - 1] * fadingRatio; switch(this->settings->scope.horizontal.format) { @@ -107,13 +107,13 @@ void GlScope::paintGL() { if((mode == Dso::CHANNELMODE_VOLTAGE) ? this->settings->scope.voltage[channel].used : this->settings->scope.spectrum[channel].used) { // Draw graph for all available depths for(int index = this->generator->digitalPhosphorDepth - 1; index >= 0; index--) { - if(this->generator->vaChannel[mode][channel][index]->data) { + if(!this->generator->vaChannel[mode][channel][index].empty()) { if(mode == Dso::CHANNELMODE_VOLTAGE) this->qglColor(this->settings->view.color.screen.voltage[channel].darker(fadingFactor[index])); else this->qglColor(this->settings->view.color.screen.spectrum[channel].darker(fadingFactor[index])); - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaChannel[mode][channel][index]->data); - glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[mode][channel][index]->getSize() / 2); + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaChannel[mode][channel][index].front()); + glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[mode][channel][index].size() / 2); } } } @@ -127,10 +127,10 @@ void GlScope::paintGL() { if(this->settings->scope.voltage[channel].used) { // Draw graph for all available depths for(int index = this->generator->digitalPhosphorDepth - 1; index >= 0; index--) { - if(this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->data) { + if(!this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].empty()) { this->qglColor(this->settings->view.color.screen.voltage[channel].darker(fadingFactor[index])); - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->data); - glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index]->getSize() / 2); + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].front()); + glDrawArrays((this->settings->view.interpolation == Dso::INTERPOLATION_OFF) ? GL_POINTS : GL_LINE_STRIP, 0, this->generator->vaChannel[Dso::CHANNELMODE_VOLTAGE][channel][index].size() / 2); } } } @@ -156,17 +156,17 @@ void GlScope::paintGL() { this->qglColor(this->settings->view.color.screen.markers); for(int marker = 0; marker < MARKER_COUNT; ++marker) { - if(!this->vaMarker[marker].data) { - this->vaMarker[marker].setSize(2 * 2); - this->vaMarker[marker].data[1] = - DIVS_VOLTAGE; - this->vaMarker[marker].data[3] = DIVS_VOLTAGE; + if(this->vaMarker[marker].size() != 4) { + this->vaMarker[marker].resize(2 * 2); + this->vaMarker[marker][1] = -DIVS_VOLTAGE; + this->vaMarker[marker][3] = DIVS_VOLTAGE; } - this->vaMarker[marker].data[0] = this->settings->scope.horizontal.marker[marker]; - this->vaMarker[marker].data[2] = this->settings->scope.horizontal.marker[marker]; + this->vaMarker[marker][0] = this->settings->scope.horizontal.marker[marker]; + this->vaMarker[marker][2] = this->settings->scope.horizontal.marker[marker]; - glVertexPointer(2, GL_FLOAT, 0, this->vaMarker[marker].data); - glDrawArrays(GL_LINES, 0, this->vaMarker[marker].getSize() / 2); + glVertexPointer(2, GL_FLOAT, 0, &this->vaMarker[marker].front()); + glDrawArrays(GL_LINES, 0, this->vaMarker[marker].size() / 2); } glDisable(GL_LINE_STIPPLE); @@ -215,14 +215,14 @@ void GlScope::drawGrid() { // Grid this->qglColor(this->settings->view.color.screen.grid); - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaGrid[0].data); - glDrawArrays(GL_POINTS, 0, this->generator->vaGrid[0].getSize() / 2); + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaGrid[0].front()); + glDrawArrays(GL_POINTS, 0, this->generator->vaGrid[0].size() / 2); // Axes this->qglColor(this->settings->view.color.screen.axes); - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaGrid[1].data); - glDrawArrays(GL_LINES, 0, this->generator->vaGrid[1].getSize() / 2); + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaGrid[1].front()); + glDrawArrays(GL_LINES, 0, this->generator->vaGrid[1].size() / 2); // Border this->qglColor(this->settings->view.color.screen.border); - glVertexPointer(2, GL_FLOAT, 0, this->generator->vaGrid[2].data); - glDrawArrays(GL_LINE_LOOP, 0, this->generator->vaGrid[2].getSize() / 2); + glVertexPointer(2, GL_FLOAT, 0, &this->generator->vaGrid[2].front()); + glDrawArrays(GL_LINE_LOOP, 0, this->generator->vaGrid[2].size() / 2); } diff --git a/openhantek/src/glscope.h b/openhantek/src/glscope.h index ce994d8..f067770 100644 --- a/openhantek/src/glscope.h +++ b/openhantek/src/glscope.h @@ -64,7 +64,7 @@ class GlScope : public QGLWidget { GlGenerator *generator; DsoSettings *settings; - GlArray vaMarker[2]; + std::vector vaMarker[2]; bool zoomed; }; diff --git a/openhantek/src/hantek/control.cpp b/openhantek/src/hantek/control.cpp index 32576c6..dacb39c 100644 --- a/openhantek/src/hantek/control.cpp +++ b/openhantek/src/hantek/control.cpp @@ -29,6 +29,7 @@ #include #include +#include #include "hantek/control.h" @@ -110,10 +111,7 @@ namespace Hantek { this->device = new Device(this); // Sample buffers - for(unsigned int channel = 0; channel < HANTEK_CHANNELS; ++channel) { - this->samples.append(0); - this->samplesSize.append(0); - } + this->samples.resize(HANTEK_CHANNELS); this->previousSampleCount = 0; @@ -162,6 +160,7 @@ namespace Hantek { // The control loop is running until the device is disconnected int captureState = CAPTURE_WAITING; + int rollState = 0; bool samplingStarted = false; Dso::TriggerMode lastTriggerMode = (Dso::TriggerMode) -1; @@ -172,7 +171,7 @@ namespace Hantek { continue; #ifdef DEBUG - qDebug("Sending bulk command:%s", Helper::hexDump(this->command[command]->data(), this->command[command]->getSize()).toLocal8Bit().data()); + Helper::timestampDebug(QString("Sending bulk command:%1").arg(Helper::hexDump(this->command[command]->data(), this->command[command]->getSize()))); #endif errorCode = this->device->bulkCommand(this->command[command]); @@ -196,7 +195,7 @@ namespace Hantek { continue; #ifdef DEBUG - qDebug("Sending control command %02x:%s", this->controlCode[control], Helper::hexDump(this->control[control]->data(), this->control[control]->getSize()).toLocal8Bit().data()); + 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()))); #endif errorCode = this->device->controlWrite(this->controlCode[control], this->control[control]->data(), this->control[control]->getSize()); @@ -218,9 +217,9 @@ namespace Hantek { // Not more often than every 10 ms though int cycleTime; if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] == UINT_MAX) - cycleTime = qMax((int) ((double) this->device->getPacketSize() / this->settings.samplerate.current * 250), 1); + cycleTime = qMax((int) ((double) this->device->getPacketSize() / ((this->settings.samplerate.limits == &this->specification.samplerate.multi) ? 1 : HANTEK_CHANNELS) / this->settings.samplerate.current * 250), 1); else - cycleTime = qMax((unsigned int) ((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10u); + cycleTime = qMax((int) ((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current * 250), 10); this->msleep(cycleTime); if(!this->sampling) { @@ -228,94 +227,184 @@ namespace Hantek { continue; } + if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] == UINT_MAX) { + // Roll mode + captureState = CAPTURE_WAITING; + + switch(rollState) { + case ROLL_STARTSAMPLING: + // Don't iterate through roll mode steps when stopped + if(!this->sampling) + continue; + + // Sampling hasn't started, update the expected sample count + this->previousSampleCount = this->getSampleCount(); + + errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]); + if(errorCode < 0) { + if(errorCode == LIBUSB_ERROR_NO_DEVICE) + captureState = LIBUSB_ERROR_NO_DEVICE; + break; + } #ifdef DEBUG - int lastCaptureState = captureState; + Helper::timestampDebug("Starting to capture"); #endif - captureState = this->getCaptureState(); - if(captureState < 0) - qWarning("Getting capture state failed: %s", Helper::libUsbErrorString(captureState).toLocal8Bit().data()); + + samplingStarted = true; + + break; + + case ROLL_ENABLETRIGGER: + errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]); + if(errorCode < 0) { + if(errorCode == LIBUSB_ERROR_NO_DEVICE) + captureState = LIBUSB_ERROR_NO_DEVICE; + break; + } #ifdef DEBUG - else if(captureState != lastCaptureState) - qDebug("Capture state changed to %d", captureState); + Helper::timestampDebug("Enabling trigger"); #endif - switch(captureState) { - case CAPTURE_READY: - case CAPTURE_READY2250: - case CAPTURE_READY5200: - // Get data and process it, if we're still sampling - errorCode = this->getSamples(samplingStarted); - if(errorCode < 0) - qWarning("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data()); + + break; + + case ROLL_FORCETRIGGER: + errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]); + if(errorCode < 0) { + if(errorCode == LIBUSB_ERROR_NO_DEVICE) + captureState = LIBUSB_ERROR_NO_DEVICE; + break; + } #ifdef DEBUG - else - qDebug("Received %d B of sampling data", errorCode); + Helper::timestampDebug("Forcing trigger"); #endif + + break; - // Check if we're in single trigger mode - if(this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE && samplingStarted) - this->stopSampling(); - - // Sampling completed, restart it when necessary - samplingStarted = false; + case ROLL_GETDATA: + // Get data and process it, if we're still sampling + errorCode = this->getSamples(samplingStarted); + if(errorCode < 0) + qWarning("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data()); + #ifdef DEBUG + else + Helper::timestampDebug(QString("Received %1 B of sampling data").arg(errorCode)); + #endif + + // Check if we're in single trigger mode + if(this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE && samplingStarted) + this->stopSampling(); + + // Sampling completed, restart it when necessary + samplingStarted = false; + + break; - // Start next capture if necessary by leaving out the break statement - if(!this->sampling) + default: +#ifdef DEBUG + Helper::timestampDebug("Roll mode state unknown"); +#endif break; + } - case CAPTURE_WAITING: - // Sampling hasn't started, update the expected sample count - this->previousSampleCount = this->getSampleCount(); + // Go to next state, or restart if last state was reached + rollState = (rollState + 1) % ROLL_COUNT; + } + else { + // Standard mode + rollState = ROLL_STARTSAMPLING; + +#ifdef DEBUG + int lastCaptureState = captureState; +#endif + captureState = this->getCaptureState(); + if(captureState < 0) + qWarning("Getting capture state failed: %s", Helper::libUsbErrorString(captureState).toLocal8Bit().data()); +#ifdef DEBUG + else if(captureState != lastCaptureState) + Helper::timestampDebug(QString("Capture state changed to %1").arg(captureState)); +#endif + switch(captureState) { + case CAPTURE_READY: + case CAPTURE_READY2250: + case CAPTURE_READY5200: + // Get data and process it, if we're still sampling + errorCode = this->getSamples(samplingStarted); + if(errorCode < 0) + qWarning("Getting sample data failed: %s", Helper::libUsbErrorString(errorCode).toLocal8Bit().data()); +#ifdef DEBUG + else + Helper::timestampDebug(QString("Received %1 B of sampling data").arg(errorCode)); +#endif + + // Check if we're in single trigger mode + if(this->settings.trigger.mode == Dso::TRIGGERMODE_SINGLE && samplingStarted) + this->stopSampling(); + + // Sampling completed, restart it when necessary + samplingStarted = false; + + // Start next capture if necessary by leaving out the break statement + if(!this->sampling) + break; - if(samplingStarted && lastTriggerMode == this->settings.trigger.mode) { - ++cycleCounter; + case CAPTURE_WAITING: + // Sampling hasn't started, update the expected sample count + this->previousSampleCount = this->getSampleCount(); - if(cycleCounter == startCycle) { - // Buffer refilled completely since start of sampling, enable the trigger now - errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]); - if(errorCode < 0) { - if(errorCode == LIBUSB_ERROR_NO_DEVICE) - captureState = LIBUSB_ERROR_NO_DEVICE; - break; + if(samplingStarted && lastTriggerMode == this->settings.trigger.mode) { + ++cycleCounter; + + if(cycleCounter == startCycle && this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] != UINT_MAX) { + // Buffer refilled completely since start of sampling, enable the trigger now + errorCode = this->device->bulkCommand(this->command[BULK_ENABLETRIGGER]); + if(errorCode < 0) { + if(errorCode == LIBUSB_ERROR_NO_DEVICE) + captureState = LIBUSB_ERROR_NO_DEVICE; + break; + } +#ifdef DEBUG + Helper::timestampDebug("Enabling trigger"); +#endif } + else if(cycleCounter >= 8 + startCycle && this->settings.trigger.mode == Dso::TRIGGERMODE_AUTO) { + // Force triggering + errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]); + if(errorCode < 0) { + if(errorCode == LIBUSB_ERROR_NO_DEVICE) + captureState = LIBUSB_ERROR_NO_DEVICE; + break; + } #ifdef DEBUG - qDebug("Enabling trigger"); + Helper::timestampDebug("Forcing trigger"); #endif + } + + if(cycleCounter < 20 || cycleCounter < 4000 / cycleTime) + break; } - else if(cycleCounter >= 8 + startCycle && this->settings.trigger.mode == Dso::TRIGGERMODE_AUTO) { - // Force triggering - errorCode = this->device->bulkCommand(this->command[BULK_FORCETRIGGER]); + + // Start capturing + errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]); + if(errorCode < 0) { if(errorCode == LIBUSB_ERROR_NO_DEVICE) captureState = LIBUSB_ERROR_NO_DEVICE; + break; + } #ifdef DEBUG - qDebug("Forcing trigger"); + Helper::timestampDebug("Starting to capture"); #endif - } - if(cycleCounter < 20 || cycleCounter < 4000 / cycleTime) - break; - } - - // Start capturing - errorCode = this->device->bulkCommand(this->command[BULK_STARTSAMPLING]); - if(errorCode < 0) { - if(errorCode == LIBUSB_ERROR_NO_DEVICE) - captureState = LIBUSB_ERROR_NO_DEVICE; + samplingStarted = true; + cycleCounter = 0; + startCycle = this->settings.trigger.position * 1000 / cycleTime + 1; + lastTriggerMode = this->settings.trigger.mode; break; - } -#ifdef DEBUG - qDebug("Starting to capture"); -#endif - samplingStarted = true; - cycleCounter = 0; - startCycle = this->settings.trigger.position * 1000 / cycleTime + 1; - lastTriggerMode = this->settings.trigger.mode; - break; - - case CAPTURE_SAMPLING: - break; - default: - break; + case CAPTURE_SAMPLING: + break; + default: + break; + } } } @@ -417,20 +506,14 @@ namespace Hantek { // Clear unused channels for(int channelCounter = 0; channelCounter < HANTEK_CHANNELS; ++channelCounter) - if(channelCounter != channel && this->samples[channelCounter]) { + if(channelCounter != channel) { - delete this->samples[channelCounter]; - this->samples[channelCounter] = 0; + this->samples[channelCounter].clear(); } if(channel < HANTEK_CHANNELS) { - // Reallocate memory for samples if the sample count has changed - if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) { - if(this->samples[channel]) - delete this->samples[channel]; - this->samples[channel] = new double[sampleCount]; - this->samplesSize[channel] = sampleCount; - } + // Resize sample vector + this->samples[channel].resize(sampleCount); // Convert data from the oscilloscope and write it into the sample buffer unsigned int bufferPosition = this->settings.trigger.point * 2; @@ -464,13 +547,8 @@ namespace Hantek { sampleCount = totalSampleCount / HANTEK_CHANNELS; for(int channel = 0; channel < HANTEK_CHANNELS; ++channel) { if(this->settings.voltage[channel].used) { - // Reallocate memory for samples if the sample count has changed - if(!this->samples[channel] || this->samplesSize[channel] != sampleCount) { - if(this->samples[channel]) - delete this->samples[channel]; - this->samples[channel] = new double[sampleCount]; - this->samplesSize[channel] = sampleCount; - } + // Resize sample vector + this->samples[channel].resize(sampleCount); // Convert data from the oscilloscope and write it into the sample buffer unsigned int bufferPosition = this->settings.trigger.point * 2; @@ -497,17 +575,20 @@ namespace Hantek { } } } - else if(this->samples[channel]) { + else { // Clear unused channels - delete this->samples[channel]; - this->samples[channel] = 0; - this->samplesSize[channel] = 0; + this->samples[channel].clear(); } } } this->samplesMutex.unlock(); - emit samplesAvailable(&(this->samples), &(this->samplesSize), this->settings.samplerate.current, &(this->samplesMutex)); +#ifdef DEBUG + static unsigned int id = 0; + ++id; + Helper::timestampDebug(QString("Received packet %1").arg(id)); +#endif + emit samplesAvailable(&(this->samples), this->settings.samplerate.current, this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] == UINT_MAX, &(this->samplesMutex)); } return errorCode; @@ -671,6 +752,14 @@ namespace Hantek { return 0; } + // Check if the divider has changed and adapt samplerate limits accordingly + if(this->specification.bufferDividers[index] != this->specification.bufferDividers[this->settings.recordLengthId]) { + this->updateSamplerateLimits(); + + // Samplerate dividers changed, recalculate it + this->restoreTargets(); + } + this->settings.recordLengthId = index; return this->settings.samplerate.limits->recordLengths[index]; @@ -777,9 +866,9 @@ namespace Hantek { this->settings.samplerate.downsampler = downsampler; if(downsampler) - this->settings.samplerate.current = this->settings.samplerate.limits->base / downsampler; + this->settings.samplerate.current = this->settings.samplerate.limits->base / this->specification.bufferDividers[this->settings.recordLengthId] / downsampler; else - this->settings.samplerate.current = this->settings.samplerate.limits->max; + this->settings.samplerate.current = this->settings.samplerate.limits->max / this->specification.bufferDividers[this->settings.recordLengthId]; // Update dependencies this->setPretriggerPosition(this->settings.trigger.position); @@ -791,15 +880,14 @@ namespace Hantek { } // Check for Roll mode - if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] != UINT_MAX) { + if(this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] != UINT_MAX) emit recordTimeChanged((double) this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId] / this->settings.samplerate.current); - emit samplerateChanged(this->settings.samplerate.current); - } + emit samplerateChanged(this->settings.samplerate.current); return downsampler; } - /// \brief Try to connect to the oscilloscope. + /// \brief Restore the samplerate/timebase targets after divider updates. void Control::restoreTargets() { if(this->settings.samplerate.target.samplerateSet) this->setSamplerate(); @@ -807,6 +895,13 @@ namespace Hantek { this->setRecordTime(); } + /// \brief Update the minimum and maximum supported samplerate. + void Control::updateSamplerateLimits() { + // Works only if the minimum samplerate for normal mode is lower than for fast rate mode, which is the case for all models + ControlSamplerateLimits *limits = (this->settings.usedChannels <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single; + 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]); + } + /// \brief Try to connect to the oscilloscope. void Control::connectDevice() { int errorCode; @@ -1023,7 +1118,7 @@ namespace Hantek { /// \param index The record length index that should be set. /// \return The record length that has been set, 0 on error. unsigned int Control::setRecordLength(unsigned int index) { - if(!this->device->isConnected()) + if(!this->device->isConnected()) return 0; if(!this->updateRecordLength(index)) @@ -1052,7 +1147,7 @@ namespace Hantek { } // When possible, enable fast rate if it is required to reach the requested samplerate - bool fastRate = (this->settings.usedChannels <= 1) && (samplerate > this->specification.samplerate.single.max); + bool fastRate = (this->settings.usedChannels <= 1) && (samplerate > this->specification.samplerate.single.max / this->specification.bufferDividers[this->settings.recordLengthId]); // What is the nearest, at least as high samplerate the scope can provide? unsigned int downsampler = 0; @@ -1085,7 +1180,7 @@ namespace Hantek { double maxSamplerate = (double) this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] / duration; // When possible, enable fast rate if the record time can't be set that low to improve resolution - bool fastRate = (this->settings.usedChannels <= 1) && (maxSamplerate >= this->specification.samplerate.multi.base); + bool fastRate = (this->settings.usedChannels <= 1) && (maxSamplerate >= this->specification.samplerate.multi.base / this->specification.bufferDividers[this->settings.recordLengthId]); // What is the nearest, at most as high samplerate the scope can provide? unsigned int downsampler = 0; @@ -1162,14 +1257,8 @@ namespace Hantek { bool fastRateChanged = (this->settings.usedChannels <= 1) != (channelCount <= 1); this->settings.usedChannels = channelCount; - if(fastRateChanged) { - // Works only if the minimum samplerate for normal mode is lower than for fast rate mode, which is the case for all models - ControlSamplerateLimits *limits = (channelCount <= 1) ? &this->specification.samplerate.multi : &this->specification.samplerate.single; - emit samplerateLimitsChanged((double) this->specification.samplerate.single.base / this->specification.samplerate.single.maxDownsampler, limits->max); - - // Samplerate differs for fast rate mode, recalculate it - this->restoreTargets(); - } + if(fastRateChanged) + this->updateSamplerateLimits(); return Dso::ERROR_NONE; } @@ -1412,6 +1501,8 @@ namespace Hantek { // All trigger positions are measured in samples unsigned int positionSamples = position * this->settings.samplerate.current; + unsigned int recordLength = this->settings.samplerate.limits->recordLengths[this->settings.recordLengthId]; + bool rollMode = recordLength == UINT_MAX; // Fast rate mode uses both channels if(this->settings.samplerate.limits == &this->specification.samplerate.multi) positionSamples /= HANTEK_CHANNELS; @@ -1419,7 +1510,7 @@ namespace Hantek { switch(this->specification.command.bulk.setPretrigger) { case BULK_SETTRIGGERANDSAMPLERATE: { // Calculate the position value (Start point depending on record length) - unsigned int position = 0x7ffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples; + unsigned int position = rollMode ? 0x1 : 0x7ffff - recordLength + positionSamples; // SetTriggerAndSamplerate bulk command for trigger position static_cast(this->command[BULK_SETTRIGGERANDSAMPLERATE])->setTriggerPosition(position); @@ -1429,8 +1520,8 @@ namespace Hantek { } case BULK_FSETBUFFER: { // Calculate the position values (Inverse, maximum is 0x7ffff) - unsigned int positionPre = 0x7fffful - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples; - unsigned int positionPost = 0x7fffful - positionSamples; + unsigned int positionPre = 0x7ffff - recordLength + positionSamples; + unsigned int positionPost = 0x7ffff - positionSamples; // SetBuffer2250 bulk command for trigger position BulkSetBuffer2250 *commandSetBuffer2250 = static_cast(this->command[BULK_FSETBUFFER]); @@ -1442,7 +1533,7 @@ namespace Hantek { } case BULK_ESETTRIGGERORSAMPLERATE: { // Calculate the position values (Inverse, maximum is 0xffff) - unsigned short int positionPre = 0xffff - this->specification.samplerate.single.recordLengths[this->settings.recordLengthId] + positionSamples; + unsigned short int positionPre = 0xffff - recordLength + positionSamples; unsigned short int positionPost = 0xffff - positionSamples; // SetBuffer5200 bulk command for trigger position diff --git a/openhantek/src/hantek/control.h b/openhantek/src/hantek/control.h index 615ccf8..a509935 100644 --- a/openhantek/src/hantek/control.h +++ b/openhantek/src/hantek/control.h @@ -53,6 +53,17 @@ namespace Hantek { }; ////////////////////////////////////////////////////////////////////////////// + /// \enum RollState hantek/types.h + /// \brief The states of the roll cycle (Since capture state isn't valid). + enum RollState { + ROLL_STARTSAMPLING = 0, ///< Start sampling + ROLL_ENABLETRIGGER = 1, ///< Enable triggering + ROLL_FORCETRIGGER = 2, ///< Force triggering + ROLL_GETDATA = 3, ///< Request sample data + ROLL_COUNT + }; + + ////////////////////////////////////////////////////////////////////////////// /// \struct ControlSpecificationCommandsBulk hantek/control.h /// \brief Stores the bulk command codes used for this device. struct ControlSpecificationCommandsBulk { @@ -208,6 +219,7 @@ namespace Hantek { unsigned int updateRecordLength(unsigned int size); unsigned int updateSamplerate(unsigned int downsampler, bool fastRate); void restoreTargets(); + void updateSamplerateLimits(); // Communication with device Device *device; ///< The USB device for the oscilloscope @@ -223,8 +235,7 @@ namespace Hantek { ControlSettings settings; ///< The current settings of the device // Results - QList samples; ///< Sample data arrays - QList samplesSize; ///< Number of samples data array + std::vector > samples; ///< Sample data vectors sent to the data analyzer unsigned int previousSampleCount; ///< The expected total number of samples at the last check before sampling started QMutex samplesMutex; ///< Mutex for the sample data diff --git a/openhantek/src/helper.h b/openhantek/src/helper.h index bbece69..afe6a39 100644 --- a/openhantek/src/helper.h +++ b/openhantek/src/helper.h @@ -30,6 +30,7 @@ #include #include +#include #if LIBUSB_VERSION == 0 @@ -71,6 +72,13 @@ namespace Helper { #ifdef DEBUG QString hexDump(unsigned char *data, unsigned int length); unsigned int hexParse(const QString dump, unsigned char *data, unsigned int length); + inline void timestampDebug(QString text); + + /// \brief Print debug information with timestamp. + /// \param text Text that will be output via qDebug. + inline void timestampDebug(QString text) { + qDebug("%s: %s", QTime::currentTime().toString("hh:mm:ss.zzz").toAscii().constData(), text.toAscii().constData()); + } #endif ////////////////////////////////////////////////////////////////////////////// diff --git a/openhantek/src/openhantek.cpp b/openhantek/src/openhantek.cpp index aa261e6..e767570 100644 --- a/openhantek/src/openhantek.cpp +++ b/openhantek/src/openhantek.cpp @@ -276,7 +276,7 @@ void OpenHantekMainWindow::connectSignals() { connect(this, SIGNAL(settingsChanged()), this, SLOT(applySettings())); //connect(this->dsoWidget, SIGNAL(stopped()), this, SLOT(stopped())); connect(this->dsoControl, SIGNAL(statusMessage(QString, int)), this->statusBar(), SLOT(showMessage(QString, int))); - connect(this->dsoControl, SIGNAL(samplesAvailable(const QList *, const QList *, double, QMutex *)), this->dataAnalyzer, SLOT(analyze(const QList *, const QList *, double, QMutex *))); + connect(this->dsoControl, SIGNAL(samplesAvailable(const std::vector > *, double, bool, QMutex *)), this->dataAnalyzer, SLOT(analyze(const std::vector > *, double, bool, QMutex *))); // Connect signals to DSO controller and widget connect(this->horizontalDock, SIGNAL(samplerateChanged(double)), this, SLOT(samplerateSelected())); @@ -334,8 +334,10 @@ void OpenHantekMainWindow::initializeDevice() { this->timebaseSelected(); if(this->dsoControl->getAvailableRecordLengths()->isEmpty()) this->dsoControl->setRecordLength(this->settings->scope.horizontal.recordLength); - else - this->dsoControl->setRecordLength(this->dsoControl->getAvailableRecordLengths()->indexOf(this->settings->scope.horizontal.recordLength)); + else { + int index = this->dsoControl->getAvailableRecordLengths()->indexOf(this->settings->scope.horizontal.recordLength); + this->dsoControl->setRecordLength(index < 0 ? 1 : index); + } this->dsoControl->setTriggerMode(this->settings->scope.trigger.mode); this->dsoControl->setPretriggerPosition(this->settings->scope.trigger.position * this->settings->scope.horizontal.timebase * DIVS_TIME); this->dsoControl->setTriggerSlope(this->settings->scope.trigger.slope); @@ -610,7 +612,7 @@ void OpenHantekMainWindow::updateSettings() { /// \brief The oscilloscope changed the record time. /// \param duration The new record time duration in seconds. void OpenHantekMainWindow::recordTimeChanged(double duration) { - if(this->settings->scope.horizontal.samplerateSet) { + if(this->settings->scope.horizontal.samplerateSet && this->settings->scope.horizontal.recordLength != UINT_MAX) { // The samplerate was set, let's adapt the timebase accordingly this->settings->scope.horizontal.timebase = duration / DIVS_TIME; this->horizontalDock->setTimebase(this->settings->scope.horizontal.timebase); @@ -625,7 +627,7 @@ void OpenHantekMainWindow::recordTimeChanged(double duration) { /// \brief The oscilloscope changed the samplerate. /// \param samplerate The new samplerate in samples per second. void OpenHantekMainWindow::samplerateChanged(double samplerate) { - if(!this->settings->scope.horizontal.samplerateSet) { + if(!this->settings->scope.horizontal.samplerateSet && this->settings->scope.horizontal.recordLength != UINT_MAX) { // The timebase was set, let's adapt the samplerate accordingly this->settings->scope.horizontal.samplerate = samplerate; this->horizontalDock->setSamplerate(samplerate);