Changeset - a5247fcab715
[Not reviewed]
recording
0 5 0
Hasan Yavuz Ă–ZDERYA - 9 years ago 2017-02-16 06:24:53
hy@ozderya.net
added column separator option
5 files changed with 62 insertions and 8 deletions:
0 comments (0 inline, 0 general)
src/datarecorder.cpp
Show inline comments
 
@@ -20,41 +20,42 @@
 
#include "datarecorder.h"
 

	
 
#include <QtDebug>
 

	
 
DataRecorder::DataRecorder(QObject *parent) :
 
    QObject(parent),
 
    fileStream(&file)
 
{
 
    lastNumChannels = 0;
 
    disableBuffering = false;
 
}
 

	
 
bool DataRecorder::startRecording(QString fileName, QStringList channelNames)
 
bool DataRecorder::startRecording(QString fileName, QString separator, QStringList channelNames)
 
{
 
    Q_ASSERT(!file.isOpen());
 
    _sep =  separator;
 

	
 
    // open file
 
    file.setFileName(fileName);
 
    if (!file.open(QIODevice::WriteOnly))
 
    {
 
        qCritical() << "Opening file " << fileName
 
                    << " for recording failed with error: " << file.error();
 
        return false;
 
    }
 

	
 
    // write header line
 
    if (!channelNames.isEmpty())
 
    {
 
        fileStream << channelNames.join(",");
 
        fileStream << channelNames.join(_sep);
 
        fileStream << "\n";
 
        lastNumChannels = channelNames.length();
 
    }
 
    return true;
 
}
 

	
 
void DataRecorder::addData(double* data, unsigned length, unsigned numOfChannels)
 
{
 
    Q_ASSERT(length > 0);
 
    Q_ASSERT(length % numOfChannels == 0);
 

	
 
    if (lastNumChannels != 0 && numOfChannels != lastNumChannels)
 
@@ -62,25 +63,25 @@ void DataRecorder::addData(double* data,
 
        qWarning() << "Number of channels changed from " << lastNumChannels
 
                   << " to " << numOfChannels <<
 
            " during recording, CSV file is corrupted but no data will be lost.";
 
    }
 
    lastNumChannels = numOfChannels;
 

	
 
    unsigned numOfSamples = length / numOfChannels; // per channel
 
    for (unsigned int i = 0; i < numOfSamples; i++)
 
    {
 
        for (unsigned ci = 0; ci < numOfChannels; ci++)
 
        {
 
            fileStream << data[ci * numOfSamples + i];
 
            if (ci != numOfChannels-1) fileStream << ",";
 
            if (ci != numOfChannels-1) fileStream << _sep;
 
        }
 
        fileStream << '\n';
 
    }
 

	
 
    if (disableBuffering) fileStream.flush();
 
}
 

	
 
void DataRecorder::stopRecording()
 
{
 
    Q_ASSERT(file.isOpen());
 

	
 
    file.close();
src/datarecorder.h
Show inline comments
 
@@ -30,28 +30,29 @@ class DataRecorder : public QObject
 
public:
 
    explicit DataRecorder(QObject *parent = 0);
 

	
 
    /// Disables file buffering
 
    bool disableBuffering;
 

	
 
    /**
 
     * @brief Starts recording data to a file in CSV format.
 
     *
 
     * File is opened and header line (names of channels) is written.
 
     *
 
     * @param fileName name of the recording file
 
     * @param separator column separator
 
     * @param channelNames names of the channels for header line, if empty no header line is written
 
     * @return false if file operation fails (read only etc.)
 
     */
 
    bool startRecording(QString fileName, QStringList channelNames);
 
    bool startRecording(QString fileName, QString separator, QStringList channelNames);
 

	
 
    /**
 
     * @brief Adds data to a channel.
 
     *
 
     * Multiple rows of data can be added at a time. Each channels
 
     * data should be ordered consecutively in the `data` array:
 
     *
 
     * [CH0_SMP0, CH0_SMP1 ... CH0_SMPN, CH1_SMP0, CH1_SMP1, ... , CHN_SMPN]
 
     *
 
     * If `numOfChannels` changes during recording, no data will be
 
     * lost (ie. it will be written to the file) but this will produce
 
     * an invalid CSV file. An error message will be written to the
 
@@ -61,15 +62,16 @@ public:
 
     * @param length number of samples in `data`, must be multiple of `numOfChannels`
 
     * @param numOfChannels how many channels samples this data carries
 
     */
 
    void addData(double* data, unsigned length, unsigned numOfChannels);
 

	
 
    /// Stops recording, closes file.
 
    void stopRecording();
 

	
 
private:
 
    unsigned lastNumChannels;   ///< used for error message only
 
    QFile file;
 
    QTextStream fileStream;
 
    QString _sep;
 
};
 

	
 
#endif // DATARECORDER_H
src/recordpanel.cpp
Show inline comments
 
@@ -213,30 +213,37 @@ bool RecordPanel::confirmOverwrite(QStri
 
    {
 
        return selectFile();
 
    }
 
}
 

	
 
void RecordPanel::startRecording(void)
 
{
 
    QStringList channelNames;
 
    if (ui->cbHeader->isChecked())
 
    {
 
        channelNames = _channelMan->infoModel()->channelNames();
 
    }
 
    _recorder->startRecording(selectedFile, channelNames);
 
    _recorder->startRecording(selectedFile, getSeparator(), channelNames);
 
    emit recordStarted();
 
}
 

	
 
void RecordPanel::stopRecording(void)
 
