diff --git a/src/binarystreamreader.cpp b/src/binarystreamreader.cpp new file mode 100644 --- /dev/null +++ b/src/binarystreamreader.cpp @@ -0,0 +1,190 @@ +/* + 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 "binarystreamreader.h" +#include "floatswap.h" + +BinaryStreamReader::BinaryStreamReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) : + AbstractReader(device, channelMan, parent) +{ + paused = false; + skipByteRequested = false; + sampleCount = 0; + + _numOfChannels = _settingsWidget.numOfChannels(); + connect(&_settingsWidget, &BinaryStreamReaderSettings::numOfChannelsChanged, + this, &BinaryStreamReader::numOfChannelsChanged); + connect(&_settingsWidget, &BinaryStreamReaderSettings::numOfChannelsChanged, + this, &BinaryStreamReader::onNumOfChannelsChanged); + + // initial number format selection + onNumberFormatChanged(_settingsWidget.numberFormat()); + connect(&_settingsWidget, &BinaryStreamReaderSettings::numberFormatChanged, + this, &BinaryStreamReader::onNumberFormatChanged); + + // enable skip byte button + connect(&_settingsWidget, &BinaryStreamReaderSettings::skipByteRequested, + [this]() + { + skipByteRequested = true; + }); +} + +QWidget* BinaryStreamReader::settingsWidget() +{ + return &_settingsWidget; +} + +unsigned BinaryStreamReader::numOfChannels() +{ + return _numOfChannels; +} + +void BinaryStreamReader::enable(bool enabled) +{ + if (enabled) + { + QObject::connect(_device, &QIODevice::readyRead, + this, &BinaryStreamReader::onDataReady); + } + else + { + QObject::disconnect(_device, 0, this, 0); + } +} + +void BinaryStreamReader::pause(bool enabled) +{ + paused = enabled; +} + +void BinaryStreamReader::onNumberFormatChanged(NumberFormat numberFormat) +{ + switch(numberFormat) + { + case NumberFormat_uint8: + sampleSize = 1; + readSample = &BinaryStreamReader::readSampleAs; + break; + case NumberFormat_int8: + sampleSize = 1; + readSample = &BinaryStreamReader::readSampleAs; + break; + case NumberFormat_uint16: + sampleSize = 2; + readSample = &BinaryStreamReader::readSampleAs; + break; + case NumberFormat_int16: + sampleSize = 2; + readSample = &BinaryStreamReader::readSampleAs; + break; + case NumberFormat_uint32: + sampleSize = 4; + readSample = &BinaryStreamReader::readSampleAs; + break; + case NumberFormat_int32: + sampleSize = 4; + readSample = &BinaryStreamReader::readSampleAs; + break; + case NumberFormat_float: + sampleSize = 4; + readSample = &BinaryStreamReader::readSampleAs; + break; + } +} + +void BinaryStreamReader::onNumOfChannelsChanged(unsigned value) +{ + _numOfChannels = value; +} + +void BinaryStreamReader::onDataReady() +{ + // a package is a set of channel data like {CHAN0_SAMPLE, CHAN1_SAMPLE...} + int packageSize = sampleSize * _numOfChannels; + int bytesAvailable = _device->bytesAvailable(); + int numOfPackagesToRead = + (bytesAvailable - (bytesAvailable % packageSize)) / packageSize; + + if (paused) + { + // read and discard data + _device->read(numOfPackagesToRead*packageSize); + return; + } + + if (bytesAvailable > 0 && skipByteRequested) + { + _device->read(1); + skipByteRequested = false; + bytesAvailable--; + } + + if (bytesAvailable < packageSize) return; + + double* channelSamples = new double[numOfPackagesToRead*_numOfChannels]; + + for (int i = 0; i < numOfPackagesToRead; i++) + { + for (unsigned int ci = 0; ci < _numOfChannels; ci++) + { + // channelSamples[ci].replace(i, (this->*readSample)()); + channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)(); + } + } + + for (unsigned int ci = 0; ci < _numOfChannels; ci++) + { + addChannelData(ci, + channelSamples + ci*numOfPackagesToRead, + numOfPackagesToRead); + } + emit dataAdded(); + + delete channelSamples; +} + + +template double BinaryStreamReader::readSampleAs() +{ + T data; + + _device->read((char*) &data, sizeof(data)); + + if (_settingsWidget.endianness() == LittleEndian) + { + data = qFromLittleEndian(data); + } + else + { + data = qFromBigEndian(data); + } + + return double(data); +} + +void BinaryStreamReader::addChannelData(unsigned int channel, + double* data, unsigned size) +{ + _channelMan->addChannelData(channel, data, size); + sampleCount += size; +}