Changeset - 8bc730cfda45
[Not reviewed]
default
0 4 0
Hasan Yavuz Ă–ZDERYA - 10 years ago 2015-08-15 13:17:08
hy@ozderya.net
use simple double array instead of QVector for FrameBuffer interface
4 files changed with 17 insertions and 18 deletions:
0 comments (0 inline, 0 general)
framebuffer.cpp
Show inline comments
 
@@ -41,51 +41,51 @@ void FrameBuffer::resize(size_t size)
 
    // move data to new array
 
    int fill_start = offset > 0 ? offset : 0;
 

	
 
    for (int i = fill_start; i < int(size); i++)
 
    {
 
        newData[i] = _sample(i - offset);
 
    }
 

	
 
    // fill the beginning of the new data
 
    if (fill_start > 0)
 
    {
 
        for (int i = 0; i < fill_start; i++)
 
        {
 
            newData[i] = 0;
 
        }
 
    }
 

	
 
    // data is ready, clean and re-point
 
    delete data;
 
    data = newData;
 
    headIndex = 0;
 
    _size = size;
 
}
 

	
 
void FrameBuffer::addSamples(QVector<double> samples)
 
void FrameBuffer::addSamples(double* samples, size_t size)
 
{
 
    unsigned shift = samples.size();
 
    unsigned shift = size;
 
    if (shift < _size)
 
    {
 
        unsigned x = _size - headIndex; // distance of `head` to end
 

	
 
        if (shift <= x) // there is enough room at the end of array
 
        {
 
            for (size_t i = 0; i < shift; i++)
 
            {
 
                data[i+headIndex] = samples[i];
 
            }
 

	
 
            if (shift == x) // we used all the room at the end
 
            {
 
                headIndex = 0;
 
            }
 
            else
 
            {
 
                headIndex += shift;
 
            }
 
        }
 
        else // there isn't enough room
 
        {
 
            for (size_t i = 0; i < x; i++) // fill the end part
 
            {
framebuffer.h
Show inline comments
 
@@ -10,41 +10,41 @@
 

	
 
  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 <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef FRAMEBUFFER_H
 
#define FRAMEBUFFER_H
 

	
 
#include <qwt_series_data.h>
 
#include <QPointF>
 
#include <QRectF>
 

	
 
class FrameBuffer : public QwtSeriesData<QPointF>
 
{
 
public:
 
    FrameBuffer(size_t size);
 
    ~FrameBuffer();
 

	
 
    void resize(size_t size);
 
    void addSamples(QVector<double> samples);
 
    void addSamples(double* samples, size_t size);
 
    void clear(); // fill 0
 

	
 
    // QwtSeriesData implementations
 
    size_t size() const;
 
    QPointF sample(size_t i) const;
 
    QRectF boundingRect() const;
 

	
 
private:
 
    size_t _size; // size of `data`
 
    double* data;
 
    size_t headIndex; // indicates the actual `0` index of the ring buffer
 

	
 
    double _sample(size_t i) const;
 
};
 

	
 
#endif // FRAMEBUFFER_H
mainwindow.cpp
Show inline comments
 
@@ -234,104 +234,105 @@ void MainWindow::onPortToggled(bool 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;
 
    QVector<DataArray> channelSamples(numOfChannels);
 
    for (unsigned int ci = 0; ci < numOfChannels; ci++)
 
    {
 
        channelSamples[ci].resize(numOfPackagesToRead);
 
    }
 
    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].replace(i, (this->*readSample)());
 
            channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)();
 
        }
 
        i++;
 
    }
 

	
 
    for (unsigned int ci = 0; ci < numOfChannels; ci++)
 
    {
 
        addChannelData(ci, channelSamples[ci]);
 
        addChannelData(ci,
 
                       channelSamples + ci*numOfPackagesToRead,
 
                       numOfPackagesToRead);
 
    }
 

	
 
    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, DataArray({channelSample}));
 
                addChannelData(ci, &channelSample, 1);
 
            }
 
            else
 
            {
 
                qWarning() << "Data parsing error for channel: " << ci;
 
            }
 
        }
 
    }
 
}
 

	
 
void MainWindow::onPortError(QSerialPort::SerialPortError error)
 