{
 
    emit recordStopped();
 
    _recorder->stopRecording();
 
}
 

	
 
void RecordPanel::onPortClose()
 
{
 
    if (recordAction.isChecked() && ui->cbStopOnClose->isChecked())
 
    {
 
        stopRecording();
 
        recordAction.setChecked(false);
 
    }
 
}
 

	
 
QString RecordPanel::getSeparator() const
 
{
 
    QString sep = ui->leSeparator->text();
 
    sep.replace("\\t", "\t");
 
    return sep;
 
}
src/recordpanel.h
Show inline comments
 
@@ -81,24 +81,28 @@ private:
 
     * If user confirms overwrite, `selectedFile` is set to
 
     * `fileName`. User is also given option to select file and is
 
     * shown a file select dialog in this case.
 
     *
 
     * @param fileName auto generated file name.
 
     * @return false if user cancels
 
     */
 
    bool confirmOverwrite(QString fileName);
 

	
 
    void startRecording(void);
 
    void stopRecording(void);
 

	
 
    /// Returns separator text from ui. "\t" is converted to TAB
 
    /// character.
 
    QString getSeparator() const;
 

	
 
private slots:
 
    /**
 
     * @brief Opens up the file select dialog
 
     *
 
     * If you cancel the selection operation, currently selected file is not
 
     * changed.
 
     *
 
     * @return true if file selected, false if user cancels
 
     */
 
    bool selectFile();
 

	
 
    void onRecord(bool start);
src/recordpanel.ui
Show inline comments
 
<?xml version="1.0" encoding="UTF-8"?>
 
<ui version="4.0">
 
 <class>RecordPanel</class>
 
 <widget class="QWidget" name="RecordPanel">
 
  <property name="geometry">
 
   <rect>
 
    <x>0</x>
 
    <y>0</y>
 
    <width>532</width>
 
    <height>169</height>
 
    <height>261</height>
 
   </rect>
 
  </property>
 
  <property name="windowTitle">
 
   <string>Form</string>
 
  </property>
 
  <layout class="QHBoxLayout" name="horizontalLayout_2">
 
   <item>
 
    <layout class="QVBoxLayout" name="verticalLayout">
 
     <item>
 
      <layout class="QHBoxLayout" name="horizontalLayout">
 
       <item>
 
        <widget class="QPushButton" name="pbBrowse">
 
@@ -84,42 +84,82 @@
 
       <property name="toolTip">
 
        <string>Channel names are written to the first line of record file</string>
 
       </property>
 
       <property name="text">
 
        <string>Write header line</string>
 
       </property>
 
       <property name="checked">
 
        <bool>true</bool>
 
       </property>
 
      </widget>
 
     </item>
 
     <item>
 
      <layout class="QHBoxLayout" name="horizontalLayout_3">
 
       <item>
 
        <widget class="QLabel" name="label">
 
         <property name="text">
 
          <string>Column Separator:</string>
 
         </property>
 
        </widget>
 
       </item>
 
       <item>
 
        <widget class="QLineEdit" name="leSeparator">
 
         <property name="maximumSize">
 
          <size>
 
           <width>30</width>
 
           <height>16777215</height>
 
          </size>
 
         </property>
 
         <property name="toolTip">
 
          <string>For TAB character enter \t</string>
 
         </property>
 
         <property name="text">
 
          <string>,</string>
 
         </property>
 
        </widget>
 
       </item>
 
       <item>
 
        <spacer name="horizontalSpacer">
 
         <property name="orientation">
 
          <enum>Qt::Horizontal</enum>
 
         </property>
 
         <property name="sizeHint" stdset="0">
 
          <size>
 
           <width>40</width>
 
           <height>20</height>
 
          </size>
 
         </property>
 
        </spacer>
 
       </item>
 
      </layout>
 
     </item>
 
     <item>
 
      <widget class="QCheckBox" name="cbDisableBuffering">
 
       <property name="toolTip">
 
        <string>Do not buffer when writing to file. Check this if you are using other software to open the file during recording.</string>
 
       </property>
 
       <property name="text">
 
        <string>Disable buffering</string>
 
       </property>
 
      </widget>
 
     </item>
 
     <item>
 
      <spacer name="verticalSpacer">
 
       <property name="orientation">
 
        <enum>Qt::Vertical</enum>
 
       </property>
 
       <property name="sizeHint" stdset="0">
 
        <size>
 
         <width>20</width>
 
         <height>40</height>
 
         <height>1</height>
 
        </size>
 
       </property>
 
      </spacer>
 
     </item>
 
    </layout>
 
   </item>
 
   <item>
 
    <layout class="QVBoxLayout" name="verticalLayout_2">
 
     <item>
 
      <widget class="QToolButton" name="pbRecord">
 
       <property name="minimumSize">
 
        <size>
 
@@ -134,24 +174,24 @@
 
        <string>Record</string>
 
       </property>
 
      </widget>
 
     </item>
 
     <item>
 
      <spacer name="verticalSpacer_2">
 
       <property name="orientation">
 
        <enum>Qt::Vertical</enum>
 
       </property>
 
       <property name="sizeHint" stdset="0">
 
        <size>
 
         <width>20</width>
 
         <height>40</height>
 
         <height>1</height>
 
        </size>
 
       </property>
 
      </spacer>
 
     </item>
 
    </layout>
 
   </item>
 
  </layout>
 
 </widget>
 
 <resources/>
 
 <connections/>
 
</ui>
0 comments (0 inline, 0 general)