# HG changeset patch # User Hasan Yavuz ÖZDERYA # Date 2015-11-07 14:46:26 # Node ID 7aac14a9755278d6b366c906908f94555986456b # Parent 3b5b36112f227316f9f8dadf3aee11975dcdc5da moved data parsing and reading related code to a new class diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ qt5_wrap_ui(UI_FILES snapshotview.ui commandpanel.ui commandwidget.ui + dataformatpanel.ui ) if (WIN32) @@ -85,6 +86,7 @@ add_executable(${PROGRAM_NAME} WIN32 commandpanel.cpp commandwidget.cpp commandedit.cpp + dataformatpanel.cpp ${UI_FILES} ${RES_FILES} misc/windows_icon.rc diff --git a/dataformatpanel.cpp b/dataformatpanel.cpp new file mode 100644 --- /dev/null +++ b/dataformatpanel.cpp @@ -0,0 +1,327 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + This file is part of serialplot. + + serialplot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + serialplot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with serialplot. If not, see . +*/ + +#include "dataformatpanel.h" +#include "ui_dataformatpanel.h" + +#include + +#include "utils.h" +#include "floatswap.h" + +DataFormatPanel::DataFormatPanel(QSerialPort* port, + QList* channelBuffers, + QWidget *parent) : + QWidget(parent), + ui(new Ui::DataFormatPanel) +{ + ui->setupUi(this); + + serialPort = port; + _channelBuffers = channelBuffers; + paused = false; + + // setup number format buttons + numberFormatButtons.addButton(ui->rbUint8, NumberFormat_uint8); + numberFormatButtons.addButton(ui->rbUint16, NumberFormat_uint16); + numberFormatButtons.addButton(ui->rbUint32, NumberFormat_uint32); + numberFormatButtons.addButton(ui->rbInt8, NumberFormat_int8); + numberFormatButtons.addButton(ui->rbInt16, NumberFormat_int16); + numberFormatButtons.addButton(ui->rbInt32, NumberFormat_int32); + numberFormatButtons.addButton(ui->rbFloat, NumberFormat_float); + numberFormatButtons.addButton(ui->rbASCII, NumberFormat_ASCII); + + QObject::connect( + &numberFormatButtons, SIGNAL(buttonToggled(int, bool)), + this, SLOT(onNumberFormatButtonToggled(int, bool))); + + // init number format + selectNumberFormat((NumberFormat) numberFormatButtons.checkedId()); + + // setup number of channels spinbox + QObject::connect(ui->spNumOfChannels, + SELECT::OVERLOAD_OF(&QSpinBox::valueChanged), + this, &DataFormatPanel::onNumOfChannelsSP); + + _numOfChannels = ui->spNumOfChannels->value(); + + // Init sps (sample per second) counter + sampleCount = 0; + QObject::connect(&spsTimer, &QTimer::timeout, + this, &DataFormatPanel::spsTimerTimeout); + spsTimer.start(SPS_UPDATE_TIMEOUT * 1000); + + // Init demo mode + demoCount = 0; + demoTimer.setInterval(100); + QObject::connect(&demoTimer, &QTimer::timeout, + this, &DataFormatPanel::demoTimerTimeout); +} + +DataFormatPanel::~DataFormatPanel() +{ + delete ui; +} + +void DataFormatPanel::onNumberFormatButtonToggled(int numberFormatId, + bool checked) +{ + if (checked) selectNumberFormat((NumberFormat) numberFormatId); +} + +void DataFormatPanel::selectNumberFormat(NumberFormat numberFormatId) +{ + numberFormat = numberFormatId; + + switch(numberFormat) + { + case NumberFormat_uint8: + sampleSize = 1; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_int8: + sampleSize = 1; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_uint16: + sampleSize = 2; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_int16: + sampleSize = 2; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_uint32: + sampleSize = 4; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_int32: + sampleSize = 4; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_float: + sampleSize = 4; + readSample = &DataFormatPanel::readSampleAs; + break; + case NumberFormat_ASCII: + sampleSize = 0; // these two members should not be used + readSample = NULL; // in this mode + break; + } + + if (numberFormat == NumberFormat_ASCII) + { + QObject::disconnect(serialPort, &QSerialPort::readyRead, 0, 0); + QObject::connect(this->serialPort, &QSerialPort::readyRead, + this, &DataFormatPanel::onDataReadyASCII); + } + else + { + QObject::disconnect(serialPort, &QSerialPort::readyRead, 0, 0); + QObject::connect(serialPort, &QSerialPort::readyRead, + this, &DataFormatPanel::onDataReady); + } + + emit skipByteEnabledChanged(skipByteEnabled()); +} + +bool DataFormatPanel::skipByteEnabled() +{ + return numberFormat != NumberFormat_ASCII; +} + +unsigned DataFormatPanel::numOfChannels() +{ + return _numOfChannels; +} + +void DataFormatPanel::onNumOfChannelsSP(int value) +{ + _numOfChannels = value; + emit numOfChannelsChanged(value); +} + +void DataFormatPanel::requestSkipByte() +{ + skipByteRequested = true; +} + +void DataFormatPanel::pause(bool enabled) +{ + paused = enabled; +} + +void DataFormatPanel::enableDemo(bool enabled) +{ + if (enabled) + { + demoTimer.start(); + } + else + { + demoTimer.stop(); + } +} + +void DataFormatPanel::spsTimerTimeout() +{ + unsigned currentSps = _samplesPerSecond; + _samplesPerSecond = sampleCount/SPS_UPDATE_TIMEOUT; + if (currentSps != _samplesPerSecond) + { + emit samplesPerSecondChanged(_samplesPerSecond); + } + sampleCount = 0; +} + + +void DataFormatPanel::demoTimerTimeout() +{ + const double period = 100; + demoCount++; + if (demoCount >= 100) demoCount = 0; + + if (!paused) + { + for (unsigned ci = 0; ci < _numOfChannels; ci++) + { + // we are calculating the fourier components of square wave + double value = 4*sin(2*M_PI*double((ci+1)*demoCount)/period)/((2*(ci+1))*M_PI); + addChannelData(ci, &value, 1); + } + emit dataAdded(); + } +} + +void DataFormatPanel::onDataReady() +{ + // TODO: discard data in the size of packageSize + if (paused) + { + serialPort->clear(QSerialPort::Input); + return; + } + + // a package is a set of channel data like {CHAN0_SAMPLE, CHAN1_SAMPLE...} + int packageSize = sampleSize * _numOfChannels; + int bytesAvailable = serialPort->bytesAvailable(); + + if (bytesAvailable > 0 && skipByteRequested) + { + serialPort->read(1); + skipByteRequested = false; + bytesAvailable--; + } + + if (bytesAvailable < packageSize) return; + + int numOfPackagesToRead = + (bytesAvailable - (bytesAvailable % packageSize)) / packageSize; + double* channelSamples = new double[numOfPackagesToRead*_numOfChannels]; + + // TODO: use `for`, it is for this + int i = 0; + while(i < numOfPackagesToRead) + { + for (unsigned int ci = 0; ci < _numOfChannels; ci++) + { + // channelSamples[ci].replace(i, (this->*readSample)()); + channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)(); + } + i++; + } + + for (unsigned int ci = 0; ci < _numOfChannels; ci++) + { + addChannelData(ci, + channelSamples + ci*numOfPackagesToRead, + numOfPackagesToRead); + } + emit dataAdded(); + + delete channelSamples; +} + +void DataFormatPanel::onDataReadyASCII() +{ + while(serialPort->canReadLine()) + { + QByteArray line = serialPort->readLine(); + + // discard data if paused + if (paused) + { + return; + } + + line = line.trimmed(); + auto separatedValues = line.split(','); + + int numReadChannels; // effective number of channels to read + if (separatedValues.length() >= int(_numOfChannels)) + { + numReadChannels = _numOfChannels; + } + else // there is missing channel data + { + numReadChannels = separatedValues.length(); + qWarning() << "Incoming data is missing data for some channels!"; + } + + // parse read line + for (int ci = 0; ci < numReadChannels; ci++) + { + bool ok; + double channelSample = separatedValues[ci].toDouble(&ok); + if (ok) + { + addChannelData(ci, &channelSample, 1); + } + else + { + qWarning() << "Data parsing error for channel: " << ci; + } + } + emit dataAdded(); + } +} + +template double DataFormatPanel::readSampleAs() +{ + T data; + serialPort->read((char*) &data, sizeof(data)); + + if (ui->rbLittleE->isChecked()) + { + data = qFromLittleEndian(data); + } + else + { + data = qFromBigEndian(data); + } + + return double(data); +} + +void DataFormatPanel::addChannelData(unsigned int channel, + double* data, unsigned size) +{ + (*_channelBuffers)[channel]->addSamples(data, size); + sampleCount += size; +} diff --git a/dataformatpanel.h b/dataformatpanel.h new file mode 100644 --- /dev/null +++ b/dataformatpanel.h @@ -0,0 +1,117 @@ +/* + Copyright © 2015 Hasan Yavuz Özderya + + This file is part of serialplot. + + serialplot is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + serialplot is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with serialplot. If not, see . +*/ + +#ifndef DATAFORMATPANEL_H +#define DATAFORMATPANEL_H + +#include +#include +#include +#include +#include +#include + +#include "framebuffer.h" + +namespace Ui { +class DataFormatPanel; +} + +class DataFormatPanel : public QWidget +{ + Q_OBJECT + +public: + explicit DataFormatPanel(QSerialPort* port, + QList* channelBuffers, + QWidget *parent = 0); + ~DataFormatPanel(); + + unsigned numOfChannels(); + unsigned samplesPerSecond(); + bool skipByteEnabled(void); // true for binary formats + +public slots: + // during next read operation reader will skip 1 byte, + // requests are not accumulated + void requestSkipByte(); + void pause(bool); + void enableDemo(bool); // demo shouldn't be enabled when port is open + +signals: + void numOfChannelsChanged(unsigned); + void samplesPerSecondChanged(unsigned); + void skipByteEnabledChanged(bool); + void dataAdded(); + +private: + enum NumberFormat + { + NumberFormat_uint8, + NumberFormat_uint16, + NumberFormat_uint32, + NumberFormat_int8, + NumberFormat_int16, + NumberFormat_int32, + NumberFormat_float, + NumberFormat_ASCII + }; + + Ui::DataFormatPanel *ui; + QButtonGroup numberFormatButtons; + + QSerialPort* serialPort; + QList* _channelBuffers; + + unsigned int _numOfChannels; + NumberFormat numberFormat; + unsigned int sampleSize; // number of bytes in the selected number format + bool skipByteRequested; + bool paused; + + const int SPS_UPDATE_TIMEOUT = 1; // second + unsigned _samplesPerSecond; + unsigned int sampleCount; + QTimer spsTimer; + + // demo + QTimer demoTimer; + int demoCount; + + void selectNumberFormat(NumberFormat numberFormatId); + + // points to the readSampleAs function for currently selected number format + double (DataFormatPanel::*readSample)(); + + // note that serialPort should already have enough bytes present + template double readSampleAs(); + + // `data` contains i th channels data + void addChannelData(unsigned int channel, double* data, unsigned size); + +private slots: + void onDataReady(); // used with binary number formats + void onDataReadyASCII(); // used with ASCII number format + void onNumberFormatButtonToggled(int numberFormatId, bool checked); + void onNumOfChannelsSP(int value); + void spsTimerTimeout(); + void demoTimerTimeout(); +}; + +#endif // DATAFORMATPANEL_H diff --git a/dataformatpanel.ui b/dataformatpanel.ui new file mode 100644 --- /dev/null +++ b/dataformatpanel.ui @@ -0,0 +1,244 @@ + + + DataFormatPanel + + + + 0 + 0 + 607 + 181 + + + + Data Format + + + + + + + + Number Of Channels: + + + + + + + + 60 + 0 + + + + false + + + 1 + + + 32 + + + + + + + + + Qt::Vertical + + + + + + + 0 + + + + + Number Format: + + + + + + unsigned 4 bytes integer + + + uint32 + + + + + + + signed 1 byte integer + + + int8 + + + + + + + unsigned 1 byte integer + + + uint8 + + + true + + + + + + + Comma Separated Values + + + ASCII(CSV) + + + + + + + signed 2 bytes integer + + + int16 + + + + + + + signed 4 bytes integer + + + int32 + + + + + + + 4 bytes floating point number + + + float + + + + + + + unsigned 2 bytes integer + + + uint16 + + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + 0 + + + + + + 0 + 0 + + + + Byte Order: + + + + + + least significant byte first + + + Little Endian + + + true + + + + + + + most significant byte first + + + Big Endian + + + + + + + + + + Qt::Vertical + + + + 20 + 1 + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 37 + 20 + + + + + + + + + diff --git a/mainwindow.cpp b/mainwindow.cpp --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -35,7 +34,6 @@ #include "utils.h" #include "version.h" -#include "floatswap.h" #if defined(Q_OS_WIN) && defined(QT_STATIC) #include @@ -56,10 +54,12 @@ MainWindow::MainWindow(QWidget *parent) aboutDialog(this), portControl(&serialPort), commandPanel(&serialPort), + dataFormatPanel(&serialPort, &channelBuffers), snapshotMan(this, &channelBuffers) { ui->setupUi(this); ui->tabWidget->insertTab(0, &portControl, "Port"); + ui->tabWidget->insertTab(1, &dataFormatPanel, "Data Format"); ui->tabWidget->insertTab(3, &commandPanel, "Commands"); ui->tabWidget->setCurrentIndex(0); addToolBar(portControl.toolBar()); @@ -94,7 +94,7 @@ MainWindow::MainWindow(QWidget *parent) this, &MainWindow::onPortToggled); QObject::connect(&portControl, &PortControl::skipByteRequested, - this, &MainWindow::skipByte); + &dataFormatPanel, &DataFormatPanel::requestSkipByte); QObject::connect(ui->spNumOfSamples, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged), this, &MainWindow::onNumOfSamplesChanged); @@ -114,24 +114,6 @@ MainWindow::MainWindow(QWidget *parent) QObject::connect(snapshotMan.takeSnapshotAction(), &QAction::triggered, ui->plot, &Plot::flashSnapshotOverlay); - // setup number of channels spinbox - QObject::connect(ui->spNumOfChannels, - SELECT::OVERLOAD_OF(&QSpinBox::valueChanged), - this, &MainWindow::onNumOfChannelsChanged); - - // setup number format buttons - numberFormatButtons.addButton(ui->rbUint8, NumberFormat_uint8); - numberFormatButtons.addButton(ui->rbUint16, NumberFormat_uint16); - numberFormatButtons.addButton(ui->rbUint32, NumberFormat_uint32); - numberFormatButtons.addButton(ui->rbInt8, NumberFormat_int8); - numberFormatButtons.addButton(ui->rbInt16, NumberFormat_int16); - numberFormatButtons.addButton(ui->rbInt32, NumberFormat_int32); - numberFormatButtons.addButton(ui->rbFloat, NumberFormat_float); - numberFormatButtons.addButton(ui->rbASCII, NumberFormat_ASCII); - - QObject::connect(&numberFormatButtons, SIGNAL(buttonToggled(int, bool)), - this, SLOT(onNumberFormatButtonToggled(int, bool))); - // init port signals QObject::connect(&(this->serialPort), SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(onPortError(QSerialPort::SerialPortError))); @@ -143,10 +125,21 @@ MainWindow::MainWindow(QWidget *parent) ui->spYmax->setRange((-1) * std::numeric_limits::max(), std::numeric_limits::max()); - // init data arrays and plot + // init data format and reader + QObject::connect(&dataFormatPanel, &DataFormatPanel::dataAdded, + ui->plot, &QwtPlot::replot); + + QObject::connect(ui->actionPause, &QAction::triggered, + &dataFormatPanel, &DataFormatPanel::pause); + // init data arrays and plot numOfSamples = ui->spNumOfSamples->value(); - numOfChannels = ui->spNumOfChannels->value(); + unsigned numOfChannels = dataFormatPanel.numOfChannels(); + + QObject::connect(&dataFormatPanel, + &DataFormatPanel::numOfChannelsChanged, + this, + &MainWindow::onNumOfChannelsChanged); // init channel data and curve list for (unsigned int i = 0; i < numOfChannels; i++) @@ -187,30 +180,15 @@ MainWindow::MainWindow(QWidget *parent) QObject::connect(ui->cbRangePresets, SIGNAL(activated(int)), this, SLOT(onRangeSelected())); - // init number format - if (numberFormatButtons.checkedId() >= 0) - { - selectNumberFormat((NumberFormat) numberFormatButtons.checkedId()); - } - else - { - selectNumberFormat(NumberFormat_uint8); - } - // Init sps (sample per second) counter - sampleCount = 0; spsLabel.setText("0sps"); spsLabel.setToolTip("samples per second (total of all channels)"); ui->statusBar->addPermanentWidget(&spsLabel); - spsTimer.start(SPS_UPDATE_TIMEOUT * 1000); - QObject::connect(&spsTimer, &QTimer::timeout, - this, &MainWindow::spsTimerTimeout); + QObject::connect(&dataFormatPanel, + &DataFormatPanel::samplesPerSecondChanged, + this, &MainWindow::onSpsChanged); - // Init demo mode - demoCount = 0; - demoTimer.setInterval(100); - QObject::connect(&demoTimer, &QTimer::timeout, - this, &MainWindow::demoTimerTimeout); + // init demo QObject::connect(ui->actionDemoMode, &QAction::toggled, this, &MainWindow::enableDemo); @@ -224,7 +202,6 @@ MainWindow::MainWindow(QWidget *parent) demoIndicator.hide(); demoIndicator.attach(ui->plot); } - } MainWindow::~MainWindow() @@ -265,97 +242,6 @@ void MainWindow::onPortToggled(bool open ui->actionDemoMode->setEnabled(!open); } -void MainWindow::onDataReady() -{ - if (ui->actionPause->isChecked()) - { - serialPort.clear(QSerialPort::Input); - return; - } - - // a package is a set of channel data like {CHAN0_SAMPLE, CHAN1_SAMPLE...} - int packageSize = sampleSize * numOfChannels; - int bytesAvailable = serialPort.bytesAvailable(); - - if (bytesAvailable > 0 && skipByteRequested) - { - serialPort.read(1); - skipByteRequested = false; - bytesAvailable--; - } - - if (bytesAvailable < packageSize) return; - - int numOfPackagesToRead = - (bytesAvailable - (bytesAvailable % packageSize)) / packageSize; - double* channelSamples = new double[numOfPackagesToRead*numOfChannels]; - - int i = 0; - while(i < numOfPackagesToRead) - { - for (unsigned int ci = 0; ci < numOfChannels; ci++) - { - // channelSamples[ci].replace(i, (this->*readSample)()); - channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)(); - } - i++; - } - - for (unsigned int ci = 0; ci < numOfChannels; ci++) - { - addChannelData(ci, - channelSamples + ci*numOfPackagesToRead, - numOfPackagesToRead); - } - ui->plot->replot(); - - delete channelSamples; -} - -void MainWindow::onDataReadyASCII() -{ - while(serialPort.canReadLine()) - { - QByteArray line = serialPort.readLine(); - - // discard data if paused - if (ui->actionPause->isChecked()) - { - return; - } - - line = line.trimmed(); - auto separatedValues = line.split(','); - - int numReadChannels; // effective number of channels to read - if (separatedValues.length() >= int(numOfChannels)) - { - numReadChannels = numOfChannels; - } - else // there is missing channel data - { - numReadChannels = separatedValues.length(); - qWarning() << "Incoming data is missing data for some channels!"; - } - - // parse read line - for (int ci = 0; ci < numReadChannels; ci++) - { - bool ok; - double channelSample = separatedValues[ci].toDouble(&ok); - if (ok) - { - addChannelData(ci, &channelSample, 1); - } - else - { - qWarning() << "Data parsing error for channel: " << ci; - } - } - ui->plot->replot(); - } -} - void MainWindow::onPortError(QSerialPort::SerialPortError error) { switch(error) @@ -414,20 +300,9 @@ required privileges or device is already } } -void MainWindow::skipByte() -{ - skipByteRequested = true; -} - -void MainWindow::addChannelData(unsigned int channel, double* data, unsigned size) -{ - channelBuffers[channel]->addSamples(data, size); - sampleCount += size; -} - void MainWindow::clearPlot() { - for (unsigned int ci = 0; ci < numOfChannels; ci++) + for (int ci = 0; ci < channelBuffers.size(); ci++) { channelBuffers[ci]->clear(); } @@ -438,7 +313,7 @@ void MainWindow::onNumOfSamplesChanged(i { numOfSamples = value; - for (unsigned int ci = 0; ci < numOfChannels; ci++) + for (int ci = 0; ci < channelBuffers.size(); ci++) { channelBuffers[ci]->resize(numOfSamples); } @@ -446,10 +321,10 @@ void MainWindow::onNumOfSamplesChanged(i ui->plot->replot(); } -void MainWindow::onNumOfChannelsChanged(int value) +void MainWindow::onNumOfChannelsChanged(unsigned value) { - unsigned int oldNum = this->numOfChannels; - this->numOfChannels = value; + unsigned int oldNum = channelBuffers.size(); + unsigned numOfChannels = value; if (numOfChannels > oldNum) { @@ -509,82 +384,9 @@ void MainWindow::onRangeSelected() ui->cbAutoScale->setChecked(false); } -void MainWindow::onNumberFormatButtonToggled(int numberFormatId, bool checked) -{ - if (checked) selectNumberFormat((NumberFormat) numberFormatId); -} - -void MainWindow::selectNumberFormat(NumberFormat numberFormatId) +void MainWindow::onSpsChanged(unsigned sps) { - numberFormat = numberFormatId; - - switch(numberFormat) - { - case NumberFormat_uint8: - sampleSize = 1; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_int8: - sampleSize = 1; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_uint16: - sampleSize = 2; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_int16: - sampleSize = 2; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_uint32: - sampleSize = 4; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_int32: - sampleSize = 4; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_float: - sampleSize = 4; - readSample = &MainWindow::readSampleAs; - break; - case NumberFormat_ASCII: - sampleSize = 0; // these two members should not be used - readSample = NULL; // in this mode - break; - } - - if (numberFormat == NumberFormat_ASCII) - { - QObject::disconnect(&(this->serialPort), &QSerialPort::readyRead, 0, 0); - QObject::connect(&(this->serialPort), &QSerialPort::readyRead, - this, &MainWindow::onDataReadyASCII); - portControl.enableSkipByte(); - } - else - { - QObject::disconnect(&(this->serialPort), &QSerialPort::readyRead, 0, 0); - QObject::connect(&(this->serialPort), &QSerialPort::readyRead, - this, &MainWindow::onDataReady); - portControl.enableSkipByte(false); - } -} - -template double MainWindow::readSampleAs() -{ - T data; - this->serialPort.read((char*) &data, sizeof(data)); - - if (ui->rbLittleE->isChecked()) - { - data = qFromLittleEndian(data); - } - else - { - data = qFromBigEndian(data); - } - - return double(data); + spsLabel.setText(QString::number(sps) + "sps"); } bool MainWindow::isDemoRunning() @@ -592,37 +394,13 @@ bool MainWindow::isDemoRunning() return ui->actionDemoMode->isChecked(); } -void MainWindow::spsTimerTimeout() -{ - spsLabel.setText(QString::number(sampleCount/SPS_UPDATE_TIMEOUT) + "sps"); - sampleCount = 0; -} - -void MainWindow::demoTimerTimeout() -{ - const double period = 100; - demoCount++; - if (demoCount >= 100) demoCount = 0; - - if (!ui->actionPause->isChecked()) - { - for (unsigned int ci = 0; ci < numOfChannels; ci++) - { - // we are calculating the fourier components of square wave - double value = 4*sin(2*M_PI*double((ci+1)*demoCount)/period)/((2*(ci+1))*M_PI); - addChannelData(ci, &value, 1); - } - ui->plot->replot(); - } -} - void MainWindow::enableDemo(bool enabled) { if (enabled) { if (!serialPort.isOpen()) { - demoTimer.start(); + dataFormatPanel.enableDemo(true); ui->actionDemoMode->setChecked(true); demoIndicator.show(); ui->plot->replot(); @@ -634,7 +412,7 @@ void MainWindow::enableDemo(bool enabled } else { - demoTimer.stop(); + dataFormatPanel.enableDemo(false); ui->actionDemoMode->setChecked(false); demoIndicator.hide(); ui->plot->replot(); @@ -659,6 +437,7 @@ void MainWindow::onExportCsv() { QTextStream fileStream(&file); + unsigned numOfChannels = channelBuffers.size(); for (unsigned int ci = 0; ci < numOfChannels; ci++) { fileStream << "Channel " << ci; diff --git a/mainwindow.h b/mainwindow.h --- a/mainwindow.h +++ b/mainwindow.h @@ -36,6 +36,7 @@ #include "portcontrol.h" #include "commandpanel.h" +#include "dataformatpanel.h" #include "ui_about_dialog.h" #include "framebuffer.h" #include "snapshotmanager.h" @@ -56,20 +57,7 @@ public: const QString &msg); private: - enum NumberFormat - { - NumberFormat_uint8, - NumberFormat_uint16, - NumberFormat_uint32, - NumberFormat_int8, - NumberFormat_int16, - NumberFormat_int32, - NumberFormat_float, - NumberFormat_ASCII - }; - Ui::MainWindow *ui; - QButtonGroup numberFormatButtons; QDialog aboutDialog; void setupAboutDialog(); @@ -78,61 +66,35 @@ private: PortControl portControl; unsigned int numOfSamples; - unsigned int numOfChannels; QList curves; // Note: FrameBuffer s are owned by their respective QwtPlotCurve s. QList channelBuffers; - // `data` contains i th channels data - void addChannelData(unsigned int channel, double* data, unsigned size); - - NumberFormat numberFormat; - unsigned int sampleSize; // number of bytes in the selected number format - double (MainWindow::*readSample)(); - - // note that serialPort should already have enough bytes present - template double readSampleAs(); - - bool skipByteRequested; - - const int SPS_UPDATE_TIMEOUT = 1; // second QLabel spsLabel; - unsigned int sampleCount; - QTimer spsTimer; CommandPanel commandPanel; + DataFormatPanel dataFormatPanel; SnapshotManager snapshotMan; - // demo - QTimer demoTimer; - int demoCount; + QwtPlotTextLabel demoIndicator; bool isDemoRunning(); - QwtPlotTextLabel demoIndicator; private slots: void onPortToggled(bool open); - void onDataReady(); // used with binary number formats - void onDataReadyASCII(); // used with ASCII number format void onPortError(QSerialPort::SerialPortError error); - void skipByte(); - void onNumOfSamplesChanged(int value); void onAutoScaleChecked(bool checked); void onYScaleChanged(); void onRangeSelected(); - - void onNumOfChannelsChanged(int value); - void onNumberFormatButtonToggled(int numberFormatId, bool checked); - void selectNumberFormat(NumberFormat numberFormatId); + void onNumOfChannelsChanged(unsigned value); void clearPlot(); - void spsTimerTimeout(); + void onSpsChanged(unsigned sps); - void demoTimerTimeout(); void enableDemo(bool enabled); void onExportCsv(); diff --git a/mainwindow.ui b/mainwindow.ui --- a/mainwindow.ui +++ b/mainwindow.ui @@ -51,236 +51,6 @@ false - - - Data Format - - - - - - - - Number Of Channels: - - - - - - - - 60 - 0 - - - - false - - - 1 - - - 32 - - - - - - - - - Qt::Vertical - - - - - - - 0 - - - - - Number Format: - - - - - - unsigned 4 bytes integer - - - uint32 - - - - - - - signed 1 byte integer - - - int8 - - - - - - - unsigned 1 byte integer - - - uint8 - - - true - - - - - - - Comma Separated Values - - - ASCII(CSV) - - - - - - - signed 2 bytes integer - - - int16 - - - - - - - signed 4 bytes integer - - - int32 - - - - - - - 4 bytes floating point number - - - float - - - - - - - unsigned 2 bytes integer - - - uint16 - - - - - - - - - - Qt::Vertical - - - - 20 - 1 - - - - - - - - - - 0 - - - - - - 0 - 0 - - - - Byte Order: - - - - - - least significant byte first - - - Little Endian - - - true - - - - - - - most significant byte first - - - Big Endian - - - - - - - - - - Qt::Vertical - - - - 20 - 1 - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::MinimumExpanding - - - - 1 - 20 - - - - - - Plot diff --git a/serialplot.pro b/serialplot.pro --- a/serialplot.pro +++ b/serialplot.pro @@ -49,7 +49,8 @@ SOURCES += main.cpp\ plotsnapshotoverlay.cpp \ commandpanel.cpp \ commandwidget.cpp \ - commandedit.cpp + commandedit.cpp \ + dataformatpanel.cpp HEADERS += mainwindow.h \ utils.h \ @@ -68,14 +69,16 @@ HEADERS += mainwindow.h \ plotsnapshotoverlay.h \ commandpanel.h \ commandwidget.h \ - commandedit.h + commandedit.h \ + dataformatpanel.h FORMS += mainwindow.ui \ about_dialog.ui \ portcontrol.ui \ snapshotview.ui \ commandpanel.ui \ - commandwidget.ui + commandwidget.ui \ + dataformatpanel.ui INCLUDEPATH += qmake/