From 60396696479ec52333887e1dd94e589fca0c01b6 Mon Sep 17 00:00:00 2001 From: "John M. Penn" Date: Fri, 19 Jan 2018 17:36:00 -0600 Subject: [PATCH] Created a new program call trkConvert that only opens the trk file once. Ref #508 --- .../Apps/trkConvert/CSV_Formatter.cpp | 23 ++ .../Apps/trkConvert/CSV_Formatter.hh | 27 ++ .../Apps/trkConvert/LogFormatter.hh | 32 ++ .../Apps/trkConvert/Varlist_Formatter.cpp | 11 + .../Apps/trkConvert/Varlist_Formatter.hh | 28 ++ .../data_products/Apps/trkConvert/makefile | 23 ++ .../Apps/trkConvert/trkConvert.cpp | 384 ++++++++++++++++++ trick_source/data_products/makefile | 1 + 8 files changed, 529 insertions(+) create mode 100644 trick_source/data_products/Apps/trkConvert/CSV_Formatter.cpp create mode 100644 trick_source/data_products/Apps/trkConvert/CSV_Formatter.hh create mode 100644 trick_source/data_products/Apps/trkConvert/LogFormatter.hh create mode 100644 trick_source/data_products/Apps/trkConvert/Varlist_Formatter.cpp create mode 100644 trick_source/data_products/Apps/trkConvert/Varlist_Formatter.hh create mode 100644 trick_source/data_products/Apps/trkConvert/makefile create mode 100644 trick_source/data_products/Apps/trkConvert/trkConvert.cpp diff --git a/trick_source/data_products/Apps/trkConvert/CSV_Formatter.cpp b/trick_source/data_products/Apps/trkConvert/CSV_Formatter.cpp new file mode 100644 index 00000000..4aa81e5b --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/CSV_Formatter.cpp @@ -0,0 +1,23 @@ +#include "CSV_Formatter.hh" +/* ================================================================================ + * CLASS: CSV_Formatter isa LogFormatter. + * ================================================================================ + */ + +void CSV_Formatter::writeColumnLabel(FILE* out_fp, const char* name, const char* units) { + fprintf(out_fp,"%s {%s}", name, units); +} +void CSV_Formatter::writeColumnLabelSeparator(FILE* out_fp) { fprintf(out_fp,","); } +void CSV_Formatter::writeDatumSeparator(FILE* out_fp) { fprintf(out_fp,","); } +void CSV_Formatter::writeRecordSeparator(FILE* out_fp) { fprintf(out_fp,"\n"); } +void CSV_Formatter::writeDatum(FILE* out_fp, int8_t datum) { fprintf(out_fp,"%d", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, uint8_t datum) { fprintf(out_fp,"%ud", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, int16_t datum) { fprintf(out_fp,"%d", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, uint16_t datum) { fprintf(out_fp,"%ud", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, int32_t datum) { fprintf(out_fp,"%d", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, uint32_t datum) { fprintf(out_fp,"%ud", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, int64_t datum) { fprintf(out_fp,"%lld", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, uint64_t datum) { fprintf(out_fp,"%lld", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, float datum) { fprintf(out_fp,"%.7f", datum); } +void CSV_Formatter::writeDatum(FILE* out_fp, double datum) { fprintf(out_fp,"%.15g", datum); } +const char* CSV_Formatter::extension() { return ".csv"; }; diff --git a/trick_source/data_products/Apps/trkConvert/CSV_Formatter.hh b/trick_source/data_products/Apps/trkConvert/CSV_Formatter.hh new file mode 100644 index 00000000..04a4837f --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/CSV_Formatter.hh @@ -0,0 +1,27 @@ + +#ifndef CSV_FORMATTER +#define CSV_FORMATTER + +#include +#include "LogFormatter.hh" + +class CSV_Formatter: public LogFormatter { + public: + void writeHeader(FILE* out_fp, int version, int endianness); + void writeColumnLabel(FILE* out_fp, const char* name, const char* units); + void writeColumnLabelSeparator(FILE* out_fp); + void writeDatumSeparator(FILE* out_fp); + void writeRecordSeparator(FILE* out_fp); + void writeDatum(FILE* out_fp, int8_t datum); + void writeDatum(FILE* out_fp, uint8_t datum); + void writeDatum(FILE* out_fp, int16_t datum); + void writeDatum(FILE* out_fp, uint16_t datum); + void writeDatum(FILE* out_fp, int32_t datum); + void writeDatum(FILE* out_fp, uint32_t datum); + void writeDatum(FILE* out_fp, int64_t datum); + void writeDatum(FILE* out_fp, uint64_t datum); + void writeDatum(FILE* out_fp, float datum); + void writeDatum(FILE* out_fp, double datum); + const char* extension(); +}; +#endif diff --git a/trick_source/data_products/Apps/trkConvert/LogFormatter.hh b/trick_source/data_products/Apps/trkConvert/LogFormatter.hh new file mode 100644 index 00000000..f75d2d27 --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/LogFormatter.hh @@ -0,0 +1,32 @@ +#ifndef LOG_FORMATTER +#define LOG_FORMATTER +#include +#include + +class LogFormatter { + + public: + void writeHeader(FILE* out_fp __attribute__((unused)), + int version __attribute__((unused)), + int endianness __attribute__((unused))) {}; + + void writeColumnLabel(FILE* out_fp __attribute__((unused)), + const char* name __attribute__((unused)), + const char* units __attribute__((unused))) {}; + + void writeColumnLabelSeparator(FILE* out_fp __attribute__((unused))) {}; + void writeDatumSeparator( FILE* out_fp __attribute__((unused))) {}; + void writeRecordSeparator(FILE* out_fp __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), int8_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), uint8_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), int16_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), uint16_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), int32_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), uint32_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), int64_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), uint64_t datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), float datum __attribute__((unused))) {}; + void writeDatum(FILE* out_fp __attribute__((unused)), double datum __attribute__((unused))) {}; + virtual const char* extension() = 0; +}; +#endif diff --git a/trick_source/data_products/Apps/trkConvert/Varlist_Formatter.cpp b/trick_source/data_products/Apps/trkConvert/Varlist_Formatter.cpp new file mode 100644 index 00000000..7adbcb29 --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/Varlist_Formatter.cpp @@ -0,0 +1,11 @@ +#include "Varlist_Formatter.hh" +/* ================================================================================ + * CLASS: Varlist_Formatter isa LogFormatter. + * ================================================================================ + */ + + void Varlist_Formatter::writeColumnLabel(FILE* out_fp, const char* name, const char* units) { + fprintf(out_fp,"%s {%s}", name, units); + } + void Varlist_Formatter::writeColumnLabelSeparator(FILE* out_fp) { fprintf(out_fp,"\n"); } + const char* Varlist_Formatter::extension() { return ".varlist"; }; diff --git a/trick_source/data_products/Apps/trkConvert/Varlist_Formatter.hh b/trick_source/data_products/Apps/trkConvert/Varlist_Formatter.hh new file mode 100644 index 00000000..b49fd981 --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/Varlist_Formatter.hh @@ -0,0 +1,28 @@ +#ifndef VARLIST_FORMATTER +#define VARLIST_FORMATTER + +#include "LogFormatter.hh" +/* ================================================================================ + * CLASS: Varlist_Formatter isa LogFormatter. + * ================================================================================ + */ +class Varlist_Formatter: public LogFormatter { + public: + void writeHeader(FILE* out_fp, int version, int endianness); + void writeColumnLabel(FILE* out_fp, const char* name, const char* units); + void writeColumnLabelSeparator(FILE* out_fp); + void writeDatumSeparator(FILE* out_fp); + void writeRecordSeparator(FILE* out_fp); + void writeDatum(FILE* out_fp, int8_t datum); + void writeDatum(FILE* out_fp, uint8_t datum); + void writeDatum(FILE* out_fp, int16_t datum); + void writeDatum(FILE* out_fp, uint16_t datum); + void writeDatum(FILE* out_fp, int32_t datum); + void writeDatum(FILE* out_fp, uint32_t datum); + void writeDatum(FILE* out_fp, int64_t datum); + void writeDatum(FILE* out_fp, uint64_t datum); + void writeDatum(FILE* out_fp, float datum); + void writeDatum(FILE* out_fp, double datum); + const char* extension(); +}; +#endif diff --git a/trick_source/data_products/Apps/trkConvert/makefile b/trick_source/data_products/Apps/trkConvert/makefile new file mode 100644 index 00000000..30781e97 --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/makefile @@ -0,0 +1,23 @@ +CPP = g++ +CC = gcc + +CXXFLAGS = + +MAIN = trkConvert + +OBJECTS = CSV_Formatter.o Varlist_Formatter.o trkConvert.o + +.c.o: + ${CC} ${CFLAGS} ${INCDIRS} -c $< + +.cpp.o: + ${CPP} ${CFLAGS} ${INCDIRS} -c $< + +all: trkConvert + +trkConvert: $(OBJECTS) + $(CPP) -o trkConvert $(OBJECTS) + +clean: + rm -f *.o + rm -f trkConvert diff --git a/trick_source/data_products/Apps/trkConvert/trkConvert.cpp b/trick_source/data_products/Apps/trkConvert/trkConvert.cpp new file mode 100644 index 00000000..c170a5e4 --- /dev/null +++ b/trick_source/data_products/Apps/trkConvert/trkConvert.cpp @@ -0,0 +1,384 @@ +#include +#include +#include // Requires C99 +#include +#include +#include +#include +#include + +#include "LogFormatter.hh" +#include "CSV_Formatter.hh" +#include "Varlist_Formatter.hh" + +typedef enum { + TRICK_VOID = 0, /* No type */ + TRICK_CHARACTER = 1, /* (char) */ + TRICK_UNSIGNED_CHARACTER = 2, /* (unsigned char) */ + TRICK_STRING = 3, /* (char *) */ + TRICK_SHORT = 4, /* (short) */ + TRICK_UNSIGNED_SHORT = 5, /* (unsigned short) */ + TRICK_INTEGER = 6, /* (int) */ + TRICK_UNSIGNED_INTEGER = 7, /* (unsigned int) */ + TRICK_LONG = 8, /* (long) */ + TRICK_UNSIGNED_LONG = 9, /* (unsigned long) */ + TRICK_FLOAT = 10, /* (float) */ + TRICK_DOUBLE = 11, /* (double) */ + TRICK_BITFIELD = 12, /* (signed int : 1) */ + TRICK_UNSIGNED_BITFIELD = 13, /* (unsigned int : 1) */ + TRICK_LONG_LONG = 14, /* (long long) */ + TRICK_UNSIGNED_LONG_LONG = 15, /* (long long) */ + TRICK_FILE_PTR = 16, /* (file *) */ + TRICK_BOOLEAN = 17, /* (C++ boolean) */ + TRICK_WCHAR = 18, /* (wchar_t) */ + TRICK_WSTRING = 19, /* (wchar_t *) */ + TRICK_VOID_PTR = 20, /* an arbitrary address */ + TRICK_ENUMERATED = 21, /* User defined type (enumeration) */ + TRICK_STRUCTURED = 22, /* User defined type (struct/class) */ + TRICK_OPAQUE_TYPE = 23, /* User defined type (where type details are as yet unknown) */ + TRICK_STL = 24, /* Standard template library type */ + TRICK_NUMBER_OF_TYPES +} TRICK_TYPE ; + +class ReadException: public std::exception { + virtual const char* what() const throw() { + return "fread() failed."; + } +} readException; + +/* ================================================================================ + * CLASS: ParamDescription + * ================================================================================ + */ +class ParamDescription { + public: + char* parameterName; + char* unitsName; + int32_t dataType; + int32_t dataSize; + + ParamDescription(){} + ParamDescription(FILE* fp); +}; + +ParamDescription::ParamDescription(FILE* in_fp){ + + int32_t nameStringLength; + if ( fread( &nameStringLength, 1, 4, in_fp) != 4) throw readException; + + parameterName = new char[nameStringLength+1]; + if ( fread( parameterName, 1, nameStringLength, in_fp) != (size_t)nameStringLength) throw readException; + parameterName[nameStringLength] = 0; + + int32_t unitsStringLength; + if ( fread( &unitsStringLength, 1, 4 , in_fp) != 4) throw readException; + + unitsName = new char[unitsStringLength+1]; + if ( fread( unitsName, 1, unitsStringLength, in_fp) != (size_t)unitsStringLength) throw readException; + unitsName[unitsStringLength] = 0; + + if ( fread( &dataType, 1, 4, in_fp) != 4) throw readException; + if ( fread( &dataSize, 1, 4, in_fp) != 4) throw readException; +} + +/* ================================================================================ + * CLASS: DataLog + * ================================================================================ + */ +class DataLog { + + public: + std::string fileName; + FILE* in_fp; + int version; + int endianness; + uint32_t N_params; + fpos_t dataPosition; + int dataRecordSize; + char* dataRecord; + + static const int LittleEndian; + static const int BigEndian; + + std::vector paramDescriptions; + std::vector paramOffsets; + std::vector paramSelected; + + DataLog(){} + DataLog(std::string fileName); + void selectAllParameters(); + void selectParameter(unsigned int index); + void selectParameter(const char * paramName); + void deselectParameter(unsigned int index); + void formattedWrite(FILE* out_fp, LogFormatter* formatter); +}; + +const int DataLog::LittleEndian = 1; +const int DataLog::BigEndian = 2; + +DataLog::DataLog(std::string file_name) { + + fileName = file_name; + in_fp = fopen(fileName.c_str(), "rb"); + + if (in_fp != NULL) { + + char trick_header_string[11]; + if (fread( trick_header_string, 1, 10, in_fp) != 10) throw readException; + trick_header_string[10] = 0; + + if (!strncmp( trick_header_string, "Trick-", 6)) { + + char version_txt[3]; + memcpy(version_txt, &trick_header_string[6], 2) ; + version_txt[2] = 0; + version = atoi(version_txt); + + char endian_txt[2]; + memcpy(endian_txt, &trick_header_string[9], 1) ; + endian_txt[1] = 0; + + if (!strncmp( endian_txt, "L", 1)) { + endianness = LittleEndian; + } else if (!strncmp( endian_txt, "B", 1)) { + endianness = BigEndian; + } else { + fprintf (stderr, "Trick header error. Endianness should be \"L\" or \"B\"."); + } + + if (fread( &N_params, 1, 4, in_fp) != 4) throw readException; + + dataRecordSize = 0; + for (int ii = 0 ; ii < (int)N_params ; ii++ ) { + ParamDescription* paramDescription = new ParamDescription(in_fp); + paramDescriptions.push_back(paramDescription); + paramOffsets.push_back(dataRecordSize); + paramSelected.push_back(false); + + dataRecordSize += paramDescription->dataSize; + } + dataRecord = new char[dataRecordSize]; + + // Time should always be selected. + paramSelected[0] = true; + + if (fgetpos(in_fp, &dataPosition) != 0) { + fprintf (stderr, "fgetpos failure.\n"); + } + } else { + std::cerr << "File \"" << fileName << "\" isn't a Trick binary log file." << std::endl; + } + } else { + std::cerr << "File \"" << fileName << "\" failed to open." << std::endl; + } +} + +void DataLog::selectAllParameters() { + for (int ii = 1 ; ii < (int)N_params ; ii++ ) { + paramSelected[ii] = true; + } +} + +void DataLog::selectParameter(unsigned int index) { + if ((index > 0) && (index < N_params)) { + paramSelected[index] = true; + } +} + +void DataLog::selectParameter(const char * paramName) { + bool found = false; + int ii = 1; + while ((ii < (int)N_params) && (found == false)) { + if ( !strcmp( paramName, paramDescriptions[ii]->parameterName )) { + paramSelected[ii] = true; + found = true; + } + ii ++; + } +} + +void DataLog::deselectParameter(unsigned int index) { + if ((index > 0) && (index < N_params)) { + paramSelected[index] = false; + } +} + +void DataLog::formattedWrite(FILE* out_fp, LogFormatter* formatter) { + + formatter->writeHeader(out_fp, version, endianness); + formatter->writeColumnLabel(out_fp, paramDescriptions[0]->parameterName, paramDescriptions[0]->unitsName); + for (int ii = 1; ii < (int)N_params ; ii++) { + if (paramSelected[ii]) + formatter->writeColumnLabelSeparator(out_fp); + formatter->writeColumnLabel(out_fp, paramDescriptions[ii]->parameterName, paramDescriptions[ii]->unitsName); + } + + if ( fsetpos(in_fp, &dataPosition) != 0 ) { + fprintf(stderr,"fsetpos() error.\n"); + } + while ( fread( dataRecord, 1, dataRecordSize, in_fp) == (size_t)dataRecordSize) { + formatter->writeRecordSeparator(out_fp); + formatter->writeDatum(out_fp, *(double*)&dataRecord[0]); // Time is always selected. + for (int ii = 1 ; ii < (int)N_params ; ii++ ) { + if (paramSelected[ii]) { + formatter->writeDatumSeparator(out_fp); + switch (paramDescriptions[ii]->dataType) { + case TRICK_CHARACTER: { /*1*/ + formatter->writeDatum(out_fp, *(int8_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_UNSIGNED_CHARACTER: { /*2*/ + formatter->writeDatum(out_fp, *(uint8_t*)&dataRecord[paramOffsets[ii]]) ; + } break; + case TRICK_SHORT: { /*4*/ + formatter->writeDatum(out_fp, *(int16_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_UNSIGNED_SHORT: { /*5*/ + formatter->writeDatum(out_fp, *(uint16_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_INTEGER: {/*6*/ + formatter->writeDatum(out_fp, *(int32_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_UNSIGNED_INTEGER: {/*7*/ + formatter->writeDatum(out_fp, *(uint32_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_LONG: { /*8*/ + formatter->writeDatum(out_fp, *(int64_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_UNSIGNED_LONG: { /*9*/ + formatter->writeDatum(out_fp, *(uint64_t*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_FLOAT: {/*10*/ + formatter->writeDatum(out_fp, *(float*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_DOUBLE: {/*11*/ + formatter->writeDatum(out_fp, *(double*)&dataRecord[paramOffsets[ii]]); + } break; + case TRICK_LONG_LONG: { /*14*/ + formatter->writeDatum(out_fp, *(int64_t*)&dataRecord[paramOffsets[ii]]); + } break; + default: { + fprintf(stdout, "?"); + } + } + } + } + } + formatter->writeRecordSeparator(out_fp); +} + +static const char *usage_doc[] = { +"----------------------------------------------------------------------------", +" trkConvert - ", +" ", +" USAGE: trkConvert -help ", +" trkConvert [-csv|-varlist] [-o ] ", +" Options: ", +" -help Print this message and exit. ", +" -csv (the default) Generates a comma-separated value (CSV) file from ", +" a Trick binary data file. CSV files are a common ", +" means of sharing data between applications. ", +" -varlist Generates a list of the names of the variables ", +" the are recorded in the Trick binary data file. ", +"----------------------------------------------------------------------------"}; +#define N_USAGE_LINES (sizeof(usage_doc)/sizeof(usage_doc[0])) + +void print_doc(char *doc[], int nlines) { + int i; + for (i=0; i < nlines; i++) { + std::cerr << doc[i] << '\n'; + } + std::cerr.flush(); +} + +void usage() { + print_doc((char **)usage_doc,N_USAGE_LINES); +} + +int main(int argc, char* argv[]) { + + std::string programName = argv[0]; + std::string trkFilePath; + std::string trkBaseName; + std::string outputName; + FILE *fp; + + CSV_Formatter csv_formatter; + LogFormatter* logFormatter = &csv_formatter; // default formatter. + Varlist_Formatter varlist_formatter; + + if (argc <= 1 ) { + std::cerr << programName << ": No arguments were supplied.\n"; + std::cerr.flush(); + usage(); + exit(1); + } else { + int i = 1; + std::string arg; + while ( i < argc ) { + arg = argv[i]; + + if (arg.find("-") == 0) { + if (arg == "-help" | arg == "--help" ) { + usage(); + exit(0); + } else if (arg == "-csv") { + logFormatter = &csv_formatter; + } else if (arg == "-varlist") { + logFormatter = &varlist_formatter; + } else if (arg == "-o") { + i++; + if (iextension(); + } + + std::cout << programName << ": Input = \"" << trkFilePath << "\"." << std::endl; + std::cout << programName << ": Output = \"" << outputName << "\"." << std::endl; + + DataLog* datalog = new DataLog(trkFilePath); + datalog->selectAllParameters(); + + if (( fp = fopen(outputName.c_str(), "w") ) != NULL) { + datalog->formattedWrite(fp, logFormatter); + return 0; + } + return 1; +} diff --git a/trick_source/data_products/makefile b/trick_source/data_products/makefile index f9514b33..85b39c45 100644 --- a/trick_source/data_products/makefile +++ b/trick_source/data_products/makefile @@ -18,6 +18,7 @@ LIBDIRS += fermi-ware endif APPDIRS = DPX \ + Apps/trkConvert \ Apps/Trk2csv \ Apps/ExternalPrograms