diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,6 +65,7 @@ qt5_wrap_ui(UI_FILES
   src/endiannessbox.ui
   src/binarystreamreadersettings.ui
   src/asciireadersettings.ui
+  src/framedreadersettings.ui
   )
 
 if (WIN32)
@@ -105,6 +106,8 @@ add_executable(${PROGRAM_NAME} WIN32
   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/serialplot.pro b/serialplot.pro
--- a/serialplot.pro
+++ b/serialplot.pro
@@ -55,7 +55,17 @@ SOURCES += \
     src/sneakylineedit.cpp \
     src/channelmanager.cpp \
     src/framebufferseries.cpp \
-    src/plotcontrolpanel.cpp
+    src/plotcontrolpanel.cpp \
+    src/numberformatbox.cpp \
+    src/endiannessbox.cpp \
+    src/framedreadersettings.cpp \
+    src/abstractreader.cpp \
+    src/binarystreamreader.cpp \
+    src/binarystreamreadersettings.cpp \
+    src/asciireadersettings.cpp \
+    src/asciireader.cpp \
+    src/demoreader.cpp \
+    src/framedreader.cpp
 
 HEADERS += \
     src/mainwindow.h \
@@ -81,7 +91,17 @@ HEADERS += \
     src/sneakylineedit.h \
     src/channelmanager.h \
     src/framebufferseries.h \
-    src/plotcontrolpanel.h
+    src/plotcontrolpanel.h \
+    src/numberformatbox.h \
+    src/endiannessbox.h \
+    src/framedreadersettings.h \
+    src/abstractreader.h \
+    src/binarystreamreader.h \
+    src/binarystreamreadersettings.h \
+    src/asciireadersettings.h \
+    src/asciireader.h \
+    src/demoreader.h \
+    src/framedreader.h
 
 FORMS += \
     src/mainwindow.ui \
@@ -91,7 +111,12 @@ FORMS += \
     src/commandpanel.ui \
     src/commandwidget.ui \
     src/dataformatpanel.ui \
-    src/plotcontrolpanel.ui
+    src/plotcontrolpanel.ui \
+    src/numberformatbox.ui \
+    src/endiannessbox.ui \
+    src/framedreadersettings.ui \
+    src/binarystreamreadersettings.ui \
+    src/asciireadersettings.ui
 
 INCLUDEPATH += qmake/ src/
 
diff --git a/src/dataformatpanel.cpp b/src/dataformatpanel.cpp
--- a/src/dataformatpanel.cpp
+++ b/src/dataformatpanel.cpp
@@ -34,6 +34,7 @@ DataFormatPanel::DataFormatPanel(QSerial
     ui(new Ui::DataFormatPanel),
     bsReader(port, channelMan, this),
     asciiReader(port, channelMan, this),
+    framedReader(port, channelMan, this),
     demoReader(port, channelMan, this)
 {
     ui->setupUi(this);
@@ -64,6 +65,11 @@ DataFormatPanel::DataFormatPanel(QSerial
                 if (checked) selectReader(&asciiReader);
             });
 
+    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);
diff --git a/src/dataformatpanel.h b/src/dataformatpanel.h
--- a/src/dataformatpanel.h
+++ b/src/dataformatpanel.h
@@ -32,6 +32,7 @@
 #include "binarystreamreader.h"
 #include "asciireader.h"
 #include "demoreader.h"
+#include "framedreader.h"
 
 namespace Ui {
 class DataFormatPanel;
@@ -66,6 +67,7 @@ private:
 
     BinaryStreamReader bsReader;
     AsciiReader asciiReader;
+    FramedReader framedReader;
     /// Currently selected reader
     AbstractReader* currentReader;
     /// Disable current reader and enable a another one
diff --git a/src/dataformatpanel.ui b/src/dataformatpanel.ui
--- a/src/dataformatpanel.ui
+++ b/src/dataformatpanel.ui
@@ -34,6 +34,13 @@
       
      
      - 
+      
+       
+        Framed
+       
+      
+     
 
+     - 
       
        
         Qt::Vertical
diff --git a/src/framedreader.cpp b/src/framedreader.cpp
new file mode 100644
--- /dev/null
+++ b/src/framedreader.cpp
@@ -0,0 +1,208 @@
+/*
+  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();
+    hasFrameByte = _settingsWidget.frameSize() == 0;
+    frameSize = _settingsWidget.frameSize();
+    syncWord = _settingsWidget.syncWord();
+    checksumEnabled = _settingsWidget.checksumEnabled();
+    onNumberFormatChanged(_settingsWidget.numberFormat());
+    checkSettings();
+
+    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;});
+}
+
+void FramedReader::enable(bool enabled)
+{
+    if (enabled)
+    {
+        // TODO
+        // QObject::connect(_device, &QIODevice::readyRead,
+                         // this, &BinaryStreamReader::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();
+}
+
+template double FramedReader::readSampleAs()
+{
+    T data;
+
+    _device->read((char*) &data, sizeof(data));
+
+    // TODO: checksum
+
+    if (_settingsWidget.endianness() == LittleEndian)
+    {
+        data = qFromLittleEndian(data);
+    }
+    else
+    {
+        data = qFromBigEndian(data);
+    }
+
+    return double(data);
+}
+
+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 (!hasFrameByte && 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();
+}
+
+void FramedReader::onSyncWordChanged(QByteArray word)
+{
+    syncWord = word;
+    checkSettings();
+}
+
+void FramedReader::onFrameSizeChanged(unsigned value)
+{
+    if (value == 0)
+    {
+        hasFrameByte = true;
+    }
+    else
+    {
+        hasFrameByte = false;
+        frameSize = value;
+    }
+    checkSettings();
+}
diff --git a/src/framedreader.h b/src/framedreader.h
new file mode 100644
--- /dev/null
+++ b/src/framedreader.h
@@ -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 .
+*/
+
+#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
+    };
+
+    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 hasFrameByte;
+    unsigned frameSize;
+
+    // TODO: create a base class that contains common functionality between binary readers
+
+    /// points to the readSampleAs function for currently selected number format
+    double (FramedReader::*readSample)();
+    template double readSampleAs();
+    // `data` contains i th channels data
+    void addChannelData(unsigned int channel, double* data, unsigned size);
+
+    /// 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();
+
+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,137 @@
+/*
+  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
+
+    connect(ui->cbChecksum, &QCheckBox::toggled,
+            [this](bool enabled)
+            {
+                emit checksumChanged(enabled);
+            });
+
+    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::checksumEnabled()
+{
+    return ui->cbChecksum->isChecked();
+}
diff --git a/src/framedreadersettings.h b/src/framedreadersettings.h
new file mode 100644
--- /dev/null
+++ b/src/framedreadersettings.h
@@ -0,0 +1,67 @@
+/*
+  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 checksumEnabled();
+
+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);
+
+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,176 @@
+
+
+ FramedReaderSettings
+ 
+  
+   
+    0
+    0
+    542
+    222
+   
+  
+  
+   Form
+  
+  
+   
+    
+     210
+     40
+     141
+     141
+    
+   
+  
+  
+   
+    
+     360
+     40
+     120
+     80
+    
+   
+  
+  
+   
+    
+     210
+     0
+     211
+     29
+    
+   
+   
+    
- 
+     
+      
+       Number Of Channels:
+      
+     
+    
 
+    - 
+     
+      
+       1
+      
+      
+       32
+      
+     
+    
 
+   
+  
+  
+   
+    
+     0
+     180
+     471
+     17
+    
+   
+   
+    All is well.
+   
+  
+  
+   
+    
+     1
+     39
+     204
+     93
+    
+   
+   
+    Frame Size:
+   
+   
+    - 
+     
+      
- 
+       
+        
+         Fixed Size:
+        
+       
+      
 
+      - 
+       
+        
+         false
+        
+        
+         1
+        
+        
+         255
+        
+       
+      
 
+     
+     
+    - 
+     
+      
+       First byte of frame is size
+      
+      
+       true
+      
+     
+    
 
+   
+  
+  
+   
+    - 
+     
+      
+       Sync Word:
+      
+     
+    
 
+    - 
+     
+    
 
+   
+  
+  
+   
+    
+     1
+     138
+     123
+     22
+    
+   
+   
+    Checksum Byte
+   
+  
+ 
+ 
+  
+   NumberFormatBox
+   QWidget
+   
+   1
+  
+  
+   EndiannessBox
+   QWidget
+   
+   1
+  
+  
+   CommandEdit
+   QLineEdit
+   
+  
+ 
+ 
+ 
+