diff --git a/dataformatpanel.cpp b/dataformatpanel.cpp
new file mode 100644
--- /dev/null
+++ b/dataformatpanel.cpp
@@ -0,0 +1,327 @@
+/*
+ Copyright © 2015 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 "dataformatpanel.h"
+#include "ui_dataformatpanel.h"
+
+#include
+
+#include "utils.h"
+#include "floatswap.h"
+
+DataFormatPanel::DataFormatPanel(QSerialPort* port,
+ QList* channelBuffers,
+ QWidget *parent) :
+ QWidget(parent),
+ ui(new Ui::DataFormatPanel)
+{
+ ui->setupUi(this);
+
+ serialPort = port;
+ _channelBuffers = channelBuffers;
+ 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());
+
+ // setup number of channels spinbox
+ QObject::connect(ui->spNumOfChannels,
+ SELECT::OVERLOAD_OF(&QSpinBox::valueChanged),
+ this, &DataFormatPanel::onNumOfChannelsSP);
+
+ _numOfChannels = ui->spNumOfChannels->value();
+
+ // Init sps (sample per second) counter
+ sampleCount = 0;
+ QObject::connect(&spsTimer, &QTimer::timeout,
+ this, &DataFormatPanel::spsTimerTimeout);
+ spsTimer.start(SPS_UPDATE_TIMEOUT * 1000);
+
+ // Init demo mode
+ demoCount = 0;
+ demoTimer.setInterval(100);
+ QObject::connect(&demoTimer, &QTimer::timeout,
+ this, &DataFormatPanel::demoTimerTimeout);
+}
+
+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;
+}
+
+void DataFormatPanel::pause(bool enabled)
+{
+ paused = enabled;
+}
+
+void DataFormatPanel::enableDemo(bool enabled)
+{
+ if (enabled)
+ {
+ demoTimer.start();
+ }
+ else
+ {
+ demoTimer.stop();
+ }
+}
+
+void DataFormatPanel::spsTimerTimeout()
+{
+ unsigned currentSps = _samplesPerSecond;
+ _samplesPerSecond = sampleCount/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()
+{
+ // TODO: discard data in the size of packageSize
+ if (paused)
+ {
+ serialPort->clear(QSerialPort::Input);
+ return;
+ }
+
+ // a package is a set of channel data like {CHAN0_SAMPLE, CHAN1_SAMPLE...}
+ int packageSize = sampleSize * _numOfChannels;
+ int bytesAvailable = serialPort->bytesAvailable();
+
+ if (bytesAvailable > 0 && skipByteRequested)
+ {
+ serialPort->read(1);
+ skipByteRequested = false;
+ bytesAvailable--;
+ }
+
+ if (bytesAvailable < packageSize) return;
+
+ int numOfPackagesToRead =
+ (bytesAvailable - (bytesAvailable % packageSize)) / packageSize;
+ double* channelSamples = new double[numOfPackagesToRead*_numOfChannels];
+
+ // TODO: use `for`, it is for this
+ int i = 0;
+ while(i < numOfPackagesToRead)
+ {
+ for (unsigned int ci = 0; ci < _numOfChannels; ci++)
+ {
+ // channelSamples[ci].replace(i, (this->*readSample)());
+ channelSamples[ci*numOfPackagesToRead+i] = (this->*readSample)();
+ }
+ i++;
+ }
+
+ 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)
+{
+ (*_channelBuffers)[channel]->addSamples(data, size);
+ sampleCount += size;
+}