diff --git a/src/CUcontent_MBsSWs.cpp b/src/CUcontent_MBsSWs.cpp index b048f78..d83b17f 100644 --- a/src/CUcontent_MBsSWs.cpp +++ b/src/CUcontent_MBsSWs.cpp @@ -363,6 +363,47 @@ bool CUcontent_MBsSWs::startMBSWreading() } else goto err; + + // store start time + startTime = std::chrono::high_resolution_clock::now(); + + // create csv object and write header + csv = new csvfile("measurements.csv"); + + // global time + *csv << "Time"; + + // time since measurement + *csv << "Delta Time"; + + // write header + for (size_t i=0; i < _MBSWmetaList.size(); i++) + { + const MBSWmetadata_dt& metadata = _MBSWmetaList.at(i); + + std::string title; + std::string unit; + + // find title and units + if (metadata.blockType == BlockType::MB) + { + const mb_dt& mb = _supportedMBs.at(metadata.nativeIndex); + title = mb.title.toStdString(); + unit = mb.unit.toStdString(); + } + else if (metadata.blockType == BlockType::SW) + { + const sw_dt& sw = _supportedSWs.at(metadata.nativeIndex); + title = sw.title.toStdString(); + unit = sw.unit.toStdString(); + } + + // write to file + *csv << title + " (" + unit + ")"; + + } + *csv << endrow; + // Reset old data: _lastValues.clear(); _minmaxData.clear(); @@ -410,6 +451,8 @@ bool CUcontent_MBsSWs::stopMBSWreading() } } disconnect( _SSMPdev, SIGNAL( newMBSWrawValues(const std::vector&, int) ), this, SLOT( processMBSWRawValues(const std::vector&, int) ) ); + // close csv files (also flushes csv) + delete csv; // Set text+icon of start/stop-button: labelStartStopButtonReadyForStart(); // Enable delete button if MBs/SWs are selected on the table: @@ -711,6 +754,28 @@ void CUcontent_MBsSWs::processMBSWRawValues(const std::vector& raw _valuesTableView->updateMBSWvalues(valueStrList, minValueStrList, maxValueStrList, unitStrList); // Output refresh duration: updateTimeInfo(refreshduration_ms); + + // write to csv + + // get timestamp + const auto currTime = std::chrono::high_resolution_clock::now(); + const std::chrono::duration deltaTime = currTime - startTime; + + // conver to unix epoch time in ms + const double unixEpochMs = std::chrono::duration_cast + (currTime.time_since_epoch()).count() / 1000.0; + const double deltaEpochMs = std::chrono::duration_cast + (deltaTime).count() / 1000.0; + + // save to csv + *csv << std::fixed << unixEpochMs; + *csv << deltaEpochMs; + for (size_t i=0; i < valueStrList.size(); i++) { + std::string value = valueStrList.at(i).toStdString(); + *csv << value; + } + *csv << endrow; + csv->flush(); } diff --git a/src/CUcontent_MBsSWs.h b/src/CUcontent_MBsSWs.h index 67cd36d..870494f 100644 --- a/src/CUcontent_MBsSWs.h +++ b/src/CUcontent_MBsSWs.h @@ -40,6 +40,10 @@ // To do binary file operations storing the current setup #include +#include + +#include "csvfile.h" + class MBSWvalue_dt { public: @@ -106,6 +110,11 @@ class CUcontent_MBsSWs : public QWidget, private Ui::MBSWcontent_Form std::vector _tableRowPosIndexes; /* index of the row at which the MB/SW is displayed in the values-table-widget */ bool _MBSWreading; + // pointer to csv file object + csvfile *csv = nullptr; + // measurement start time (default ot current time) + std::chrono::high_resolution_clock::time_point startTime; + void setupTimeModeUiElements(); bool validateMBSWselection(const std::vector& MBSWmetaList); void setMBSWselectionUnvalidated(const std::vector& MBSWmetaList); diff --git a/src/csvfile.h b/src/csvfile.h new file mode 100644 index 0000000..e36561c --- /dev/null +++ b/src/csvfile.h @@ -0,0 +1,128 @@ +/** + * csvfile.h - Utility for writing CSV files + * + * Based on this github gist: https://gist.github.com/rudolfovich/f250900f1a833e715260a66c87369d15 + */ + +#ifndef CSVFILE_H +#define CSVFILE_H + +#include +#include +#include +#include + +class csvfile; + +inline static csvfile& endrow(csvfile& file); +inline static csvfile& flush(csvfile& file); + +class csvfile +{ + std::ofstream fs_; + bool is_first_; + const std::string separator_; + const std::string escape_seq_; + const std::string special_chars_; +public: + csvfile(const std::string filename, const std::string separator = ";") + : fs_() + , is_first_(true) + , separator_(separator) + , escape_seq_("\"") + , special_chars_("\"") + { + fs_.exceptions(std::ios::failbit | std::ios::badbit); + fs_.open(filename); + } + + ~csvfile() + { + flush(); + fs_.close(); + } + + void flush() + { + fs_.flush(); + } + + void endrow() + { + fs_ << std::endl; + is_first_ = true; + } + + csvfile& operator << ( csvfile& (* val)(csvfile&)) + { + return val(*this); + } + + csvfile& operator << (const char * val) + { + return write(escape(val)); + } + + csvfile& operator << (const std::string & val) + { + return write(escape(val)); + } + + csvfile& operator<<(std::ios_base& (*manip)(std::ios_base&)) + { + fs_ << manip; + return *this; + } + + template + csvfile& operator << (const T& val) + { + return write(val); + } + +private: + template + csvfile& write (const T& val) + { + if (!is_first_) + { + fs_ << separator_; + } + else + { + is_first_ = false; + } + fs_ << val; + return *this; + } + + std::string escape(const std::string & val) + { + std::ostringstream result; + result << '"'; + std::string::size_type to, from = 0u, len = val.length(); + while (from < len && + std::string::npos != (to = val.find_first_of(special_chars_, from))) + { + result << val.substr(from, to - from) << escape_seq_ << val[to]; + from = to + 1; + } + result << val.substr(from) << '"'; + return result.str(); + } +}; + + +inline static csvfile& endrow(csvfile& file) +{ + file.endrow(); + return file; +} + +inline static csvfile& flush(csvfile& file) +{ + file.flush(); + return file; +} + +#endif