diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -61,6 +61,11 @@ qt5_wrap_ui(UI_FILES
   src/commandwidget.ui
   src/dataformatpanel.ui
   src/plotcontrolpanel.ui
+  src/numberformatbox.ui
+  src/endiannessbox.ui
+  src/binarystreamreadersettings.ui
+  src/asciireadersettings.ui
+  src/framedreadersettings.ui
   )
 
 if (WIN32)
@@ -93,6 +98,16 @@ add_executable(${PROGRAM_NAME} WIN32
   src/sneakylineedit.cpp
   src/channelmanager.cpp
   src/framebufferseries.cpp
+  src/numberformatbox.cpp
+  src/endiannessbox.cpp
+  src/abstractreader.cpp
+  src/binarystreamreader.cpp
+  src/binarystreamreadersettings.cpp
+  src/asciireader.cpp
+  src/asciireadersettings.cpp
+  src/demoreader.cpp
+  src/framedreader.cpp
+  src/framedreadersettings.cpp
   misc/windows_icon.rc
   ${UI_FILES}
   ${RES_FILES}
diff --git a/misc/pseudo_device.py b/misc/pseudo_device.py
--- a/misc/pseudo_device.py
+++ b/misc/pseudo_device.py
@@ -71,6 +71,34 @@ def uint32_test(port, little):
         time.sleep(0.05)
         i = i+1 if i <= maxi else 0
 
+def frame_test(port, fixed_size=False, hasChecksum=True):
+    """Sends binary data in framed format."""
+    SYNCWORD = [0xAA, 0xBB]
+    NUMSAMPLES = 10
+    SIZE = NUMSAMPLES * 4 # integer
+    if fixed_size:
+        HEADER = bytes(SYNCWORD)
+    else:
+        HEADER = bytes(SYNCWORD + [SIZE])
+    i = 0
+    checksum = 0
+    bytesent = 0
+    while True:
+        if i > 100: i = 0
+        if bytesent == 0: # beginning of a frame?
+            os.write(port, HEADER)
+        os.write(port, struct.pack('.
+*/
+
+#include "abstractreader.h"
+
+AbstractReader::AbstractReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) :
+    QObject(parent)
+{
+    _device = device;
+    _channelMan = channelMan;
+
+    // initialize sps counter
+    sampleCount = 0;
+    samplesPerSecond = 0;
+    QObject::connect(&spsTimer, &QTimer::timeout,
+                     this, &AbstractReader::spsTimerTimeout);
+    // TODO: start sps timer when reader is enabled
+    spsTimer.start(SPS_UPDATE_TIMEOUT * 1000);
+}
+
+void AbstractReader::spsTimerTimeout()
+{
+    unsigned currentSps = samplesPerSecond;
+    samplesPerSecond = (sampleCount/numOfChannels())/SPS_UPDATE_TIMEOUT;
+    if (currentSps != samplesPerSecond)
+    {
+        emit samplesPerSecondChanged(samplesPerSecond);
+    }
+    sampleCount = 0;
+}
diff --git a/src/abstractreader.h b/src/abstractreader.h
new file mode 100644
--- /dev/null
+++ b/src/abstractreader.h
@@ -0,0 +1,89 @@
+/*
+  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 ABSTRACTREADER_H
+#define ABSTRACTREADER_H
+
+#include 
+#include 
+#include 
+#include 
+
+#include "channelmanager.h"
+
+/**
+ * All reader classes must inherit this class.
+ */
+class AbstractReader : public QObject
+{
+    Q_OBJECT
+public:
+    explicit AbstractReader(QIODevice* device, ChannelManager* channelMan, QObject *parent = 0);
+
+    /**
+     * Returns a widget to be shown in data format panel when reader
+     * is selected.
+     */
+    virtual QWidget* settingsWidget() = 0;
+
+    /**
+     * Number of channels being read.
+     *
+     * This number may be user selected or automatically determined
+     * from incoming stream.
+     */
+    virtual unsigned numOfChannels() = 0;
+
+    /// Reader should only read when enabled. Default state should be
+    /// 'disabled'.
+    virtual void enable(bool enabled = true) = 0;
+
+signals:
+    void numOfChannelsChanged(unsigned);
+    // TODO: this must be signaled by 'channel man' for better abstraction
+    void dataAdded(); ///< emitted when data added to channel man.
+    // TODO: this should be a part of 'channel man'
+    void samplesPerSecondChanged(unsigned);
+
+public slots:
+    /**
+     * Pauses the reading.
+     *
+     * Reader should actually continue reading to keep the
+     * synchronization but shouldn't commit data.
+     */
+    virtual void pause(bool) = 0;
+
+protected:
+    QIODevice* _device;
+    ChannelManager* _channelMan;
+
+    /// Implementing class should simply increase this count as samples are read
+    unsigned sampleCount;
+
+private:
+    const int SPS_UPDATE_TIMEOUT = 1;  // second
+    unsigned samplesPerSecond;
+    QTimer spsTimer;
+
+private slots:
+    void spsTimerTimeout();
+};
+
+#endif // ABSTRACTREADER_H
diff --git a/src/asciireader.cpp b/src/asciireader.cpp
new file mode 100644
--- /dev/null
+++ b/src/asciireader.cpp
@@ -0,0 +1,110 @@
+/*
+  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 
+
+#include "asciireader.h"
+
+AsciiReader::AsciiReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) :
+    AbstractReader(device, channelMan, parent)
+{
+    paused = false;
+    sampleCount = 0;
+    // TODO: sps counter
+
+    _numOfChannels = _settingsWidget.numOfChannels();
+    connect(&_settingsWidget, &AsciiReaderSettings::numOfChannelsChanged,
+            this, &AsciiReader::numOfChannelsChanged);
+    connect(&_settingsWidget, &AsciiReaderSettings::numOfChannelsChanged,
+            [this](unsigned value){_numOfChannels = value;});
+}
+
+QWidget* AsciiReader::settingsWidget()
+{
+    return &_settingsWidget;
+}
+
+unsigned AsciiReader::numOfChannels()
+{
+    return _numOfChannels;
+}
+
+// TODO: this could be a part of AbstractReader
+void AsciiReader::enable(bool enabled)
+{
+    if (enabled)
+    {
+        QObject::connect(_device, &QIODevice::readyRead,
+                         this, &AsciiReader::onDataReady);
+    }
+    else
+    {
+        QObject::disconnect(_device, 0, this, 0);
+    }
+}
+
+void AsciiReader::pause(bool enabled)
+{
+    paused = enabled;
+}
+
+void AsciiReader::onDataReady()
+{
+    while(_device->canReadLine())
+    {
+        QByteArray line = _device->readLine();
+
+        // discard data if paused
+        if (paused)
+        {
+            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)
+            {
+                _channelMan->addChannelData(ci, &channelSample, 1);
+                sampleCount++;
+            }
+            else
+            {
+                qWarning() << "Data parsing error for channel: " << ci;
+            }
+        }
+        emit dataAdded();
+    }
+}
diff --git a/src/asciireader.h b/src/asciireader.h
new file mode 100644
--- /dev/null
+++ b/src/asciireader.h
@@ -0,0 +1,48 @@
+/*
+  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 ASCIIREADER_H
+#define ASCIIREADER_H
+
+#include "abstractreader.h"
+#include "asciireadersettings.h"
+
+class AsciiReader : public AbstractReader
+{
+    Q_OBJECT
+
+public:
+    explicit AsciiReader(QIODevice* device, ChannelManager* channelMan, QObject *parent = 0);
+    QWidget* settingsWidget();
+    unsigned numOfChannels();
+    void enable(bool enabled = true);
+
+public slots:
+    void pause(bool);
+
+private:
+    AsciiReaderSettings _settingsWidget;
+    unsigned _numOfChannels;
+    bool paused;
+
+private slots:
+    void onDataReady();
+};
+
+#endif // ASCIIREADER_H
diff --git a/src/asciireadersettings.cpp b/src/asciireadersettings.cpp
new file mode 100644
--- /dev/null
+++ b/src/asciireadersettings.cpp
@@ -0,0 +1,47 @@
+/*
+  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 "utils.h"
+
+#include "asciireadersettings.h"
+#include "ui_asciireadersettings.h"
+
+AsciiReaderSettings::AsciiReaderSettings(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::AsciiReaderSettings)
+{
+    ui->setupUi(this);
+
+    // Note: if directly connected we get a runtime warning on incompatible signal arguments
+    connect(ui->spNumOfChannels, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged),
+            [this](int value)
+            {
+                emit numOfChannelsChanged(value);
+            });
+}
+
+AsciiReaderSettings::~AsciiReaderSettings()
+{
+    delete ui;
+}
+
+unsigned AsciiReaderSettings::numOfChannels()
+{
+    return ui->spNumOfChannels->value();
+}
diff --git a/src/asciireadersettings.h b/src/asciireadersettings.h
new file mode 100644
--- /dev/null
+++ b/src/asciireadersettings.h
@@ -0,0 +1,46 @@
+/*
+  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 ASCIIREADERSETTINGS_H
+#define ASCIIREADERSETTINGS_H
+
+#include 
+
+namespace Ui {
+class AsciiReaderSettings;
+}
+
+class AsciiReaderSettings : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit AsciiReaderSettings(QWidget *parent = 0);
+    ~AsciiReaderSettings();
+
+    unsigned numOfChannels();
+
+signals:
+    void numOfChannelsChanged(unsigned);
+
+private:
+    Ui::AsciiReaderSettings *ui;
+};
+
+#endif // ASCIIREADERSETTINGS_H
diff --git a/src/asciireadersettings.ui b/src/asciireadersettings.ui
new file mode 100644
--- /dev/null
+++ b/src/asciireadersettings.ui
@@ -0,0 +1,92 @@
+
+
+ AsciiReaderSettings
+ 
+  
+   
+    0
+    0
+    414
+    171
+   
+  
+  
+   Form
+  
+  
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   - 
+    
+     
- 
+      
+       
+        Number Of Channels:
+       
+      
+     
 
+     - 
+      
+       
+        
+         60
+         0
+        
+       
+       
+        Select number of channels
+       
+       
+        false
+       
+       
+        1
+       
+       
+        32
+       
+      
+     
 
+     - 
+      
+       
+        Qt::Horizontal
+       
+       
+        
+         1
+         20
+        
+       
+      
+     
 
+    
+    
+   - 
+    
+     
+      Qt::Vertical
+     
+     
+      
+       20
+       1
+      
+     
+    
+   
 
+  
+ 
+ 
+ 
+
diff --git a/src/binarystreamreader.cpp b/src/binarystreamreader.cpp
new file mode 100644
--- /dev/null
+++ b/src/binarystreamreader.cpp
@@ -0,0 +1,190 @@
+/*
+  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 
+#include 
+
+#include "binarystreamreader.h"
+#include "floatswap.h"
+
+BinaryStreamReader::BinaryStreamReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) :
+    AbstractReader(device, channelMan, parent)
+{
+    paused = false;
+    skipByteRequested = false;
+    sampleCount = 0;
+
+    _numOfChannels = _settingsWidget.numOfChannels();
+    connect(&_settingsWidget, &BinaryStreamReaderSettings::numOfChannelsChanged,
+            this, &BinaryStreamReader::numOfChannelsChanged);
+    connect(&_settingsWidget, &BinaryStreamReaderSettings::numOfChannelsChanged,
+            this, &BinaryStreamReader::onNumOfChannelsChanged);
+
+    // initial number format selection
+    onNumberFormatChanged(_settingsWidget.numberFormat());
+    connect(&_settingsWidget, &BinaryStreamReaderSettings::numberFormatChanged,
+            this, &BinaryStreamReader::onNumberFormatChanged);
+
+    // enable skip byte button
+    connect(&_settingsWidget, &BinaryStreamReaderSettings::skipByteRequested,
+            [this]()
+            {
+                skipByteRequested = true;
+            });
+}
+
+QWidget* BinaryStreamReader::settingsWidget()
+{
+    return &_settingsWidget;
+}
+
+unsigned BinaryStreamReader::numOfChannels()
+{
+    return _numOfChannels;
+}
+
+void BinaryStreamReader::enable(bool enabled)
+{
+    if (enabled)
+    {
+        QObject::connect(_device, &QIODevice::readyRead,
+                         this, &BinaryStreamReader::onDataReady);
+    }
+    else
+    {
+        QObject::disconnect(_device, 0, this, 0);
+    }
+}
+
+void BinaryStreamReader::pause(bool enabled)
+{
+    paused = enabled;
+}
+
+void BinaryStreamReader::onNumberFormatChanged(NumberFormat numberFormat)
+{
+    switch(numberFormat)
+    {
+        case NumberFormat_uint8:
+            sampleSize = 1;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+        case NumberFormat_int8:
+            sampleSize = 1;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+        case NumberFormat_uint16:
+            sampleSize = 2;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+        case NumberFormat_int16:
+            sampleSize = 2;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+        case NumberFormat_uint32:
+            sampleSize = 4;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+        case NumberFormat_int32:
+            sampleSize = 4;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+        case NumberFormat_float:
+            sampleSize = 4;
+            readSample = &BinaryStreamReader::readSampleAs;
+            break;
+    }
+}
+
+void BinaryStreamReader::onNumOfChannelsChanged(unsigned value)
+{
+    _numOfChannels = value;
+}
+
+void BinaryStreamReader::onDataReady()
+{
+    // a package is a set of channel data like {CHAN0_SAMPLE, CHAN1_SAMPLE...}
+    int packageSize = sampleSize * _numOfChannels;
+    int bytesAvailable = _device->bytesAvailable();
+    int numOfPackagesToRead =
+        (bytesAvailable - (bytesAvailable % packageSize)) / packageSize;
+
+    if (paused)
+    {
+        // read and discard data
+        _device->read(numOfPackagesToRead*packageSize);
+        return;
+    }
+
+    if (bytesAvailable > 0 && skipByteRequested)
+    {
+        _device->read(1);
+        skipByteRequested = false;
+        bytesAvailable--;
+    }
+
+    if (bytesAvailable < packageSize) return;
+
+    double* channelSamples = new double[numOfPackagesToRead*_numOfChannels];
+
+    for (int i = 0; i < numOfPackagesToRead; i++)
+    {
+        for (unsigned int ci = 0; ci < _numOfChannels; ci++)
+        {
+            // channelSamples[ci].replace(i, (this->*readSample)());
+            channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)();
+        }
+    }
+
+    for (unsigned int ci = 0; ci < _numOfChannels; ci++)
+    {
+        addChannelData(ci,
+                       channelSamples + ci*numOfPackagesToRead,
+                       numOfPackagesToRead);
+    }
+    emit dataAdded();
+
+    delete channelSamples;
+}
+
+
+template double BinaryStreamReader::readSampleAs()
+{
+    T data;
+
+    _device->read((char*) &data, sizeof(data));
+
+    if (_settingsWidget.endianness() == LittleEndian)
+    {
+        data = qFromLittleEndian(data);
+    }
+    else
+    {
+        data = qFromBigEndian(data);
+    }
+
+    return double(data);
+}
+
+void BinaryStreamReader::addChannelData(unsigned int channel,
+                                        double* data, unsigned size)
+{
+    _channelMan->addChannelData(channel, data, size);
+    sampleCount += size;
+}
diff --git a/src/binarystreamreader.h b/src/binarystreamreader.h
new file mode 100644
--- /dev/null
+++ b/src/binarystreamreader.h
@@ -0,0 +1,70 @@
+/*
+  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 BINARYSTREAMREADER_H
+#define BINARYSTREAMREADER_H
+
+#include "abstractreader.h"
+#include "binarystreamreadersettings.h"
+
+/**
+ * Reads a simple stream of samples in binary form from the
+ * device. There is no means of synchronization other than a button
+ * that should be manually triggered by user.
+ */
+class BinaryStreamReader : public AbstractReader
+{
+    Q_OBJECT
+public:
+    explicit BinaryStreamReader(QIODevice* device, ChannelManager* channelMan, QObject *parent = 0);
+    QWidget* settingsWidget();
+    unsigned numOfChannels();
+    void enable(bool enabled = true);
+
+public slots:
+    void pause(bool);
+
+private:
+    BinaryStreamReaderSettings _settingsWidget;
+    unsigned _numOfChannels;
+    unsigned sampleSize;
+    bool paused;
+    bool skipByteRequested;
+
+    /// points to the readSampleAs function for currently selected number format
+    double (BinaryStreamReader::*readSample)();
+
+    /**
+     * Reads 1 sample from the device in given format.
+     *
+     * @note Device should already have enough bytes present before
+     * calling this function.
+     */
+    template double readSampleAs();
+
+    // `data` contains i th channels data
+    void addChannelData(unsigned int channel, double* data, unsigned size);
+
+private slots:
+    void onNumberFormatChanged(NumberFormat numberFormat);
+    void onNumOfChannelsChanged(unsigned value);
+    void onDataReady();
+};
+
+#endif // BINARYSTREAMREADER_H
diff --git a/src/binarystreamreadersettings.cpp b/src/binarystreamreadersettings.cpp
new file mode 100644
--- /dev/null
+++ b/src/binarystreamreadersettings.cpp
@@ -0,0 +1,62 @@
+/*
+  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 "binarystreamreadersettings.h"
+#include "ui_binarystreamreadersettings.h"
+
+#include "utils.h"
+
+BinaryStreamReaderSettings::BinaryStreamReaderSettings(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::BinaryStreamReaderSettings)
+{
+    ui->setupUi(this);
+
+    // Note: if directly connected we get a runtime warning on incompatible signal arguments
+    connect(ui->spNumOfChannels, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged),
+            [this](int value)
+            {
+                emit numOfChannelsChanged(value);
+            });
+
+    connect(ui->nfBox, SIGNAL(selectionChanged(NumberFormat)),
+            this, SIGNAL(numberFormatChanged(NumberFormat)));
+
+    connect(ui->pbSkipByte, SIGNAL(clicked()), this, SIGNAL(skipByteRequested()));
+}
+
+BinaryStreamReaderSettings::~BinaryStreamReaderSettings()
+{
+    delete ui;
+}
+
+unsigned BinaryStreamReaderSettings::numOfChannels()
+{
+    return ui->spNumOfChannels->value();
+}
+
+NumberFormat BinaryStreamReaderSettings::numberFormat()
+{
+    return ui->nfBox->currentSelection();
+}
+
+Endianness BinaryStreamReaderSettings::endianness()
+{
+    return ui->endiBox->currentSelection();
+}
diff --git a/src/binarystreamreadersettings.h b/src/binarystreamreadersettings.h
new file mode 100644
--- /dev/null
+++ b/src/binarystreamreadersettings.h
@@ -0,0 +1,52 @@
+/*
+  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 BINARYSTREAMREADERSETTINGS_H
+#define BINARYSTREAMREADERSETTINGS_H
+
+#include 
+#include "numberformatbox.h"
+#include "endiannessbox.h"
+
+namespace Ui {
+class BinaryStreamReaderSettings;
+}
+
+class BinaryStreamReaderSettings : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit BinaryStreamReaderSettings(QWidget *parent = 0);
+    ~BinaryStreamReaderSettings();
+
+    unsigned numOfChannels();
+    NumberFormat numberFormat();
+    Endianness endianness();
+
+signals:
+    void numOfChannelsChanged(unsigned);
+    void numberFormatChanged(NumberFormat);
+    void skipByteRequested();
+
+private:
+    Ui::BinaryStreamReaderSettings *ui;
+};
+
+#endif // BINARYSTREAMREADERSETTINGS_H
diff --git a/src/binarystreamreadersettings.ui b/src/binarystreamreadersettings.ui
new file mode 100644
--- /dev/null
+++ b/src/binarystreamreadersettings.ui
@@ -0,0 +1,172 @@
+
+
+ BinaryStreamReaderSettings
+ 
+  
+   
+    0
+    0
+    588
+    212
+   
+  
+  
+   Form
+  
+  
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   - 
+    
+     
- 
+      
+       
+        Number Of Channels:
+       
+      
+     
 
+     - 
+      
+       
+        
+         60
+         0
+        
+       
+       
+        Select number of channels
+       
+       
+        false
+       
+       
+        1
+       
+       
+        32
+       
+      
+     
 
+     - 
+      
+       
+        Qt::Horizontal
+       
+       
+        
+         40
+         20
+        
+       
+      
+     
 
+     - 
+      
+       
+        Skip reading 1 byte to correct the alignment
+       
+       
+        Skip Byte
+       
+      
+     
 
+    
+    
+   - 
+    
+     
+      QFormLayout::FieldsStayAtSizeHint
+     
+     
+      3
+     
+     
- 
+      
+       
+        
+         0
+         0
+        
+       
+       
+        Number Type:
+       
+      
+     
 
+     - 
+      
+       
+        
+         0
+         0
+        
+       
+       
+        Endianness:
+       
+      
+     
 
+     - 
+      
+       
+        
+         0
+         0
+        
+       
+      
+     
 
+     - 
+      
+       
+        
+         0
+         0
+        
+       
+      
+     
 
+    
+    
+   - 
+    
+     
+      Qt::Vertical
+     
+     
+      
+       20
+       40
+      
+     
+    
+   
 
+  
+ 
+ 
+  
+   NumberFormatBox
+   QWidget
+   
+   1
+  
+  
+   EndiannessBox
+   QWidget
+   
+   1
+  
+ 
+ 
+ 
+
diff --git a/src/dataformatpanel.cpp b/src/dataformatpanel.cpp
--- a/src/dataformatpanel.cpp
+++ b/src/dataformatpanel.cpp
@@ -1,5 +1,5 @@
 /*
-  Copyright © 2015 Hasan Yavuz Özderya
+  Copyright © 2016 Hasan Yavuz Özderya
 
   This file is part of serialplot.
 
@@ -20,6 +20,7 @@
 #include "dataformatpanel.h"
 #include "ui_dataformatpanel.h"
 
+#include 
 #include 
 #include 
 
@@ -30,7 +31,11 @@ DataFormatPanel::DataFormatPanel(QSerial
                                  ChannelManager* channelMan,
                                  QWidget *parent) :
     QWidget(parent),
-    ui(new Ui::DataFormatPanel)
+    ui(new Ui::DataFormatPanel),
+    bsReader(port, channelMan, this),
+    asciiReader(port, channelMan, this),
+    framedReader(port, channelMan, this),
+    demoReader(port, channelMan, this)
 {
     ui->setupUi(this);
 
@@ -38,41 +43,36 @@ DataFormatPanel::DataFormatPanel(QSerial
     _channelMan = channelMan;
     paused = false;
 
-    // setup number format buttons
-    numberFormatButtons.addButton(ui->rbUint8,  NumberFormat_uint8);
-    numberFormatButtons.addButton(ui->rbUint16, NumberFormat_uint16);
-    numberFormatButtons.addButton(ui->rbUint32, NumberFormat_uint32);
-    numberFormatButtons.addButton(ui->rbInt8,   NumberFormat_int8);
-    numberFormatButtons.addButton(ui->rbInt16,  NumberFormat_int16);
-    numberFormatButtons.addButton(ui->rbInt32,  NumberFormat_int32);
-    numberFormatButtons.addButton(ui->rbFloat,  NumberFormat_float);
-    numberFormatButtons.addButton(ui->rbASCII,  NumberFormat_ASCII);
-
-    QObject::connect(
-        &numberFormatButtons, SIGNAL(buttonToggled(int, bool)),
-        this, SLOT(onNumberFormatButtonToggled(int, bool)));
-
-    // init number format
-    selectNumberFormat((NumberFormat) numberFormatButtons.checkedId());
+    // initalize default reader
+    currentReader = &bsReader;
+    bsReader.enable();
+    ui->rbBinary->setChecked(true);
+    ui->horizontalLayout->addWidget(bsReader.settingsWidget(), 1);
+    connect(&bsReader, SIGNAL(dataAdded()), this, SIGNAL(dataAdded()));
+    connect(&bsReader, SIGNAL(numOfChannelsChanged(unsigned)),
+            this, SIGNAL(numOfChannelsChanged(unsigned)));
+    connect(&bsReader, SIGNAL(samplesPerSecondChanged(unsigned)),
+            this, SIGNAL(samplesPerSecondChanged(unsigned)));
 
-    // setup number of channels spinbox
-    QObject::connect(ui->spNumOfChannels,
-                     SELECT::OVERLOAD_OF(&QSpinBox::valueChanged),
-                     this, &DataFormatPanel::onNumOfChannelsSP);
-
-    _numOfChannels = ui->spNumOfChannels->value();
+    // initalize reader selection buttons
+    connect(ui->rbBinary, &QRadioButton::toggled, [this](bool checked)
+            {
+                if (checked) selectReader(&bsReader);
+            });
 
-    // Init sps (sample per second) counter
-    sampleCount = 0;
-    QObject::connect(&spsTimer, &QTimer::timeout,
-                     this, &DataFormatPanel::spsTimerTimeout);
-    spsTimer.start(SPS_UPDATE_TIMEOUT * 1000);
+    connect(ui->rbAscii, &QRadioButton::toggled, [this](bool checked)
+            {
+                if (checked) selectReader(&asciiReader);
+            });
 
-    // Init demo mode
-    demoCount = 0;
-    demoTimer.setInterval(100);
-    QObject::connect(&demoTimer, &QTimer::timeout,
-                     this, &DataFormatPanel::demoTimerTimeout);
+    connect(ui->rbFramed, &QRadioButton::toggled, [this](bool checked)
+            {
+                if (checked) selectReader(&framedReader);
+            });
+
+    // re-purpose numofchannels settings from actual reader settings to demo reader
+    connect(this, &DataFormatPanel::numOfChannelsChanged,
+            &demoReader, &DemoReader::setNumOfChannels);
 }
 
 DataFormatPanel::~DataFormatPanel()
@@ -80,246 +80,68 @@ DataFormatPanel::~DataFormatPanel()
     delete ui;
 }
 
-void DataFormatPanel::onNumberFormatButtonToggled(int numberFormatId,
-                                                  bool checked)
-{
-    if (checked) selectNumberFormat((NumberFormat) numberFormatId);
-}
-
-void DataFormatPanel::selectNumberFormat(NumberFormat numberFormatId)
-{
-    numberFormat = numberFormatId;
-
-    switch(numberFormat)
-    {
-        case NumberFormat_uint8:
-            sampleSize = 1;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_int8:
-            sampleSize = 1;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_uint16:
-            sampleSize = 2;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_int16:
-            sampleSize = 2;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_uint32:
-            sampleSize = 4;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_int32:
-            sampleSize = 4;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_float:
-            sampleSize = 4;
-            readSample = &DataFormatPanel::readSampleAs;
-            break;
-        case NumberFormat_ASCII:
-            sampleSize = 0;    // these two members should not be used
-            readSample = NULL; // in this mode
-            break;
-    }
-
-    if (numberFormat == NumberFormat_ASCII)
-    {
-        QObject::disconnect(serialPort, &QSerialPort::readyRead, 0, 0);
-        QObject::connect(this->serialPort, &QSerialPort::readyRead,
-                         this, &DataFormatPanel::onDataReadyASCII);
-    }
-    else
-    {
-        QObject::disconnect(serialPort, &QSerialPort::readyRead, 0, 0);
-        QObject::connect(serialPort, &QSerialPort::readyRead,
-                         this, &DataFormatPanel::onDataReady);
-    }
-
-    emit skipByteEnabledChanged(skipByteEnabled());
-}
-
-bool DataFormatPanel::skipByteEnabled()
-{
-    return numberFormat != NumberFormat_ASCII;
-}
-
 unsigned DataFormatPanel::numOfChannels()
 {
-    return _numOfChannels;
-}
-
-void DataFormatPanel::onNumOfChannelsSP(int value)
-{
-    _numOfChannels = value;
-    emit numOfChannelsChanged(value);
-}
-
-void DataFormatPanel::requestSkipByte()
-{
-    skipByteRequested = true;
+    return currentReader->numOfChannels();
 }
 
 void DataFormatPanel::pause(bool enabled)
 {
     paused = 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::spsTimerTimeout()
-{
-    unsigned currentSps = _samplesPerSecond;
-    _samplesPerSecond = (sampleCount/_numOfChannels)/SPS_UPDATE_TIMEOUT;
-    if (currentSps != _samplesPerSecond)
-    {
-        emit samplesPerSecondChanged(_samplesPerSecond);
-    }
-    sampleCount = 0;
-}
-
-
-void DataFormatPanel::demoTimerTimeout()
-{
-    const double period = 100;
-    demoCount++;
-    if (demoCount >= 100) demoCount = 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)*demoCount)/period)/((2*(ci+1))*M_PI);
-            addChannelData(ci, &value, 1);
-        }
-        emit dataAdded();
-    }
-}
-
-void DataFormatPanel::onDataReady()
-{
-    // a package is a set of channel data like {CHAN0_SAMPLE, CHAN1_SAMPLE...}
-    int packageSize = sampleSize * _numOfChannels;
-    int bytesAvailable = serialPort->bytesAvailable();
-    int numOfPackagesToRead =
-        (bytesAvailable - (bytesAvailable % packageSize)) / packageSize;
-
-    if (paused)
-    {
-        // read and discard data
-        serialPort->read(numOfPackagesToRead*packageSize);
-        return;
-    }
-
-    if (bytesAvailable > 0 && skipByteRequested)
-    {
-        serialPort->read(1);
-        skipByteRequested = false;
-        bytesAvailable--;
-    }
-
-    if (bytesAvailable < packageSize) return;
-
-    double* channelSamples = new double[numOfPackagesToRead*_numOfChannels];
-
-    for (int i = 0; i < numOfPackagesToRead; i++)
-    {
-        for (unsigned int ci = 0; ci < _numOfChannels; ci++)
-        {
-            // channelSamples[ci].replace(i, (this->*readSample)());
-            channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)();
-        }
+        demoReader.enable(false);
+        disconnect(&demoReader, 0, this, 0);
     }
-
-    for (unsigned int ci = 0; ci < _numOfChannels; ci++)
-    {
-        addChannelData(ci,
-                       channelSamples + ci*numOfPackagesToRead,
-                       numOfPackagesToRead);
-    }
-    emit dataAdded();
-
-    delete channelSamples;
-}
-
-void DataFormatPanel::onDataReadyASCII()
-{
-    while(serialPort->canReadLine())
-    {
-        QByteArray line = serialPort->readLine();
-
-        // discard data if paused
-        if (paused)
-        {
-            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, &channelSample, 1);
-            }
-            else
-            {
-                qWarning() << "Data parsing error for channel: " << ci;
-            }
-        }
-        emit dataAdded();
-    }
-}
-
-template double DataFormatPanel::readSampleAs()
-{
-    T data;
-    serialPort->read((char*) &data, sizeof(data));
-
-    if (ui->rbLittleE->isChecked())
-    {
-        data = qFromLittleEndian(data);
-    }
-    else
-    {
-        data = qFromBigEndian(data);
-    }
-
-    return double(data);
 }
 
 void DataFormatPanel::addChannelData(unsigned int channel,
                                      double* data, unsigned size)
 {
     _channelMan->addChannelData(channel, data, size);
-    sampleCount += size;
 }
+
+void DataFormatPanel::selectReader(AbstractReader* reader)
+{
+    currentReader->enable(false);
+    reader->enable();
+
+    // re-connect signals
+    disconnect(currentReader, 0, this, 0);
+    connect(reader, SIGNAL(dataAdded()), this, SIGNAL(dataAdded()));
+    connect(reader, SIGNAL(numOfChannelsChanged(unsigned)),
+            this, SIGNAL(numOfChannelsChanged(unsigned)));
+    connect(reader, SIGNAL(samplesPerSecondChanged(unsigned)),
+            this, SIGNAL(samplesPerSecondChanged(unsigned)));
+
+    // switch the settings widget
+    ui->horizontalLayout->removeWidget(currentReader->settingsWidget());
+    currentReader->settingsWidget()->hide();
+    ui->horizontalLayout->addWidget(reader->settingsWidget(), 1);
+    reader->settingsWidget()->show();
+
+    // notify if number of channels is different
+    if (currentReader->numOfChannels() != reader->numOfChannels())
+    {
+        emit numOfChannelsChanged(reader->numOfChannels());
+    }
+
+    // pause
+    reader->pause(paused);
+
+    currentReader = reader;
+}
diff --git a/src/dataformatpanel.h b/src/dataformatpanel.h
--- a/src/dataformatpanel.h
+++ b/src/dataformatpanel.h
@@ -1,5 +1,5 @@
 /*
-  Copyright © 2015 Hasan Yavuz Özderya
+  Copyright © 2016 Hasan Yavuz Özderya
 
   This file is part of serialplot.
 
@@ -29,6 +29,10 @@
 
 #include "framebuffer.h"
 #include "channelmanager.h"
+#include "binarystreamreader.h"
+#include "asciireader.h"
+#include "demoreader.h"
+#include "framedreader.h"
 
 namespace Ui {
 class DataFormatPanel;
@@ -45,74 +49,36 @@ public:
     ~DataFormatPanel();
 
     unsigned numOfChannels();
-    unsigned samplesPerSecond();
-    bool skipByteEnabled(void); // true for binary formats
 
 public slots:
-    // during next read operation reader will skip 1 byte,
-    // requests are not accumulated
-    void requestSkipByte();
     void pause(bool);
     void enableDemo(bool); // demo shouldn't be enabled when port is open
 
 signals:
     void numOfChannelsChanged(unsigned);
     void samplesPerSecondChanged(unsigned);
-    void skipByteEnabledChanged(bool);
     void dataAdded();
 
 private:
-    enum NumberFormat
-    {
-        NumberFormat_uint8,
-        NumberFormat_uint16,
-        NumberFormat_uint32,
-        NumberFormat_int8,
-        NumberFormat_int16,
-        NumberFormat_int32,
-        NumberFormat_float,
-        NumberFormat_ASCII
-    };
-
     Ui::DataFormatPanel *ui;
-    QButtonGroup numberFormatButtons;
 
     QSerialPort* serialPort;
     ChannelManager* _channelMan;
 
-    unsigned int _numOfChannels;
-    NumberFormat numberFormat;
-    unsigned int sampleSize; // number of bytes in the selected number format
-    bool skipByteRequested;
+    BinaryStreamReader bsReader;
+    AsciiReader asciiReader;
+    FramedReader framedReader;
+    /// Currently selected reader
+    AbstractReader* currentReader;
+    /// Disable current reader and enable a another one
+    void selectReader(AbstractReader* reader);
+
     bool paused;
 
-    const int SPS_UPDATE_TIMEOUT = 1;  // second
-    unsigned _samplesPerSecond;
-    unsigned int sampleCount;
-    QTimer spsTimer;
-
-    // demo
-    QTimer demoTimer;
-    int demoCount;
-
-    void selectNumberFormat(NumberFormat numberFormatId);
-
-    // points to the readSampleAs function for currently selected number format
-    double (DataFormatPanel::*readSample)();
-
-    // note that serialPort should already have enough bytes present
-    template double readSampleAs();
+    DemoReader demoReader;
 
     // `data` contains i th channels data
     void addChannelData(unsigned int channel, double* data, unsigned size);
-
-private slots:
-    void onDataReady();      // used with binary number formats
-    void onDataReadyASCII(); // used with ASCII number format
-    void onNumberFormatButtonToggled(int numberFormatId, bool checked);
-    void onNumOfChannelsSP(int value);
-    void spsTimerTimeout();
-    void demoTimerTimeout();
 };
 
 #endif // DATAFORMATPANEL_H
diff --git a/src/dataformatpanel.ui b/src/dataformatpanel.ui
--- a/src/dataformatpanel.ui
+++ b/src/dataformatpanel.ui
@@ -15,195 +15,38 @@
   
   
    - 
-    
-     
- 
-      
-       
-        Number Of Channels:
+    
+     
- 
+      
+       
+        Data is sent as consecutive samples in binary form. Syncing can be a problem.
        
-      
-     
 
-     - 
-      
-       
-        
-         60
-         0
-        
+       
+        Simple Binary
        
-       
-        false
-       
-       
-        1
-       
-       
-        32
+       
+        true
        
       
      
 
-    
-    
-   - 
-    
-     
-      Qt::Vertical
-     
-    
-   
 
-   - 
-    
-     
-      0
-     
      
- 
-      
-       
-        Number Format:
+      
+       
+        Data is sent in the form of ASCII text as comma seperated values. Easy to implement.
        
-       
-        
- 
-         
-          
-           unsigned 4 bytes integer
-          
-          
-           uint32
-          
-         
-        
 
-        - 
-         
-          
-           signed 1 byte integer
-          
-          
-           int8
-          
-         
-        
 
-        - 
-         
-          
-           unsigned 1 byte integer
-          
-          
-           uint8
-          
-          
-           true
-          
-         
-        
 
-        - 
-         
-          
-           Comma Separated Values
-          
-          
-           ASCII(CSV)
-          
-         
-        
 
-        - 
-         
-          
-           signed 2 bytes integer
-          
-          
-           int16
-          
-         
-        
 
-        - 
-         
-          
-           signed 4 bytes integer
-          
-          
-           int32
-          
-         
-        
 
-        - 
-         
-          
-           4 bytes floating point number
-          
-          
-           float
-          
-         
-        
 
-        - 
-         
-          
-           unsigned 2 bytes integer
-          
-          
-           uint16
-          
-         
-        
 
-       
+       
+        ASCII
+       
       
       
      - 
-      
-       
-        Qt::Vertical
-       
-       
-        
-         20
-         1
-        
-       
-      
-     
 
-    
-    
-   - 
-    
-     
-      0
-     
-     
- 
-      
-       
-        
-         0
-         0
-        
+      
+       
+        Define a custom binary frame. Powerful.
        
-       
-        Byte Order:
+       
+        Custom Frame
        
-       
-        
- 
-         
-          
-           least significant byte first
-          
-          
-           Little Endian
-          
-          
-           true
-          
-         
-        
 
-        - 
-         
-          
-           most significant byte first
-          
-          
-           Big Endian
-          
-         
-        
 
-       
       
       
      - 
@@ -214,7 +57,7 @@
        
         
          20
-         1
+         40
         
        
       
@@ -222,20 +65,11 @@
     
 
     
    - 
-    
+    
      
-      Qt::Horizontal
-     
-     
-      QSizePolicy::MinimumExpanding
+      Qt::Vertical
      
-     
-      
-       37
-       20
-      
-     
-    
+    
    
 
   
  
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
diff --git a/src/endiannessbox.cpp b/src/endiannessbox.cpp
new file mode 100644
--- /dev/null
+++ b/src/endiannessbox.cpp
@@ -0,0 +1,50 @@
+/*
+  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 "endiannessbox.h"
+#include "ui_endiannessbox.h"
+
+EndiannessBox::EndiannessBox(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::EndiannessBox)
+{
+    ui->setupUi(this);
+
+    connect(ui->rbLittleE, &QRadioButton::toggled, [this](bool checked)
+            {
+                emit selectionChanged(currentSelection());
+            });
+}
+
+EndiannessBox::~EndiannessBox()
+{
+    delete ui;
+}
+
+Endianness EndiannessBox::currentSelection()
+{
+    if (ui->rbLittleE->isChecked())
+    {
+        return LittleEndian;
+    }
+    else
+    {
+        return BigEndian;
+    }
+}
diff --git a/src/endiannessbox.h b/src/endiannessbox.h
new file mode 100644
--- /dev/null
+++ b/src/endiannessbox.h
@@ -0,0 +1,53 @@
+/*
+  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 ENDIANNESSBOX_H
+#define ENDIANNESSBOX_H
+
+#include 
+
+namespace Ui {
+class EndiannessBox;
+}
+
+enum Endianness
+{
+    LittleEndian,
+    BigEndian
+};
+
+class EndiannessBox : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit EndiannessBox(QWidget *parent = 0);
+    ~EndiannessBox();
+
+    Endianness currentSelection(); ///< currently selected endianness
+
+signals:
+    /// Signaled when endianness selection is changed
+    void selectionChanged(Endianness endianness);
+
+private:
+    Ui::EndiannessBox *ui;
+};
+
+#endif // ENDIANNESSBOX_H
diff --git a/src/endiannessbox.ui b/src/endiannessbox.ui
new file mode 100644
--- /dev/null
+++ b/src/endiannessbox.ui
@@ -0,0 +1,59 @@
+
+
+ EndiannessBox
+ 
+  
+   
+    0
+    0
+    202
+    22
+   
+  
+  
+   EndiannessBox
+  
+  
+   
+    3
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   - 
+    
+     
+      least significant byte first
+     
+     
+      Little Endian
+     
+     
+      true
+     
+    
+   
 
+   - 
+    
+     
+      most significant byte first
+     
+     
+      Big Endian
+     
+    
+   
 
+  
+ 
+ 
+ 
+
diff --git a/src/framedreader.cpp b/src/framedreader.cpp
new file mode 100644
--- /dev/null
+++ b/src/framedreader.cpp
@@ -0,0 +1,345 @@
+/*
+  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 
+#include 
+#include "floatswap.h"
+
+#include "framedreader.h"
+
+FramedReader::FramedReader(QIODevice* device, ChannelManager* channelMan, QObject *parent) :
+    AbstractReader(device, channelMan, parent)
+{
+    paused = false;
+
+    // initial settings
+    settingsInvalid = 0;
+    _numOfChannels = _settingsWidget.numOfChannels();
+    hasSizeByte = _settingsWidget.frameSize() == 0;
+    frameSize = _settingsWidget.frameSize();
+    syncWord = _settingsWidget.syncWord();
+    checksumEnabled = _settingsWidget.isChecksumEnabled();
+    onNumberFormatChanged(_settingsWidget.numberFormat());
+    debugModeEnabled = _settingsWidget.isDebugModeEnabled();
+    checkSettings();
+
+    // init setting connections
+    connect(&_settingsWidget, &FramedReaderSettings::numberFormatChanged,
+            this, &FramedReader::onNumberFormatChanged);
+
+    connect(&_settingsWidget, &FramedReaderSettings::numOfChannelsChanged,
+            this, &FramedReader::onNumOfChannelsChanged);
+
+    connect(&_settingsWidget, &FramedReaderSettings::syncWordChanged,
+            this, &FramedReader::onSyncWordChanged);
+
+    connect(&_settingsWidget, &FramedReaderSettings::frameSizeChanged,
+            this, &FramedReader::onFrameSizeChanged);
+
+    connect(&_settingsWidget, &FramedReaderSettings::checksumChanged,
+            [this](bool enabled){checksumEnabled = enabled; reset();});
+
+    connect(&_settingsWidget, &FramedReaderSettings::debugModeChanged,
+            [this](bool enabled){debugModeEnabled = enabled;});
+
+    // init reader state
+    reset();
+}
+
+void FramedReader::enable(bool enabled)
+{
+    if (enabled)
+    {
+        connect(_device, &QIODevice::readyRead,
+                this, &FramedReader::onDataReady);
+    }
+    else
+    {
+        QObject::disconnect(_device, 0, this, 0);
+    }
+}
+
+QWidget* FramedReader::settingsWidget()
+{
+    return &_settingsWidget;
+}
+
+unsigned FramedReader::numOfChannels()
+{
+    return _numOfChannels;
+}
+
+void FramedReader::pause(bool enabled)
+{
+    paused = enabled;
+}
+
+void FramedReader::onNumberFormatChanged(NumberFormat numberFormat)
+{
+    switch(numberFormat)
+    {
+        case NumberFormat_uint8:
+            sampleSize = 1;
+            readSample = &FramedReader::readSampleAs;
+            break;
+        case NumberFormat_int8:
+            sampleSize = 1;
+            readSample = &FramedReader::readSampleAs;
+            break;
+        case NumberFormat_uint16:
+            sampleSize = 2;
+            readSample = &FramedReader::readSampleAs;
+            break;
+        case NumberFormat_int16:
+            sampleSize = 2;
+            readSample = &FramedReader::readSampleAs;
+            break;
+        case NumberFormat_uint32:
+            sampleSize = 4;
+            readSample = &FramedReader::readSampleAs;
+            break;
+        case NumberFormat_int32:
+            sampleSize = 4;
+            readSample = &FramedReader::readSampleAs;
+            break;
+        case NumberFormat_float:
+            sampleSize = 4;
+            readSample = &FramedReader::readSampleAs;
+            break;
+    }
+
+    checkSettings();
+    reset();
+}
+
+void FramedReader::checkSettings()
+{
+    // sync word is invalid (empty or missing a nibble at the end)
+    if (!syncWord.size())
+    {
+        settingsInvalid |= SYNCWORD_INVALID;
+    }
+    else // sync word is valid
+    {
+        settingsInvalid &= ~SYNCWORD_INVALID;
+    }
+
+    // check if fixed frame size is multiple of a sample set size
+    if (!hasSizeByte && frameSize % (_numOfChannels * sampleSize) != 0)
+    {
+        settingsInvalid |= FRAMESIZE_INVALID;
+    }
+    else
+    {
+        settingsInvalid &= ~FRAMESIZE_INVALID;
+    }
+
+    // show an error message
+    if (settingsInvalid & SYNCWORD_INVALID)
+    {
+        _settingsWidget.showMessage("Sync word is invalid!", true);
+    }
+    else if (settingsInvalid & FRAMESIZE_INVALID)
+    {
+        QString errorMessage =
+            QString("Frame size must be multiple of %1 (#channels * sample size)!")\
+            .arg(_numOfChannels * sampleSize);
+
+        _settingsWidget.showMessage(errorMessage, true);
+    }
+    else
+    {
+        _settingsWidget.showMessage("All is well!");
+    }
+}
+
+void FramedReader::onNumOfChannelsChanged(unsigned value)
+{
+    _numOfChannels = value;
+    checkSettings();
+    reset();
+    emit numOfChannelsChanged(value);
+}
+
+void FramedReader::onSyncWordChanged(QByteArray word)
+{
+    syncWord = word;
+    checkSettings();
+    reset();
+}
+
+void FramedReader::onFrameSizeChanged(unsigned value)
+{
+    if (value == 0)
+    {
+        hasSizeByte = true;
+    }
+    else
+    {
+        hasSizeByte = false;
+        frameSize = value;
+    }
+    checkSettings();
+    reset();
+}
+
+void FramedReader::onDataReady()
+{
+    if (settingsInvalid) return;
+
+    // loop until we run out of bytes or more bytes is required
+    unsigned bytesAvailable;
+    while ((bytesAvailable = _device->bytesAvailable()))
+    {
+        if (!gotSync) // read sync word
+        {
+            char c;
+            _device->getChar(&c);
+            if (c == syncWord[sync_i]) // correct sync byte?
+            {
+                sync_i++;
+                if (sync_i == (unsigned) syncWord.length())
+                {
+                    gotSync = true;
+                }
+            }
+            else
+            {
+                if (debugModeEnabled) qCritical() << "Missed " << sync_i+1 << "th sync byte.";
+            }
+        }
+        else if (hasSizeByte && !gotSize) // skipped if fixed frame size
+        {
+            frameSize = 0;
+            _device->getChar((char*) &frameSize);
+
+            if (frameSize == 0) // check size
+            {
+                qCritical() << "Frame size is 0!";
+                reset();
+            }
+            else if (frameSize % (_numOfChannels * sampleSize) != 0)
+            {
+                qCritical() <<
+                    QString("Frame size is not multiple of %1 (#channels * sample size)!") \
+                    .arg(_numOfChannels * sampleSize);
+                reset();
+            }
+            else
+            {
+                if (debugModeEnabled) qDebug() << "Frame size:" << frameSize;
+                gotSize = true;
+            }
+        }
+        else // read data bytes
+        {
+            // have enough data bytes? (+1 for checksum)
+            if (bytesAvailable < (checksumEnabled ? frameSize+1 : frameSize))
+            {
+                break;
+            }
+            else // read data bytes and checksum
+            {
+                readFrameDataAndCheck();
+                reset();
+            }
+        }
+    }
+}
+
+void FramedReader::reset()
+{
+    sync_i = 0;
+    gotSync = false;
+    gotSize = false;
+    if (hasSizeByte) frameSize = 0;
+    calcChecksum = 0;
+}
+
+// Important: this function assumes device has enough bytes to read a full frames data and checksum
+void FramedReader::readFrameDataAndCheck()
+{
+    // a package is 1 set of samples for all channels
+    unsigned numOfPackagesToRead = frameSize / (_numOfChannels * sampleSize);
+    double* channelSamples = new double[numOfPackagesToRead * _numOfChannels];
+
+    for (unsigned i = 0; i < numOfPackagesToRead; i++)
+    {
+        for (unsigned int ci = 0; ci < _numOfChannels; ci++)
+        {
+            channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)();
+        }
+    }
+
+    // read checksum
+    unsigned rChecksum = 0;
+    bool checksumPassed = false;
+    if (checksumEnabled)
+    {
+        _device->read((char*) &rChecksum, 1);
+        calcChecksum &= 0xFF;
+        checksumPassed = (calcChecksum == rChecksum);
+    }
+
+    if (!checksumEnabled || checksumPassed)
+    {
+        // commit data
+        for (unsigned int ci = 0; ci < _numOfChannels; ci++)
+        {
+            _channelMan->addChannelData(
+                ci,
+                channelSamples + ci*numOfPackagesToRead,
+                numOfPackagesToRead);
+            sampleCount += numOfPackagesToRead;
+        }
+        emit dataAdded();
+    }
+    else
+    {
+        qCritical() << "Checksum failed! Received:" << rChecksum << "Calculated:" << calcChecksum;
+    }
+
+    delete channelSamples;
+}
+
+template double FramedReader::readSampleAs()
+{
+    T data;
+
+    _device->read((char*) &data, sizeof(data));
+
+    if (checksumEnabled)
+    {
+        for (unsigned i = 0; i < sizeof(data); i++)
+        {
+            calcChecksum += ((unsigned char*) &data)[i];
+        }
+    }
+
+    if (_settingsWidget.endianness() == LittleEndian)
+    {
+        data = qFromLittleEndian(data);
+    }
+    else
+    {
+        data = qFromBigEndian(data);
+    }
+
+    return double(data);
+}
diff --git a/src/framedreader.h b/src/framedreader.h
new file mode 100644
--- /dev/null
+++ b/src/framedreader.h
@@ -0,0 +1,92 @@
+/*
+  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 FRAMEDREADER_H
+#define FRAMEDREADER_H
+
+#include "abstractreader.h"
+#include "framedreadersettings.h"
+
+/**
+ * Reads data in a customizable framed format.
+ */
+class FramedReader : public AbstractReader
+{
+    Q_OBJECT
+
+public:
+    explicit FramedReader(QIODevice* device, ChannelManager* channelMan, QObject *parent = 0);
+    QWidget* settingsWidget();
+    unsigned numOfChannels();
+    void enable(bool enabled = true);
+
+public slots:
+    void pause(bool);
+
+private:
+    /// bit wise fields for `settingsValid` member
+    enum SettingInvalidFlag
+    {
+        SYNCWORD_INVALID = 1,
+        FRAMESIZE_INVALID = 2
+    };
+
+    // settings related members
+    FramedReaderSettings _settingsWidget;
+    unsigned _numOfChannels;
+    unsigned sampleSize;
+    bool paused;
+    unsigned settingsInvalid;   /// settings are all valid if this is 0, if not no reading is done
+    QByteArray syncWord;
+    bool checksumEnabled;
+    bool hasSizeByte;
+    unsigned frameSize;
+    bool debugModeEnabled;
+
+    /// Checks the validity of syncWord and frameSize then shows an
+    /// error message. Also updates `settingsInvalid`. If settings are
+    /// valid `settingsInvalid` should be `0`.
+    void checkSettings();
+
+    // read state related members
+    unsigned sync_i; /// sync byte index to be read next
+    bool gotSync;    /// indicates if sync word is captured
+    bool gotSize;    /// indicates if size is captured, ignored if size byte is disabled (fixed size)
+    unsigned calcChecksum;
+
+    void reset();    /// Resets the reading state. Used in case of error or setting change.
+    /// points to the readSampleAs function for currently selected number format
+    double (FramedReader::*readSample)();
+    template double readSampleAs();
+    /// reads payload portion of the frame, calculates checksum and commits data
+    /// @note should be called only if there are enough bytes on device
+    void readFrameDataAndCheck();
+    // `data` contains i th channels data
+    void addChannelData(unsigned int channel, double* data, unsigned size);
+
+private slots:
+    void onDataReady();
+
+    void onNumberFormatChanged(NumberFormat numberFormat);
+    void onNumOfChannelsChanged(unsigned value);
+    void onSyncWordChanged(QByteArray);
+    void onFrameSizeChanged(unsigned);
+};
+
+#endif // FRAMEDREADER_H
diff --git a/src/framedreadersettings.cpp b/src/framedreadersettings.cpp
new file mode 100644
--- /dev/null
+++ b/src/framedreadersettings.cpp
@@ -0,0 +1,146 @@
+/*
+  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 "utils.h"
+#include "framedreadersettings.h"
+#include "ui_framedreadersettings.h"
+
+FramedReaderSettings::FramedReaderSettings(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::FramedReaderSettings)
+{
+    ui->setupUi(this);
+
+    ui->leSyncWord->setMode(false); // hex mode
+    ui->leSyncWord->setText("AA BB");
+
+    connect(ui->cbChecksum, &QCheckBox::toggled,
+            [this](bool enabled)
+            {
+                emit checksumChanged(enabled);
+            });
+
+    connect(ui->cbDebugMode, &QCheckBox::toggled,
+            this, &FramedReaderSettings::debugModeChanged);
+
+    connect(ui->rbFixedSize, &QRadioButton::toggled,
+            ui->spSize, &QWidget::setEnabled);
+
+    connect(ui->rbFixedSize, &QRadioButton::toggled,
+            [this](bool checked)
+            {
+                emit frameSizeChanged(frameSize());
+            });
+
+    // Note: if directly connected we get a runtime warning on incompatible signal arguments
+    connect(ui->spSize, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged),
+            [this](int value)
+            {
+                emit frameSizeChanged(value);
+            });
+
+    connect(ui->spNumOfChannels, SELECT::OVERLOAD_OF(&QSpinBox::valueChanged),
+            [this](int value)
+            {
+                emit numOfChannelsChanged(value);
+            });
+
+    connect(ui->leSyncWord, &QLineEdit::textChanged,
+            this, &FramedReaderSettings::onSyncWordEdited);
+
+    connect(ui->nfBox, SIGNAL(selectionChanged(NumberFormat)),
+            this, SIGNAL(numberFormatChanged(NumberFormat)));
+}
+
+FramedReaderSettings::~FramedReaderSettings()
+{
+    delete ui;
+}
+
+void FramedReaderSettings::showMessage(QString message, bool error)
+{
+    ui->lMessage->setText(message);
+    if (error)
+    {
+        ui->lMessage->setStyleSheet("color: red;");
+    }
+    else
+    {
+        ui->lMessage->setStyleSheet("");
+    }
+}
+
+unsigned FramedReaderSettings::numOfChannels()
+{
+    return ui->spNumOfChannels->value();
+}
+
+NumberFormat FramedReaderSettings::numberFormat()
+{
+    return ui->nfBox->currentSelection();
+}
+
+Endianness FramedReaderSettings::endianness()
+{
+    return ui->endiBox->currentSelection();
+}
+
+QByteArray FramedReaderSettings::syncWord()
+{
+    QString text = ui->leSyncWord->text().remove(' ');
+
+    // check if nibble is missing
+    if (text.size() % 2 == 1)
+    {
+        // TODO: remove this warning
+        return QByteArray();
+    }
+    else
+    {
+        return QByteArray::fromHex(text.toLatin1());
+    }
+}
+
+void FramedReaderSettings::onSyncWordEdited()
+{
+    // TODO: emit with a delay so that error message doesn't flash!
+    emit syncWordChanged(syncWord());
+}
+
+unsigned FramedReaderSettings::frameSize()
+{
+    if (ui->rbFixedSize->isChecked())
+    {
+        return ui->spSize->value();
+    }
+    else
+    {
+        return 0; // frame byte is enabled
+    }
+}
+
+bool FramedReaderSettings::isChecksumEnabled()
+{
+    return ui->cbChecksum->isChecked();
+}
+
+bool FramedReaderSettings::isDebugModeEnabled()
+{
+    return ui->cbDebugMode->isChecked();
+}
diff --git a/src/framedreadersettings.h b/src/framedreadersettings.h
new file mode 100644
--- /dev/null
+++ b/src/framedreadersettings.h
@@ -0,0 +1,69 @@
+/*
+  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 FRAMEDREADERSETTINGS_H
+#define FRAMEDREADERSETTINGS_H
+
+#include 
+#include 
+
+#include "numberformatbox.h"
+#include "endiannessbox.h"
+
+namespace Ui {
+class FramedReaderSettings;
+}
+
+class FramedReaderSettings : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit FramedReaderSettings(QWidget *parent = 0);
+    ~FramedReaderSettings();
+
+    void showMessage(QString message, bool error = false);
+
+    unsigned numOfChannels();
+    NumberFormat numberFormat();
+    Endianness endianness();
+    QByteArray syncWord();
+    unsigned frameSize(); /// If frame bye is enabled `0` is returned
+    bool isChecksumEnabled();
+    bool isDebugModeEnabled();
+
+signals:
+    /// If sync word is invalid (empty or 1 nibble missing at the end)
+    /// signaled with an empty array
+    void syncWordChanged(QByteArray);
+    /// `0` indicates frame size byte is enabled
+    void frameSizeChanged(unsigned);
+    void checksumChanged(bool);
+    void numOfChannelsChanged(unsigned);
+    void numberFormatChanged(NumberFormat);
+    void debugModeChanged(bool);
+
+private:
+    Ui::FramedReaderSettings *ui;
+
+private slots:
+    void onSyncWordEdited();
+};
+
+#endif // FRAMEDREADERSETTINGS_H
diff --git a/src/framedreadersettings.ui b/src/framedreadersettings.ui
new file mode 100644
--- /dev/null
+++ b/src/framedreadersettings.ui
@@ -0,0 +1,239 @@
+
+
+ FramedReaderSettings
+ 
+  
+   
+    0
+    0
+    852
+    222
+   
+  
+  
+   Form
+  
+  
+   
+    3
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   - 
+    
+     
+      QFormLayout::FieldsStayAtSizeHint
+     
+     
- 
+      
+       
+        Enter the 'Frame Start' bytes in hexadecimal.
+       
+      
+     
 
+     - 
+      
+       
+        Number of Channels
+       
+       
+        # Channels:
+       
+      
+     
 
+     - 
+      
+       
+        Select number of channels
+       
+       
+        1
+       
+       
+        32
+       
+      
+     
 
+     - 
+      
+       
+        Frame Size:
+       
+      
+     
 
+     - 
+      
+       
- 
+        
+         
+          Frame size is always the same
+         
+         
+          Fixed Size:
+         
+        
+       
 
+       - 
+        
+         
+          false
+         
+         
+          <html><head/><body><p>Enter the frame size. It <span style=" font-weight:600;">must</span> be the multiple of (#channels * sample size).</p></body></html>
+         
+         
+          1
+         
+         
+          255
+         
+        
+       
 
+       - 
+        
+         
+          First byte after the 'frame start' bytes should be the size of the frame. Not counting itself and checksum.
+         
+         
+          First byte of the payload is size
+         
+         
+          true
+         
+        
+       
 
+      
+      
+     - 
+      
+       
+        
+       
+       
+        Number Type:
+       
+      
+     
 
+     - 
+      
+       
+        
+         0
+         0
+        
+       
+      
+     
 
+     - 
+      
+       
+        Byte Order
+       
+       
+        Endianness:
+       
+      
+     
 
+     - 
+      
+     
 
+     - 
+      
+       
+        Checksum:
+       
+      
+     
 
+     - 
+      
+       
+        Last byte of the frame is checksum.
+       
+       
+        Enabled
+       
+      
+     
 
+     - 
+      
+       
+        Frame Start:
+       
+      
+     
 
+    
+    
+   - 
+    
+     
+      Qt::Vertical
+     
+     
+      
+       20
+       1
+      
+     
+    
+   
 
+   - 
+    
+     
- 
+      
+       
+        
+         0
+         0
+        
+       
+       
+        All is well.
+       
+      
+     
 
+     - 
+      
+       
+        Enable printing of extra log messages that can be useful for debugging
+       
+       
+        Debug Mode
+       
+      
+     
 
+    
+    
+  
+ 
+ 
+  
+   NumberFormatBox
+   QWidget
+   
+   1
+  
+  
+   EndiannessBox
+   QWidget
+   
+   1
+  
+  
+   CommandEdit
+   QLineEdit
+   
+  
+ 
+ 
+ 
+
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -105,9 +105,6 @@ MainWindow::MainWindow(QWidget *parent) 
     QObject::connect(&portControl, &PortControl::portToggled,
                      this, &MainWindow::onPortToggled);
 
-    QObject::connect(&portControl, &PortControl::skipByteRequested,
-                     &dataFormatPanel, &DataFormatPanel::requestSkipByte);
-
     connect(&plotControlPanel, &PlotControlPanel::numOfSamplesChanged,
             this, &MainWindow::onNumOfSamplesChanged);
 
diff --git a/src/numberformatbox.cpp b/src/numberformatbox.cpp
new file mode 100644
--- /dev/null
+++ b/src/numberformatbox.cpp
@@ -0,0 +1,56 @@
+/*
+  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 "numberformatbox.h"
+#include "ui_numberformatbox.h"
+
+NumberFormatBox::NumberFormatBox(QWidget *parent) :
+    QWidget(parent),
+    ui(new Ui::NumberFormatBox)
+{
+    ui->setupUi(this);
+
+    // setup buttons
+    buttonGroup.addButton(ui->rbUint8,  NumberFormat_uint8);
+    buttonGroup.addButton(ui->rbUint16, NumberFormat_uint16);
+    buttonGroup.addButton(ui->rbUint32, NumberFormat_uint32);
+    buttonGroup.addButton(ui->rbInt8,   NumberFormat_int8);
+    buttonGroup.addButton(ui->rbInt16,  NumberFormat_int16);
+    buttonGroup.addButton(ui->rbInt32,  NumberFormat_int32);
+    buttonGroup.addButton(ui->rbFloat,  NumberFormat_float);
+
+    QObject::connect(
+        &buttonGroup, SIGNAL(buttonToggled(int, bool)),
+        this, SLOT(onButtonToggled(int, bool)));
+}
+
+NumberFormatBox::~NumberFormatBox()
+{
+    delete ui;
+}
+
+void NumberFormatBox::onButtonToggled(int numberFormatId, bool checked)
+{
+    if (checked) emit selectionChanged((NumberFormat) numberFormatId);
+}
+
+NumberFormat NumberFormatBox::currentSelection()
+{
+    return (NumberFormat) buttonGroup.checkedId();
+}
diff --git a/src/numberformatbox.h b/src/numberformatbox.h
new file mode 100644
--- /dev/null
+++ b/src/numberformatbox.h
@@ -0,0 +1,63 @@
+/*
+  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 NUMBERFORMATBOX_H
+#define NUMBERFORMATBOX_H
+
+#include 
+#include 
+
+namespace Ui {
+class NumberFormatBox;
+}
+
+enum NumberFormat
+{
+    NumberFormat_uint8,
+    NumberFormat_uint16,
+    NumberFormat_uint32,
+    NumberFormat_int8,
+    NumberFormat_int16,
+    NumberFormat_int32,
+    NumberFormat_float,
+};
+
+class NumberFormatBox : public QWidget
+{
+    Q_OBJECT
+
+public:
+    explicit NumberFormatBox(QWidget *parent = 0);
+    ~NumberFormatBox();
+
+    NumberFormat currentSelection(); ///< returns the currently selected number format
+
+signals:
+    /// Signaled when number format selection is changed
+    void selectionChanged(NumberFormat numberFormat);
+
+private:
+    Ui::NumberFormatBox *ui;
+    QButtonGroup buttonGroup;
+
+private slots:
+    void onButtonToggled(int numberFormatId, bool checked);
+};
+
+#endif // NUMBERFORMATBOX_H
diff --git a/src/numberformatbox.ui b/src/numberformatbox.ui
new file mode 100644
--- /dev/null
+++ b/src/numberformatbox.ui
@@ -0,0 +1,109 @@
+
+
+ NumberFormatBox
+ 
+  
+   
+    0
+    0
+    440
+    22
+   
+  
+  
+   NumberFormat
+  
+  
+   
+    3
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   
+    0
+   
+   - 
+    
+     
+      unsigned 1 byte integer
+     
+     
+      uint8
+     
+     
+      true
+     
+    
+   
 
+   - 
+    
+     
+      unsigned 2 bytes integer
+     
+     
+      uint16
+     
+    
+   
 
+   - 
+    
+     
+      unsigned 4 bytes integer
+     
+     
+      uint32
+     
+    
+   
 
+   - 
+    
+     
+      signed 1 byte integer
+     
+     
+      int8
+     
+    
+   
 
+   - 
+    
+     
+      signed 2 bytes integer
+     
+     
+      int16
+     
+    
+   
 
+   - 
+    
+     
+      signed 4 bytes integer
+     
+     
+      int32
+     
+    
+   
 
+   - 
+    
+     
+      4 bytes floating point number
+     
+     
+      float
+     
+    
+   
 
+  
+ 
+ 
+ 
+
diff --git a/src/portcontrol.cpp b/src/portcontrol.cpp
--- a/src/portcontrol.cpp
+++ b/src/portcontrol.cpp
@@ -115,10 +115,6 @@ PortControl::PortControl(QSerialPort* po
                      SELECT::OVERLOAD_OF(&QButtonGroup::buttonClicked),
                      this, &PortControl::selectFlowControl);
 
-    // init skip byte button
-    QObject::connect(ui->pbSkipByte, &QPushButton::clicked,
-                     [this](){emit skipByteRequested();});
-
     loadPortList();
     loadBaudRateList();
     ui->cbBaudRate->setCurrentIndex(ui->cbBaudRate->findText("9600"));
@@ -272,11 +268,6 @@ void PortControl::selectPort(QString por
     }
 }
 
-void PortControl::enableSkipByte(bool enabled)
-{
-    ui->pbSkipByte->setDisabled(enabled);
-}
-
 QToolBar* PortControl::toolBar()
 {
     return &portToolBar;
diff --git a/src/portcontrol.h b/src/portcontrol.h
--- a/src/portcontrol.h
+++ b/src/portcontrol.h
@@ -64,7 +64,6 @@ public slots:
     void loadBaudRateList();
     void togglePort();
     void selectPort(QString portName);
-    void enableSkipByte(bool enabled = true);
 
     void selectBaudRate(QString baudRate);
     void selectParity(int parity); // parity must be one of QSerialPort::Parity
@@ -79,7 +78,6 @@ private slots:
     void onTbPortListActivated(int index);
 
 signals:
-    void skipByteRequested();
     void portToggled(bool open);
 };
 
diff --git a/src/portcontrol.ui b/src/portcontrol.ui
--- a/src/portcontrol.ui
+++ b/src/portcontrol.ui
@@ -7,7 +7,7 @@
     0
     0
     631
-    213
+    232
    
   
   
@@ -285,7 +285,7 @@
        
        
         
-         0
+         85
          50
         
        
@@ -301,16 +301,6 @@
       
       
      - 
-      
-       
-        Skip reading 1 byte to correct the alignment
-       
-       
-        Skip Byte
-       
-      
-     
 
-     - 
       
        
         Qt::Vertical