Changeset - f6ca721ac759
[Not reviewed]
stream
0 3 1
Hasan Yavuz ÖZDERYA - 7 years ago 2018-04-15 13:34:06
hy@ozderya.net
added reworked DataRecorder with simple test
4 files changed with 110 insertions and 16 deletions:
0 comments (0 inline, 0 general)
src/datarecorder.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -54,26 +54,29 @@ bool DataRecorder::startRecording(QStrin
 
    return true;
 
}
 

	
 
void DataRecorder::addData(double* data, unsigned length, unsigned numOfChannels)
 
void DataRecorder::feedIn(const SamplePack& data)
 
{
 
    Q_ASSERT(length > 0);
 
    Q_ASSERT(length % numOfChannels == 0);
 
    Q_ASSERT(file.isOpen());    // recorder should be disconnected before stopping recording
 
    Q_ASSERT(!data.hasX());     // NYI
 

	
 
    if (lastNumChannels != 0 && numOfChannels != lastNumChannels)
 
    // check if number of channels has changed during recording and warn
 
    unsigned numChannels = data.numChannels();
 
    if (lastNumChannels != 0 && numChannels != lastNumChannels)
 
    {
 
        qWarning() << "Number of channels changed from " << lastNumChannels
 
                   << " to " << numOfChannels <<
 
                   << " to " << numChannels <<
 
            " during recording, CSV file is corrupted but no data will be lost.";
 
    }
 
    lastNumChannels = numOfChannels;
 
    lastNumChannels = numChannels;
 

	
 
    unsigned numOfSamples = length / numOfChannels; // per channel
 
    for (unsigned int i = 0; i < numOfSamples; i++)
 
    // write data
 
    unsigned numSamples = data.numSamples();
 
    for (unsigned int i = 0; i < numSamples; i++)
 
    {
 
        for (unsigned ci = 0; ci < numOfChannels; ci++)
 
        for (unsigned ci = 0; ci < numChannels; ci++)
 
        {
 
            fileStream << data[ci * numOfSamples + i];
 
            if (ci != numOfChannels-1) fileStream << _sep;
 
            fileStream << data.data(ci)[i];
 
            if (ci != numChannels-1) fileStream << _sep;
 
        }
 
        fileStream << le();
 
    }
src/datarecorder.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
@@ -24,7 +24,15 @@
 
#include <QFile>
 
#include <QTextStream>
 

	
 
class DataRecorder : public QObject
 
#include "sink.h"
 

	
 
/**
 
 * Implemented as a `Sink` that writes incoming data to a file. Before
 
 * connecting a `Source` recording must be started with the `startRecording`
 
 * method. Also before calling `stopRecording`, recorder should be disconnected
 
 * from source.
 
 */
 
class DataRecorder : public QObject, public Sink
 
{
 
    Q_OBJECT
 
public:
 
@@ -44,7 +52,8 @@ public:
 
    /**
 
     * @brief Starts recording data to a file in CSV format.
 
     *
 
     * File is opened and header line (names of channels) is written.
 
     * File is opened and header line (names of channels) is written. After
 
     * calling this function recorder should be connected to a `Source`.
 
     *
 
     * @param fileName name of the recording file
 
     * @param separator column separator
 
@@ -75,6 +84,9 @@ public:
 
    /// Stops recording, closes file.
 
    void stopRecording();
 

	
 
protected:
 
    virtual void feedIn(const SamplePack& data);
 

	
 
private:
 
    unsigned lastNumChannels;   ///< used for error message only
 
    QFile file;
tests/CMakeLists.txt
Show inline comments
 
@@ -71,6 +71,21 @@ add_executable(TestReaders EXCLUDE_FROM_
 
qt5_use_modules(TestReaders Widgets Test)
 
add_test(NAME test_readers COMMAND TestReaders)
 

	
 
# test for recroder
 
add_executable(TestRecorder EXCLUDE_FROM_ALL
 
  test_recorder.cpp
 
  ../src/samplepack.cpp
 
  ../src/sink.cpp
 
  ../src/source.cpp
 
  ../src/datarecorder.cpp
 
)
 
qt5_use_modules(TestRecorder Widgets Test)
 
add_test(NAME test_recorder COMMAND TestRecorder)
 

	
 
set(CMAKE_CTEST_COMMAND ctest -V)
 
add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND})
 
add_dependencies(check Test TestReaders)
 
add_dependencies(check
 
  Test
 
  TestReaders
 
  TestRecorder
 
  )
tests/test_recorder.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/>.
 
*/
 

	
 
#define CATCH_CONFIG_MAIN  // This tells Catch to provide a main() - only do this in one cpp file
 
#include "catch.hpp"
 

	
 
#include <QDir>
 
#include "datarecorder.h"
 
#include "test_helpers.h"
 

	
 
#define TEST_FILE_NAME   "sp_test_recording.csv"
 

	
 
TEST_CASE("test recording single channel", "[recorder]")
 
{
 
    DataRecorder rec;
 
    TestSource source(1, false);
 

	
 
    // temporary file, remove if exists
 
    auto fileName = QDir::tempPath() + QString("/" TEST_FILE_NAME);
 
    if (QFile::exists(fileName)) QFile::remove(fileName);
 

	
 
    // connect source → sink
 
    source.connectSink(&rec);
 

	
 
    // prepare data
 
    QStringList channelNames({"Channel 1"});
 
    SamplePack samples(5, 1);
 
    for (int i = 0; i < 5; i++)
 
    {
 
        samples.data(0)[i] = i+1;
 
    }
 

	
 
    // test
 
    rec.startRecording(fileName, ",", channelNames);
 
    source._feed(samples);
 
    rec.stopRecording();
 

	
 
    // read file contents back
 
    QFile recordFile(fileName);
 
    REQUIRE(recordFile.open(QIODevice::ReadOnly | QIODevice::Text));
 
    // NOTE: mind the extra parantheses, otherwise 'catch' macros fail to compile
 
    REQUIRE((recordFile.readLine() == "Channel 1\n"));
 
    for (int i = 0; i < 5; i++)
 
        REQUIRE((recordFile.readLine() == QString("%1\n").arg(i+1)));
 

	
 
    // cleanup
 
    if (QFile::exists(fileName)) QFile::remove(fileName);
 
}
0 comments (0 inline, 0 general)