Changeset - 5c0005f331cf
[Not reviewed]
stream
0 13 2
Hasan Yavuz ÖZDERYA - 8 years ago 2018-02-24 14:14:27
hy@ozderya.net
various fixes to get stream to compile and some basic tests
15 files changed with 255 insertions and 116 deletions:
0 comments (0 inline, 0 general)
src/channelinfomodel.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -336,7 +336,7 @@ void ChannelInfoModel::resetVisibility()
 
    endResetModel();
 
}
 

	
 
void ChannelInfoModel::saveSettings(QSettings* settings)
 
void ChannelInfoModel::saveSettings(QSettings* settings) const
 
{
 
    settings->beginGroup(SettingGroup_Channels);
 
    settings->beginWriteArray(SG_Channels_Channel);
src/channelinfomodel.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -57,7 +57,7 @@ public:
 

	
 
    void setNumOfChannels(unsigned number);
 
    /// Stores all channel info into a `QSettings`
 
    void saveSettings(QSettings* settings);
 
    void saveSettings(QSettings* settings) const;
 
    /// Loads all channel info from a `QSettings`.
 
    void loadSettings(QSettings* settings);
 

	
src/framebuffer2.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -45,6 +45,7 @@ public:
 
/// Common base class for index and writable frame buffers
 
class ResizableBuffer : public FrameBuffer
 
{
 
public:
 
    /// Resize the buffer.
 
    ///
 
    /// @important Resizing to same value is an error.
src/samplepack.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -76,3 +76,13 @@ double* SamplePack::data(unsigned channe
 

	
 
    return &_yData[channel * _numSamples];
 
}
 

	
 
double* SamplePack::xData()
 
{
 
    return const_cast<double*>(static_cast<const SamplePack&>(*this).xData());
 
}
 

	
 
double* SamplePack::data(unsigned channel)
 
{
 
    return const_cast<double*>(static_cast<const SamplePack&>(*this).data(channel));
 
}
src/samplepack.h
Show inline comments
 
@@ -32,6 +32,9 @@ public:
 
    double* xData() const;
 
    double* data(unsigned channel) const;
 

	
 
    double* xData();
 
    double* data(unsigned channel);
 

	
 
private:
 
    unsigned _numSamples, _numChannels;
 
    double* _xData;
src/sink.h
Show inline comments
 
@@ -30,12 +30,15 @@ class Sink
 
public:
 
    /// Placeholder virtual destructor
 
    virtual ~Sink() {};
 

	
 
    /// Connects a sink to get any data that this sink
 
    /// gets. Connecting an already connected sink is an error.
 
    void connectFollower(Sink* sink);
 

	
 
    /// Disconnects a follower. Disconnecting an unconnected sink is
 
    /// an error.
 
    void disconnectFollower(Sink* sink);
 

	
 
    /// Returns the connected source. `NULL` if it's not connected.
 
    const Source* connectedSource() const;
 

	
 
@@ -43,9 +46,11 @@ protected:
 
    /// Entry point for incoming data. Re-implementations should
 
    /// call this function to feed followers.
 
    virtual void feedIn(const SamplePack& data);
 

	
 
    /// Is set by connected source. Re-implementations should call
 
    /// this function to update followers.
 
    virtual void setNumChannels(unsigned nc, bool x);
 

	
 
    /// Set by the connected source when its connected. When
 
    /// disconnecting it's set to `NULL`.
 
    ///
src/source.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -21,6 +21,14 @@
 

	
 
#include "source.h"
 

	
 
Source::~Source()
 
{
 
    for (auto sink : sinks)
 
    {
 
        sink->setSource(NULL);
 
    }
 
}
 

	
 
void Source::connect(Sink* sink)
 
{
 
    Q_ASSERT(!sinks.contains(sink));
src/source.h
Show inline comments
 
@@ -28,16 +28,19 @@
 
class Source
 
{
 
public:
 
    /// Placeholder virtual destructor
 
    virtual ~Source() {};
 
    /// Virtual destructor. Must be called by implementors to notify sinks.
 
    virtual ~Source();
 

	
 
    /// Returns true if source has X data
 
    virtual bool hasX() const = 0;
 

	
 
    /// Returns number of channels
 
    virtual unsigned numChannels() const = 0;
 

	
 
    /// Connects a sink to this source. Trying to connect an already
 
    /// connected sink is an error.
 
    void connect(Sink* sink);
 

	
 
    /// Disconnects an already connected sink. Trying to disconnect an
 
    /// unconnected sink is an error.
 
    void disconnect(Sink* sink);
 
@@ -45,6 +48,7 @@ public:
 
protected:
 
    /// Feeds "in" given data to connected sinks
 
    void feedOut(const SamplePack& data) const;
 

	
 
    /// Updates "number of channels" of connected sinks. Must be
 
    /// called when num. channels or hasX changes.
 
    void updateNumChannels() const;
src/stream.cpp
Show inline comments
 
@@ -19,6 +19,7 @@
 

	
 
#include "stream.h"
 
#include "ringbuffer.h"
 
#include "indexbuffer.h"
 

	
 
Stream::Stream(unsigned nc, bool x, unsigned ns) :
 
    _infoModel(nc)
 
@@ -56,7 +57,7 @@ bool Stream::hasX() const
 
    return _hasx;
 
}
 

	
 
unsigned Stream::numChannels()
 
unsigned Stream::numChannels() const
 
{
 
    return channels.length();
 
}
 
@@ -72,52 +73,57 @@ const StreamChannel* Stream::channel(uns
 
    return channels[index];
 
}
 

	
 
StreamChannel* Stream::channel(unsigned index)
 
{
 
    return const_cast<StreamChannel*>(static_cast<const Stream&>(*this).channel(index));
 
}
 

	
 
void Stream::setNumChannels(unsigned nc, bool x)
 
{
 
    unsigned oldNum = numChannels();
 
    if (oldNum == nc && x == _hasX) return;
 
    if (oldNum == nc && x == _hasx) return;
 

	
 
    // adjust the number of channels
 
    if (nc > oldNum)
 
    {
 
        for (int i = oldNum; i < nc; i++)
 
        for (unsigned i = oldNum; i < nc; i++)
 
        {
 
            auto c = new StreamChannel(i, xData, new RingBuffer(ns), &_infoModel);
 
            auto c = new StreamChannel(i, xData, new RingBuffer(_numSamples), &_infoModel);
 
            channels.append(c);
 
        }
 
    }
 
    else if (nc < oldNum)
 
    {
 
        for (int i = oldNum-1; i > nc-1; i--)
 
        for (unsigned i = oldNum-1; i > nc-1; i--)
 
        {
 
            delete channels.takeLast();
 
        }
 
    }
 

	
 
    // change the xdata
 
    if (x != _hasX)
 
    if (x != _hasx)
 
    {
 
        if (x)
 
        {
 
            xData = new RingBuffer(ns);
 
            xData = new RingBuffer(_numSamples);
 
        }
 
        else
 
        {
 
            xData = new IndexBuffer(ns);
 
            xData = new IndexBuffer(_numSamples);
 
        }
 

	
 
        for (auto c : channels)
 
        {
 
            c.setX(xData);
 
            c->setX(xData);
 
        }
 
        _hasX = x;
 
        _hasx = x;
 
    }
 

	
 
    if (nc != oldNum)
 
    {
 
        _infoModel.setNumChannels(nc);
 
        _infoModel.setNumOfChannels(nc);
 
        // TODO: how abut X change?
 
        emit numOfChannelsChanged(nc);
 
        emit numChannelsChanged(nc);
 
    }
 

	
 
    Sink::setNumChannels(nc, x);
 
@@ -131,13 +137,13 @@ void Stream::feedIn(const SamplePack& da
 
    if (_paused) return;
 

	
 
    unsigned ns = data.numSamples();
 
    if (_hasX)
 
    if (_hasx)
 
    {
 
        xData.addSamples(data.xData(), ns);
 
        static_cast<RingBuffer*>(xData)->addSamples(data.xData(), ns);
 
    }
 
    for (unsigned i = 0; i < numChannels(); i++)
 
    {
 
        channels[i].yData()->addSamples(data.data(i), ns);
 
        static_cast<RingBuffer*>(channels[i]->yData())->addSamples(data.data(i), ns);
 
    }
 

	
 
    Sink::feedIn(data);
 
@@ -153,10 +159,10 @@ void Stream::setNumSamples(unsigned valu
 
    if (value == _numSamples) return;
 
    _numSamples = value;
 

	
 
    xData.resize(value);
 
    xData->resize(value);
 
    for (auto c : channels)
 
    {
 
        channels[i].yData()->resize(value);
 
        static_cast<RingBuffer*>(c->yData())->resize(value);
 
    }
 
}
 

	
src/stream.h
Show inline comments
 
@@ -29,21 +29,23 @@
 
#include "source.h"
 
#include "channelinfomodel.h"
 
#include "streamchannel.h"
 
#include "resizablebuffer.h"
 
#include "framebuffer2.h"
 

	
 
/**
 
 * Main waveform storage class. It consists of channels. Channels are
 
 * synchronized with each other.
 
 *
 
 * Implements `Sink` class for data entry. It's expected to be
 
 * connected to a `Device` source. Also implements a `Source` class
 
 * for data that exists the buffers.
 
 * connected to a `Device` source.
 
 */
 
class Stream : public Sink, public QObject
 
class Stream : public QObject, public Sink
 
{
 
    Q_OBJECT
 

	
 
public:
 
    /**
 
     * @param nc number of channels
 
     * @param x has X data input
 
     * @param ns number of samples
 
     */
 
    Stream(unsigned nc = 0, bool x = false, unsigned ns = 0);
 
@@ -51,10 +53,11 @@ public:
 

	
 
    // implementations for `Source`
 
    virtual bool hasX() const;
 
    virtual unsigned numChannels();
 
    virtual unsigned numChannels() const;
 

	
 
    unsigned numSamples() const;
 
    const StreamChannel* channel(unsigned index) const;
 
    StreamChannel* channel(unsigned index);
 

	
 
    /// Saves channel information
 
    void saveSettings(QSettings* settings) const;
 
@@ -75,7 +78,7 @@ signals:
 

	
 
public slots:
 
    // TODO: these won't be public
 
    void setNumChannels(unsigned number);
 
    // void setNumChannels(unsigned number);
 
    void setNumSamples(unsigned value);
 

	
 
    /// When paused data feed is ignored
src/streamchannel.cpp
Show inline comments
 
@@ -34,11 +34,11 @@ StreamChannel::~StreamChannel()
 
}
 

	
 
unsigned StreamChannel::index() const {return _index;}
 
QString StreamChannel::name() const {return _info->name(_index)};
 
QColor StreamChannel::color() const {return _info->color(_index)};
 
bool StreamChannel::visible() const {return _info->isVisible(_index)};
 
QString StreamChannel::name() const {return _info->name(_index);};
 
QColor StreamChannel::color() const {return _info->color(_index);};
 
bool StreamChannel::visible() const {return _info->isVisible(_index);};
 
const FrameBuffer* StreamChannel::xData() const {return _x;}
 
const FrameBuffer* StreamChannel::yData() const {return _y;}
 
FrameBuffer* StreamChannel::yData() {return _y;}
 
const ChannelInfoModel* StreamChannel::info() const {return _info;}
 
void StreamChannel::setX(const FrameBuffer* x) {_x = x};
 
void StreamChannel::setX(const FrameBuffer* x) {_x = x;};
tests/CMakeLists.txt
Show inline comments
 
#
 
# Copyright © 2017 Hasan Yavuz Özderya
 
# Copyright © 2018 Hasan Yavuz Özderya
 
#
 
# This file is part of serialplot.
 
#
 
@@ -24,6 +24,7 @@ include_directories("../src")
 

	
 
add_executable(Test EXCLUDE_FROM_ALL
 
  test.cpp
 
  test_stream.cpp
 
  ../src/samplepack.cpp
 
  ../src/sink.cpp
 
  ../src/source.cpp
 
@@ -31,6 +32,9 @@ add_executable(Test EXCLUDE_FROM_ALL
 
  ../src/linindexbuffer.cpp
 
  ../src/ringbuffer.cpp
 
  ../src/readonlybuffer.cpp
 
  ../src/stream.cpp
 
  ../src/streamchannel.cpp
 
  ../src/channelinfomodel.cpp
 
  )
 
add_test(NAME test1 COMMAND Test)
 
qt5_use_modules(Test Widgets)
tests/test.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -27,6 +27,8 @@
 
#include "ringbuffer.h"
 
#include "readonlybuffer.h"
 

	
 
#include "test_helpers.h"
 

	
 
TEST_CASE("samplepack with no X", "[memory]")
 
{
 
    SamplePack pack(100, 3, false);
 
@@ -53,48 +55,6 @@ TEST_CASE("samplepack with X", "[memory]
 
    REQUIRE(pack.xData() != nullptr);
 
}
 

	
 
class TestSink : public Sink
 
{
 
public:
 
    int totalFed;
 
    int _numChannels;
 
    bool _hasX;
 

	
 
    TestSink()
 
        {
 
            totalFed = 0;
 
            _numChannels = 0;
 
            _hasX = false;
 
        };
 

	
 
    void feedIn(const SamplePack& data)
 
        {
 
            REQUIRE(data.numChannels() == numChannels());
 

	
 
            totalFed += data.numSamples();
 

	
 
            Sink::feedIn(data);
 
        };
 

	
 
    void setNumChannels(unsigned nc, bool x)
 
        {
 
            _numChannels = nc;
 
            _hasX = x;
 

	
 
            Sink::setNumChannels(nc, x);
 
        };
 

	
 
    virtual unsigned numChannels() const
 
        {
 
            return _numChannels;
 
        };
 

	
 
    virtual bool hasX() const
 
        {
 
            return _hasX;
 
        };
 
};
 

	
 
TEST_CASE("sink", "[memory, stream]")
 
{
 
    TestSink sink;
 
@@ -129,42 +89,6 @@ TEST_CASE("sink must be created unconnec
 
    REQUIRE(sink.connectedSource() == NULL);
 
}
 

	
 
class TestSource : public Source
 
{
 
public:
 
    int _numChannels;
 
    bool _hasX;
 

	
 
    TestSource(unsigned nc, bool x)
 
        {
 
            _numChannels = nc;
 
            _hasX = x;
 
        };
 

	
 
    virtual unsigned numChannels() const
 
        {
 
            return _numChannels;
 
        };
 

	
 
    virtual bool hasX() const
 
        {
 
            return _hasX;
 
        };
 

	
 
    void _feed(const SamplePack& data) const
 
        {
 
            feedOut(data);
 
        };
 

	
 
    void _setNumChannels(unsigned nc, bool x)
 
        {
 
            _numChannels = nc;
 
            _hasX = x;
 

	
 
            updateNumChannels();
 
        };
 
};
 

	
 
TEST_CASE("source", "[memory, stream]")
 
{
 
    TestSink sink;
tests/test_helpers.h
Show inline comments
 
new file 100644
 
#ifndef TEST_HELPERS_H
 
#define TEST_HELPERS_H
 

	
 
#include "source.h"
 
#include "sink.h"
 

	
 
class TestSink : public Sink
 
{
 
public:
 
    int totalFed;
 
    int _numChannels;
 
    bool _hasX;
 

	
 
    TestSink()
 
        {
 
            totalFed = 0;
 
            _numChannels = 0;
 
            _hasX = false;
 
        };
 

	
 
    void feedIn(const SamplePack& data)
 
        {
 
            REQUIRE(data.numChannels() == numChannels());
 

	
 
            totalFed += data.numSamples();
 

	
 
            Sink::feedIn(data);
 
        };
 

	
 
    void setNumChannels(unsigned nc, bool x)
 
        {
 
            _numChannels = nc;
 
            _hasX = x;
 

	
 
            Sink::setNumChannels(nc, x);
 
        };
 

	
 
    virtual unsigned numChannels() const
 
        {
 
            return _numChannels;
 
        };
 

	
 
    virtual bool hasX() const
 
        {
 
            return _hasX;
 
        };
 
};
 

	
 
class TestSource : public Source
 
{
 
public:
 
    int _numChannels;
 
    bool _hasX;
 

	
 
    TestSource(unsigned nc, bool x)
 
        {
 
            _numChannels = nc;
 
            _hasX = x;
 
        };
 

	
 
    virtual unsigned numChannels() const
 
        {
 
            return _numChannels;
 
        };
 

	
 
    virtual bool hasX() const
 
        {
 
            return _hasX;
 
        };
 

	
 
    void _feed(const SamplePack& data) const
 
        {
 
            feedOut(data);
 
        };
 

	
 
    void _setNumChannels(unsigned nc, bool x)
 
        {
 
            _numChannels = nc;
 
            _hasX = x;
 

	
 
            updateNumChannels();
 
        };
 
};
 

	
 

	
 
#endif // TEST_HELPERS_H
tests/test_stream.cpp
Show inline comments
 
new file 100644
 
/*
 
  Copyright © 2018 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 <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "stream.h"
 

	
 
#include "catch.hpp"
 
#include "test_helpers.h"
 

	
 
TEST_CASE("construction of stream with default values", "[memory, stream]")
 
{
 
    // default values are an empty stream with no channels
 
    Stream s;
 

	
 
    REQUIRE(s.numChannels() == 0);
 
    REQUIRE(!s.hasX());
 
    REQUIRE(s.numSamples() == 0);
 
}
 

	
 
TEST_CASE("construction of stream with parameters", "[memory, stream]")
 
{
 
    Stream s(4, true, 100);
 

	
 
    REQUIRE(s.numChannels() == 4);
 
    REQUIRE(s.hasX());
 
    REQUIRE(s.numSamples() == 100);
 

	
 
    for (unsigned i = 0; i < 4; i++)
 
    {
 
        const StreamChannel* c = s.channel(i);
 
        REQUIRE(c != NULL);
 
        REQUIRE(c->index() == i);
 
    }
 
}
 

	
 
TEST_CASE("adding data to a stream with no X", "[memory, stream, data]")
 
{
 
    Stream s(3, false, 10);
 

	
 
    // prepare data
 
    SamplePack pack(5, 3, false);
 
    for (unsigned ci = 0; ci < 3; ci++)
 
    {
 
        for (unsigned i = 0; i < 5; i++)
 
        {
 
            pack.data(ci)[i] = i;
 
        }
 
    }
 

	
 
    TestSource so(3, false);
 
    so.connect(&s);
 

	
 
    // test
 
    so._feed(pack);
 

	
 
    for (unsigned ci = 0; ci < 3; ci++)
 
    {
 
        const StreamChannel* c = s.channel(ci);
 
        const FrameBuffer* y = c->yData();
 

	
 
        for (unsigned i = 0; i < 5; i++)
 
        {
 
            REQUIRE(y->sample(i) == 0);
 
        }
 
        for (unsigned i = 5; i < 10; i++)
 
        {
 
            REQUIRE(y->sample(i) == i-5);
 
        }
 
    }
 
}
0 comments (0 inline, 0 general)