diff --git a/src/datarecorder.cpp b/src/datarecorder.cpp
new file mode 100644
--- /dev/null
+++ b/src/datarecorder.cpp
@@ -0,0 +1,89 @@
+/*
+ Copyright © 2017 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 "datarecorder.h"
+
+#include
+
+DataRecorder::DataRecorder(QObject *parent) :
+ QObject(parent),
+ fileStream(&file)
+{
+ lastNumChannels = 0;
+ disableBuffering = false;
+}
+
+bool DataRecorder::startRecording(QString fileName, QString separator, QStringList channelNames)
+{
+ Q_ASSERT(!file.isOpen());
+ _sep = separator;
+
+ // open file
+ file.setFileName(fileName);
+ if (!file.open(QIODevice::WriteOnly))
+ {
+ qCritical() << "Opening file " << fileName
+ << " for recording failed with error: " << file.error();
+ return false;
+ }
+
+ // write header line
+ if (!channelNames.isEmpty())
+ {
+ fileStream << channelNames.join(_sep);
+ fileStream << "\n";
+ lastNumChannels = channelNames.length();
+ }
+ return true;
+}
+
+void DataRecorder::addData(double* data, unsigned length, unsigned numOfChannels)
+{
+ Q_ASSERT(length > 0);
+ Q_ASSERT(length % numOfChannels == 0);
+
+ if (lastNumChannels != 0 && numOfChannels != lastNumChannels)
+ {
+ qWarning() << "Number of channels changed from " << lastNumChannels
+ << " to " << numOfChannels <<
+ " during recording, CSV file is corrupted but no data will be lost.";
+ }
+ lastNumChannels = numOfChannels;
+
+ unsigned numOfSamples = length / numOfChannels; // per channel
+ for (unsigned int i = 0; i < numOfSamples; i++)
+ {
+ for (unsigned ci = 0; ci < numOfChannels; ci++)
+ {
+ fileStream << data[ci * numOfSamples + i];
+ if (ci != numOfChannels-1) fileStream << _sep;
+ }
+ fileStream << '\n';
+ }
+
+ if (disableBuffering) fileStream.flush();
+}
+
+void DataRecorder::stopRecording()
+{
+ Q_ASSERT(file.isOpen());
+
+ file.close();
+ lastNumChannels = 0;
+}