{
 
    switch(error)
 
    {
 
        case QSerialPort::NoError :
 
            break;
 
        case QSerialPort::ResourceError :
 
            qWarning() << "Port error: resource unavaliable; most likely device removed.";
 
            if (serialPort.isOpen())
 
            {
 
                qWarning() << "Closing port on resource error: " << serialPort.portName();
 
                portControl.togglePort();
 
            }
 
            portControl.loadPortList();
 
            break;
 
@@ -362,53 +363,53 @@ required privileges or device is already
 
            break;
 
        case QSerialPort::ReadError:
 
            qCritical() << "An error occurred while reading data.";
 
            break;
 
        case QSerialPort::UnsupportedOperationError:
 
            qCritical() << "Operation is not supported.";
 
            break;
 
        case QSerialPort::TimeoutError:
 
            qCritical() << "A timeout error occurred.";
 
            break;
 
        case QSerialPort::UnknownError:
 
            qCritical() << "Unknown error!";
 
            break;
 
        default:
 
            qCritical() << "Unhandled port error: " << error;
 
            break;
 
    }
 
}
 

	
 
void MainWindow::skipByte()
 
{
 
    skipByteRequested = true;
 
}
 

	
 
void MainWindow::addChannelData(unsigned int channel, DataArray data)
 
void MainWindow::addChannelData(unsigned int channel, double* data, unsigned size)
 
{
 
    channelBuffers[channel]->addSamples(data);
 
    channelBuffers[channel]->addSamples(data, size);
 
    ui->plot->replot(); // TODO: replot after all channel data updated
 
    sampleCount += data.size();
 
    sampleCount += size;
 
}
 

	
 
void MainWindow::clearPlot()
 
{
 
    for (unsigned int ci = 0; ci < numOfChannels; ci++)
 
    {
 
        channelBuffers[ci]->clear();
 
    }
 
    ui->plot->replot();
 
}
 

	
 
void MainWindow::onNumOfSamplesChanged(int value)
 
{
 
    numOfSamples = value;
 

	
 
    for (unsigned int ci = 0; ci < numOfChannels; ci++)
 
    {
 
        channelBuffers[ci]->resize(numOfSamples);
 
    }
 

	
 
    ui->plot->replot();
 
}
 

	
 
void MainWindow::onNumOfChannelsChanged(int value)
 
@@ -544,53 +545,51 @@ template<typename T> double MainWindow::
 
    return double(data);
 
}
 

	
 
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++)
 
        {
 
            DataArray data(1);
 
            // 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);
 
            data.replace(0, value);
 
            addChannelData(ci, data);
 
            addChannelData(ci, &value, 1);
 
        }
 
    }
 
}
 

	
 
void MainWindow::enableDemo(bool enabled)
 
{
 
    if (enabled)
 
    {
 
        if (!serialPort.isOpen())
 
        {
 
            demoTimer.start();
 
            ui->actionDemoMode->setChecked(true);
 
            demoIndicator.show();
 
            ui->plot->replot();
 
        }
 
        else
 
        {
 
            ui->actionDemoMode->setChecked(false);
 
        }
 
    }
 
    else
 
    {
 
        demoTimer.stop();
 
        ui->actionDemoMode->setChecked(false);
mainwindow.h
Show inline comments
 
@@ -63,49 +63,49 @@ private:
 
        NumberFormat_int16,
 
        NumberFormat_int32,
 
        NumberFormat_float,
 
        NumberFormat_ASCII
 
    };
 

	
 
    Ui::MainWindow *ui;
 
    QButtonGroup numberFormatButtons;
 

	
 
    QDialog aboutDialog;
 
    void setupAboutDialog();
 

	
 
    QSerialPort serialPort;
 
    PortControl portControl;
 

	
 
    unsigned int numOfSamples;
 
    unsigned int numOfChannels;
 

	
 
    QList<QwtPlotCurve*> curves;
 
    typedef QVector<double> DataArray;
 
    // Note: FrameBuffer s are owned by their respective QwtPlotCurve s.
 
    QList<FrameBuffer*> channelBuffers;
 

	
 
    // `data` contains i th channels data
 
    void addChannelData(unsigned int channel, DataArray 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<typename T> double readSampleAs();
 

	
 
    bool skipByteRequested;
 

	
 
    const int SPS_UPDATE_TIMEOUT = 1;  // second
 
    QLabel spsLabel;
 
    unsigned int sampleCount;
 
    QTimer spsTimer;
 

	
 
    // demo
 
    QTimer demoTimer;
 
    int demoCount;
 
    bool isDemoRunning();
 
    QwtPlotTextLabel demoIndicator;
 

	
 
    QColor makeColor(unsigned int channelIndex);
 

	
 
private slots:
0 comments (0 inline, 0 general)