diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,6 +65,7 @@ qt5_wrap_ui(UI_FILES src/endiannessbox.ui src/binarystreamreadersettings.ui src/asciireadersettings.ui + src/framedreadersettings.ui ) if (WIN32) @@ -105,6 +106,8 @@ add_executable(${PROGRAM_NAME} WIN32 src/asciireader.cpp src/asciireadersettings.cpp src/demoreader.cpp + src/framedreader.cpp + src/framedreadersettings.cpp misc/windows_icon.rc ${UI_FILES} ${RES_FILES} diff --git a/serialplot.pro b/serialplot.pro --- a/serialplot.pro +++ b/serialplot.pro @@ -55,7 +55,17 @@ SOURCES += \ src/sneakylineedit.cpp \ src/channelmanager.cpp \ src/framebufferseries.cpp \ - src/plotcontrolpanel.cpp + src/plotcontrolpanel.cpp \ + src/numberformatbox.cpp \ + src/endiannessbox.cpp \ + src/framedreadersettings.cpp \ + src/abstractreader.cpp \ + src/binarystreamreader.cpp \ + src/binarystreamreadersettings.cpp \ + src/asciireadersettings.cpp \ + src/asciireader.cpp \ + src/demoreader.cpp \ + src/framedreader.cpp HEADERS += \ src/mainwindow.h \ @@ -81,7 +91,17 @@ HEADERS += \ src/sneakylineedit.h \ src/channelmanager.h \ src/framebufferseries.h \ - src/plotcontrolpanel.h + src/plotcontrolpanel.h \ + src/numberformatbox.h \ + src/endiannessbox.h \ + src/framedreadersettings.h \ + src/abstractreader.h \ + src/binarystreamreader.h \ + src/binarystreamreadersettings.h \ + src/asciireadersettings.h \ + src/asciireader.h \ + src/demoreader.h \ + src/framedreader.h FORMS += \ src/mainwindow.ui \ @@ -91,7 +111,12 @@ FORMS += \ src/commandpanel.ui \ src/commandwidget.ui \ src/dataformatpanel.ui \ - src/plotcontrolpanel.ui + src/plotcontrolpanel.ui \ + src/numberformatbox.ui \ + src/endiannessbox.ui \ + src/framedreadersettings.ui \ + src/binarystreamreadersettings.ui \ + src/asciireadersettings.ui INCLUDEPATH += qmake/ src/ diff --git a/src/dataformatpanel.cpp b/src/dataformatpanel.cpp --- a/src/dataformatpanel.cpp +++ b/src/dataformatpanel.cpp @@ -34,6 +34,7 @@ DataFormatPanel::DataFormatPanel(QSerial ui(new Ui::DataFormatPanel), bsReader(port, channelMan, this), asciiReader(port, channelMan, this), + framedReader(port, channelMan, this), demoReader(port, channelMan, this) { ui->setupUi(this); @@ -64,6 +65,11 @@ DataFormatPanel::DataFormatPanel(QSerial if (checked) selectReader(&asciiReader); }); + connect(ui->rbFramed, &QRadioButton::toggled, [this](bool checked) + { + if (checked) selectReader(&framedReader); + }); + // re-purpose numofchannels settings from actual reader settings to demo reader connect(this, &DataFormatPanel::numOfChannelsChanged, &demoReader, &DemoReader::setNumOfChannels); diff --git a/src/dataformatpanel.h b/src/dataformatpanel.h --- a/src/dataformatpanel.h +++ b/src/dataformatpanel.h @@ -32,6 +32,7 @@ #include "binarystreamreader.h" #include "asciireader.h" #include "demoreader.h" +#include "framedreader.h" namespace Ui { class DataFormatPanel; @@ -66,6 +67,7 @@ private: BinaryStreamReader bsReader; AsciiReader asciiReader; + FramedReader framedReader; /// Currently selected reader AbstractReader* currentReader; /// Disable current reader and enable a another one diff --git a/src/dataformatpanel.ui b/src/dataformatpanel.ui --- a/src/dataformatpanel.ui +++ b/src/dataformatpanel.ui @@ -34,6 +34,13 @@ + + + Framed + + + + Qt::Vertical diff --git a/src/framedreader.cpp b/src/framedreader.cpp new file mode 100644 --- /dev/null +++ b/src/framedreader.cpp @@ -0,0 +1,208 @@ +/* + Copyright © 2016 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 +#include +#include "floatswap.h" + +#include "framedreader.h" + +FramedReader::FramedReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) : + AbstractReader(device, channelMan, parent) +{ + paused = false; + + // initial settings + settingsInvalid = 0; + _numOfChannels = _settingsWidget.numOfChannels(); + hasFrameByte = _settingsWidget.frameSize() == 0; + frameSize = _settingsWidget.frameSize(); + syncWord = _settingsWidget.syncWord(); + checksumEnabled = _settingsWidget.checksumEnabled(); + onNumberFormatChanged(_settingsWidget.numberFormat()); + checkSettings(); + + connect(&_settingsWidget, &FramedReaderSettings::numberFormatChanged, + this, &FramedReader::onNumberFormatChanged); + + connect(&_settingsWidget, &FramedReaderSettings::numOfChannelsChanged, + this, &FramedReader::onNumOfChannelsChanged); + + connect(&_settingsWidget, &FramedReaderSettings::syncWordChanged, + this, &FramedReader::onSyncWordChanged); + + connect(&_settingsWidget, &FramedReaderSettings::frameSizeChanged, + this, &FramedReader::onFrameSizeChanged); + + connect(&_settingsWidget, &FramedReaderSettings::checksumChanged, + [this](bool enabled){checksumEnabled = enabled;}); +} + +void FramedReader::enable(bool enabled) +{ + if (enabled) + { + // TODO + // QObject::connect(_device, &QIODevice::readyRead, + // this, &BinaryStreamReader::onDataReady); + } + else + { + QObject::disconnect(_device, 0, this, 0); + } +} + +QWidget* FramedReader::settingsWidget() +{ + return &_settingsWidget; +} + +unsigned FramedReader::numOfChannels() +{ + return _numOfChannels; +} + +void FramedReader::pause(bool enabled) +{ + paused = enabled; +} + +void FramedReader::onNumberFormatChanged(NumberFormat numberFormat) +{ + switch(numberFormat) + { + case NumberFormat_uint8: + sampleSize = 1; + readSample = &FramedReader::readSampleAs; + break; + case NumberFormat_int8: + sampleSize = 1; + readSample = &FramedReader::readSampleAs; + break; + case NumberFormat_uint16: + sampleSize = 2; + readSample = &FramedReader::readSampleAs; + break; + case NumberFormat_int16: + sampleSize = 2; + readSample = &FramedReader::readSampleAs; + break; + case NumberFormat_uint32: + sampleSize = 4; + readSample = &FramedReader::readSampleAs; + break; + case NumberFormat_int32: + sampleSize = 4; + readSample = &FramedReader::readSampleAs; + break; + case NumberFormat_float: + sampleSize = 4; + readSample = &FramedReader::readSampleAs; + break; + } + + checkSettings(); +} + +template double FramedReader::readSampleAs() +{ + T data; + + _device->read((char*) &data, sizeof(data)); + + // TODO: checksum + + if (_settingsWidget.endianness() == LittleEndian) + { + data = qFromLittleEndian(data); + } + else + { + data = qFromBigEndian(data); + } + + return double(data); +} + +void FramedReader::checkSettings() +{ + // sync word is invalid (empty or missing a nibble at the end) + if (!syncWord.size()) + { + settingsInvalid |= SYNCWORD_INVALID; + } + else // sync word is valid + { + settingsInvalid &= ~SYNCWORD_INVALID; + } + + // check if fixed frame size is multiple of a sample set size + if (!hasFrameByte && frameSize % (_numOfChannels * sampleSize) != 0) + { + settingsInvalid |= FRAMESIZE_INVALID; + } + else + { + settingsInvalid &= ~FRAMESIZE_INVALID; + } + + // show an error message + if (settingsInvalid & SYNCWORD_INVALID) + { + _settingsWidget.showMessage("Sync word is invalid!", true); + } + else if (settingsInvalid & FRAMESIZE_INVALID) + { + QString errorMessage = + QString("Frame size must be multiple of %1 (#channels * sample size)!")\ + .arg(_numOfChannels * sampleSize); + + _settingsWidget.showMessage(errorMessage, true); + } + else + { + _settingsWidget.showMessage("All is well!"); + } +} + +void FramedReader::onNumOfChannelsChanged(unsigned value) +{ + _numOfChannels = value; + checkSettings(); +} + +void FramedReader::onSyncWordChanged(QByteArray word) +{ + syncWord = word; + checkSettings(); +} + +void FramedReader::onFrameSizeChanged(unsigned value) +{ + if (value == 0) + { + hasFrameByte = true; + } + else + { + hasFrameByte = false; + frameSize = value; + } + checkSettings(); +} diff --git a/src/framedreader.h b/src/framedreader.h new file mode 100644 --- /dev/null +++ b/src/framedreader.h @@ -0,0 +1,82 @@ +/* + Copyright © 2016 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 FRAMEDREADER_H +#define FRAMEDREADER_H + +#include "abstractreader.h" +#include "framedreadersettings.h" + +/** + * Reads data in a customizable framed format. + */ +class FramedReader : public AbstractReader +{ + Q_OBJECT + +public: + explicit FramedReader(QIODevice* device, ChannelManager* channelMan, QObject *parent = 0); + QWidget* settingsWidget(); + unsigned numOfChannels(); + void enable(bool enabled = true); + +public slots: + void pause(bool); + +private: + /// bit wise fields for `settingsValid` member + enum SettingInvalidFlag + { + SYNCWORD_INVALID = 1, + FRAMESIZE_INVALID = 2 + }; + + FramedReaderSettings _settingsWidget; + unsigned _numOfChannels; + unsigned sampleSize; + bool paused; + unsigned settingsInvalid; /// settings are all valid if this is 0, if not no reading is done + QByteArray syncWord; + bool checksumEnabled; + bool hasFrameByte; + unsigned frameSize; + + // TODO: create a base class that contains common functionality between binary readers + + /// points to the readSampleAs function for currently selected number format + double (FramedReader::*readSample)(); + template double readSampleAs(); + // `data` contains i th channels data + void addChannelData(unsigned int channel, double* data, unsigned size); + + /// Checks the validity of syncWord and frameSize then shows an + /// error message. Also updates `settingsInvalid`. If settings are + /// valid `settingsInvalid` should be `0`. + void checkSettings(); + +private slots: + // void onDataReady(); + + void onNumberFormatChanged(NumberFormat numberFormat); + void onNumOfChannelsChanged(unsigned value); + void onSyncWordChanged(QByteArray); + void onFrameSizeChanged(unsigned); +}; + +#endif // FRAMEDREADER_H diff --git a/src/framedreadersettings.cpp b/src/framedreadersettings.cpp new file mode 100644 --- /dev/null +++ b/src/framedreadersettings.cpp @@ -0,0 +1,137 @@ +/* + Copyright © 2016 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 "utils.h" +#include "framedreadersettings.h" +#include "ui_framedreadersettings.h" + +FramedReaderSettings::FramedReaderSettings(QWidget *parent) : + QWidget(parent), + ui(new Ui::FramedReaderSettings) +{ + ui->setupUi(this); + + ui->leSyncWord->setMode(false); // hex mode + + connect(ui->cbChecksum, &QCheckBox::toggled, + [this](bool enabled) + { + emit checksumChanged(enabled); + }); + + connect(ui->rbFixedSize, &QRadioButton::toggled, + ui->spSize, &QWidget::setEnabled); + + connect(ui->rbFixedSize, &QRadioButton::toggled, + [this](bool checked) + { + emit frameSizeChanged(frameSize()); + }); + + // Note: if directly connected we get a runtime warning on incompatible signal arguments + connect(ui->spSize, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged), + [this](int value) + { + emit frameSizeChanged(value); + }); + + connect(ui->spNumOfChannels, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged), + [this](int value) + { + emit numOfChannelsChanged(value); + }); + + connect(ui->leSyncWord, &QLineEdit::textChanged, + this, &FramedReaderSettings::onSyncWordEdited); + + connect(ui->nfBox, SIGNAL(selectionChanged(NumberFormat)), + this, SIGNAL(numberFormatChanged(NumberFormat))); +} + +FramedReaderSettings::~FramedReaderSettings() +{ + delete ui; +} + +void FramedReaderSettings::showMessage(QString message, bool error) +{ + ui->lMessage->setText(message); + if (error) + { + ui->lMessage->setStyleSheet("color: red;"); + } + else + { + ui->lMessage->setStyleSheet(""); + } +} + +unsigned FramedReaderSettings::numOfChannels() +{ + return ui->spNumOfChannels->value(); +} + +NumberFormat FramedReaderSettings::numberFormat() +{ + return ui->nfBox->currentSelection(); +} + +Endianness FramedReaderSettings::endianness() +{ + return ui->endiBox->currentSelection(); +} + +QByteArray FramedReaderSettings::syncWord() +{ + QString text = ui->leSyncWord->text().remove(' '); + + // check if nibble is missing + if (text.size() % 2 == 1) + { + // TODO: remove this warning + return QByteArray(); + } + else + { + return QByteArray::fromHex(text.toLatin1()); + } +} + +void FramedReaderSettings::onSyncWordEdited() +{ + // TODO: emit with a delay so that error message doesn't flash! + emit syncWordChanged(syncWord()); +} + +unsigned FramedReaderSettings::frameSize() +{ + if (ui->rbFixedSize->isChecked()) + { + return ui->spSize->value(); + } + else + { + return 0; // frame byte is enabled + } +} + +bool FramedReaderSettings::checksumEnabled() +{ + return ui->cbChecksum->isChecked(); +} diff --git a/src/framedreadersettings.h b/src/framedreadersettings.h new file mode 100644 --- /dev/null +++ b/src/framedreadersettings.h @@ -0,0 +1,67 @@ +/* + Copyright © 2016 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 FRAMEDREADERSETTINGS_H +#define FRAMEDREADERSETTINGS_H + +#include +#include + +#include "numberformatbox.h" +#include "endiannessbox.h" + +namespace Ui { +class FramedReaderSettings; +} + +class FramedReaderSettings : public QWidget +{ + Q_OBJECT + +public: + explicit FramedReaderSettings(QWidget *parent = 0); + ~FramedReaderSettings(); + + void showMessage(QString message, bool error = false); + + unsigned numOfChannels(); + NumberFormat numberFormat(); + Endianness endianness(); + QByteArray syncWord(); + unsigned frameSize(); /// If frame bye is enabled `0` is returned + bool checksumEnabled(); + +signals: + /// If sync word is invalid (empty or 1 nibble missing at the end) + /// signaled with an empty array + void syncWordChanged(QByteArray); + /// `0` indicates frame size byte is enabled + void frameSizeChanged(unsigned); + void checksumChanged(bool); + void numOfChannelsChanged(unsigned); + void numberFormatChanged(NumberFormat); + +private: + Ui::FramedReaderSettings *ui; + +private slots: + void onSyncWordEdited(); +}; + +#endif // FRAMEDREADERSETTINGS_H diff --git a/src/framedreadersettings.ui b/src/framedreadersettings.ui new file mode 100644 --- /dev/null +++ b/src/framedreadersettings.ui @@ -0,0 +1,176 @@ + + + FramedReaderSettings + + + + 0 + 0 + 542 + 222 + + + + Form + + + + + 210 + 40 + 141 + 141 + + + + + + + 360 + 40 + 120 + 80 + + + + + + + 210 + 0 + 211 + 29 + + + + + + + Number Of Channels: + + + + + + + 1 + + + 32 + + + + + + + + + 0 + 180 + 471 + 17 + + + + All is well. + + + + + + 1 + 39 + 204 + 93 + + + + Frame Size: + + + + + + + + Fixed Size: + + + + + + + false + + + 1 + + + 255 + + + + + + + + + First byte of frame is size + + + true + + + + + + + + + + + Sync Word: + + + + + + + + + + + + 1 + 138 + 123 + 22 + + + + Checksum Byte + + + + + + NumberFormatBox + QWidget +
numberformatbox.h
+ 1 +
+ + EndiannessBox + QWidget +
endiannessbox.h
+ 1 +
+ + CommandEdit + QLineEdit +
commandedit.h
+
+
+ + +