diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -104,6 +104,7 @@ add_executable(${PROGRAM_NAME} WIN32
   src/binarystreamreadersettings.cpp
   src/asciireader.cpp
   src/asciireadersettings.cpp
+  src/demoreader.cpp
   misc/windows_icon.rc
   ${UI_FILES}
   ${RES_FILES}
diff --git a/src/dataformatpanel.cpp b/src/dataformatpanel.cpp
--- a/src/dataformatpanel.cpp
+++ b/src/dataformatpanel.cpp
@@ -32,8 +32,9 @@ DataFormatPanel::DataFormatPanel(QSerial
                                  QWidget *parent) :
     QWidget(parent),
     ui(new Ui::DataFormatPanel),
-    bsReader(port, channelMan),
-    asciiReader(port, channelMan)
+    bsReader(port, channelMan, this),
+    asciiReader(port, channelMan, this),
+    demoReader(port, channelMan, this)
 {
     ui->setupUi(this);
 
@@ -63,11 +64,9 @@ DataFormatPanel::DataFormatPanel(QSerial
                 if (checked) selectReader(&asciiReader);
             });
 
-    // Init demo mode
-    demoCount = 0;
-    demoTimer.setInterval(100);
-    QObject::connect(&demoTimer, &QTimer::timeout,
-                     this, &DataFormatPanel::demoTimerTimeout);
+    // re-purpose numofchannels settings from actual reader settings to demo reader
+    connect(this, &DataFormatPanel::numOfChannelsChanged,
+            &demoReader, &DemoReader::setNumOfChannels);
 }
 
 DataFormatPanel::~DataFormatPanel()
@@ -83,35 +82,23 @@ unsigned DataFormatPanel::numOfChannels(
 void DataFormatPanel::pause(bool enabled)
 {
     currentReader->pause(enabled);
+    demoReader.pause(enabled);
 }
 
 void DataFormatPanel::enableDemo(bool enabled)
 {
     if (enabled)
     {
-        demoTimer.start();
+        demoReader.enable();
+        connect(&demoReader, &DemoReader::dataAdded,
+                this, &DataFormatPanel::dataAdded);
+        connect(&demoReader, &DemoReader::samplesPerSecondChanged,
+                this, &DataFormatPanel::samplesPerSecondChanged);
     }
     else
     {
-        demoTimer.stop();
-    }
-}
-
-void DataFormatPanel::demoTimerTimeout()
-{
-    const double period = 100;
-    demoCount++;
-    if (demoCount >= 100) demoCount = 0;
-
-    if (!paused)
-    {
-        for (unsigned ci = 0; ci < currentReader->numOfChannels(); ci++)
-        {
-            // 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);
-            addChannelData(ci, &value, 1);
-        }
-        emit dataAdded();
+        demoReader.enable(false);
+        disconnect(&demoReader, 0, this, 0);
     }
 }
 
diff --git a/src/dataformatpanel.h b/src/dataformatpanel.h
--- a/src/dataformatpanel.h
+++ b/src/dataformatpanel.h
@@ -31,6 +31,7 @@
 #include "channelmanager.h"
 #include "binarystreamreader.h"
 #include "asciireader.h"
+#include "demoreader.h"
 
 namespace Ui {
 class DataFormatPanel;
@@ -72,15 +73,10 @@ private:
 
     bool paused; // remove
 
-    // demo
-    QTimer demoTimer;
-    int demoCount;
+    DemoReader demoReader;
 
     // `data` contains i th channels data
     void addChannelData(unsigned int channel, double* data, unsigned size);
-
-private slots:
-    void demoTimerTimeout();
 };
 
 #endif // DATAFORMATPANEL_H
diff --git a/src/demoreader.cpp b/src/demoreader.cpp
new file mode 100644
--- /dev/null
+++ b/src/demoreader.cpp
@@ -0,0 +1,82 @@
+/*
+  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 "demoreader.h"
+
+DemoReader::DemoReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) :
+    AbstractReader(device, channelMan, parent)
+{
+    paused = false;
+    _numOfChannels = 1;
+    count = 0;
+    timer.setInterval(100);
+    QObject::connect(&timer, &QTimer::timeout,
+                     this, &DemoReader::demoTimerTimeout);
+}
+
+QWidget* DemoReader::settingsWidget()
+{
+    return NULL;
+}
+
+void DemoReader::enable(bool enabled)
+{
+    if (enabled)
+    {
+        timer.start();
+    }
+    else
+    {
+        timer.stop();
+    }
+}
+
+unsigned DemoReader::numOfChannels()
+{
+    return _numOfChannels;
+}
+
+void DemoReader::setNumOfChannels(unsigned value)
+{
+    _numOfChannels = value;
+}
+
+void DemoReader::pause(bool enabled)
+{
+    paused = enabled;
+}
+
+void DemoReader::demoTimerTimeout()
+{
+    const double period = 100;
+    count++;
+    if (count >= 100) count = 0;
+
+    if (!paused)
+    {
+        for (unsigned ci = 0; ci < _numOfChannels; ci++)
+        {
+            // we are calculating the fourier components of square wave
+            double value = 4*sin(2*M_PI*double((ci+1)*count)/period)/((2*(ci+1))*M_PI);
+            _channelMan->addChannelData(ci, &value, 1);
+            sampleCount++;
+        }
+        emit dataAdded();
+    }
+}
diff --git a/src/demoreader.h b/src/demoreader.h
new file mode 100644
--- /dev/null
+++ b/src/demoreader.h
@@ -0,0 +1,66 @@
+/*
+  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 .
+*/
+
+#ifndef DEMOREADER_H
+#define DEMOREADER_H
+
+#include 
+
+#include "abstractreader.h"
+
+/**
+ * This is a special case of reader implementation and should be used
+ * with care.
+ *
+ * There is no settings widget. Number of channels should be set from
+ * currently selected actual readers settings widget.
+ *
+ * This reader should not be enabled when port is open!
+ */
+class DemoReader : public AbstractReader
+{
+    Q_OBJECT
+
+public:
+    explicit DemoReader(QIODevice* device, ChannelManager* channelMan, QObject *parent = 0);
+
+    /// Demo reader is an exception so this function returns NULL
+    QWidget* settingsWidget();
+
+    unsigned numOfChannels();
+
+    void enable(bool enabled = true);
+
+public slots:
+    void pause(bool);
+
+    /// Sets the number of channels, this doesn't trigger a `numOfChannelsChanged` signal.
+    void setNumOfChannels(unsigned value);
+
+private:
+    bool paused;
+    unsigned _numOfChannels;
+    QTimer timer;
+    int count;
+
+private slots:
+    void demoTimerTimeout();
+};
+
+#endif // DEMOREADER_H