From 3ae2b985cef5da87f33732046de38100efdddbf6 Mon Sep 17 00:00:00 2001 From: "Sean C. Rhea" Date: Mon, 9 Apr 2007 20:43:52 +0000 Subject: [PATCH] Will now read, interpret, and include any appropriately named .srm files in the user's directory. Ride summary, ride plot, and power histogram all work fine, but opening the CP intervals graph causes a crash if any such files exist. Also need to add a menu item to import .srm files that renames them to the proper form (date-time.srm). --- src/gui/GoldenCheetah.pro | 5 +- src/gui/MainWindow.cpp | 6 +-- src/gui/RawFile.cpp | 47 +++++++++++++---- src/gui/RawFile.h | 2 +- src/srm/Makefile | 33 +++++++----- src/srm/srm.cpp | 107 ++++++++++++++++++++++++++++++++------ src/srm/srm.h | 31 +++++++++++ src/srm/srm.pro | 5 +- 8 files changed, 188 insertions(+), 48 deletions(-) create mode 100644 src/srm/srm.h diff --git a/src/gui/GoldenCheetah.pro b/src/gui/GoldenCheetah.pro index cef9630a5..378f09c0d 100644 --- a/src/gui/GoldenCheetah.pro +++ b/src/gui/GoldenCheetah.pro @@ -5,9 +5,10 @@ TEMPLATE = app TARGET += DEPENDPATH += . -INCLUDEPATH += /usr/local/include/qwt ../lib +INCLUDEPATH += /home/srhea/src/qwt-20060130/include ../lib ../srm CONFIG += static -LIBS += /usr/local/lib/libqwt.a ../lib/libgc.a +LIBS += /home/srhea/src/qwt-20060130/lib/libqwt.a ../lib/libgc.a +LIBS += ../srm/libsrm.a LIBS += -lm -lz macx { LIBS += -framework Carbon diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 97223821e..75e216fdf 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -39,7 +39,7 @@ #define RIDE_TYPE 1 static char *rideFileRegExp = ("^(\\d\\d\\d\\d)_(\\d\\d)_(\\d\\d)" - "_(\\d\\d)_(\\d\\d)_(\\d\\d)\\.raw$"); + "_(\\d\\d)_(\\d\\d)_(\\d\\d)\\.(raw|srm)$"); MainWindow::MainWindow(const QDir &home) : home(home), settings(GC_SETTINGS_CO, GC_SETTINGS_APP) @@ -70,13 +70,13 @@ MainWindow::MainWindow(const QDir &home) : QRegExp rx(rideFileRegExp); QStringList filters; - filters << "*.raw"; + filters << "*.raw" << "*.srm"; QTreeWidgetItem *last = NULL; QStringListIterator i(home.entryList(filters, QDir::Files)); while (i.hasNext()) { QString name = i.next(); if (rx.exactMatch(name)) { - assert(rx.numCaptures() == 6); + assert(rx.numCaptures() == 7); QDate date(rx.cap(1).toInt(), rx.cap(2).toInt(),rx.cap(3).toInt()); QTime time(rx.cap(4).toInt(), rx.cap(5).toInt(),rx.cap(6).toInt()); QDateTime dt(date, time); diff --git a/src/gui/RawFile.cpp b/src/gui/RawFile.cpp index 4e47dd02b..fed880991 100644 --- a/src/gui/RawFile.cpp +++ b/src/gui/RawFile.cpp @@ -19,8 +19,11 @@ */ #include "RawFile.h" +#include #include #include +#include "srm.h" + extern "C" { #include "pt.h" } @@ -93,19 +96,43 @@ error_cb(const char *msg, void *context) state->errors.append(QString(msg)); } -RawFile *RawFile::readFile(const QFile &file, QStringList &errors) +RawFile *RawFile::readFile(QFile &file, QStringList &errors) { RawFile *result = new RawFile(file.fileName()); - if (!result->file.open(QIODevice::ReadOnly)) { - delete result; - return NULL; + if (file.fileName().indexOf(".srm") == file.fileName().size() - 4) { + SrmData data; + if (!readSrmFile(file, data, errors)) { + delete result; + return NULL; + } + result->startTime = data.startTime; + result->rec_int = (unsigned) round(data.recint); // TODO + + QListIterator i(data.dataPoints); + while (i.hasNext()) { + SrmDataPoint *p1 = i.next(); + RawFilePoint *p2 = new RawFilePoint( + p1->secs, 0, p1->kph * 0.62137119, p1->watts, + p1->km * 0.62137119, p1->cad, p1->hr, p1->interval); + if (result->powerHist.contains(p2->watts)) + result->powerHist[p2->watts] += data.recint; + else + result->powerHist[p2->watts] = data.recint; + result->points.append(p2); + } + } + else { + if (!result->file.open(QIODevice::ReadOnly)) { + delete result; + return NULL; + } + FILE *f = fdopen(result->file.handle(), "r"); + assert(f); + RawFileReadState state(result->points, result->powerHist, errors); + pt_read_raw(f, 0 /* not compat */, &state, config_cb, + time_cb, data_cb, error_cb); + result->rec_int = state.rec_int; } - FILE *f = fdopen(result->file.handle(), "r"); - assert(f); - RawFileReadState state(result->points, result->powerHist, errors); - pt_read_raw(f, 0 /* not compat */, &state, config_cb, - time_cb, data_cb, error_cb); - result->rec_int = state.rec_int; return result; } diff --git a/src/gui/RawFile.h b/src/gui/RawFile.h index 5c4dd10ae..0cd0c66a9 100644 --- a/src/gui/RawFile.h +++ b/src/gui/RawFile.h @@ -53,7 +53,7 @@ class RawFile int rec_int; QList points; QMap powerHist; - static RawFile *readFile(const QFile &file, QStringList &errors); + static RawFile *readFile(QFile &file, QStringList &errors); }; #endif // _GC_RawFile_h diff --git a/src/srm/Makefile b/src/srm/Makefile index 8357fd488..ce0e71300 100644 --- a/src/srm/Makefile +++ b/src/srm/Makefile @@ -1,8 +1,8 @@ ############################################################################# -# Makefile for building: srm -# Generated by qmake (2.01a) (Qt 4.2.0) on: Sun Apr 8 18:34:58 2007 +# Makefile for building: libsrm.a +# Generated by qmake (2.01a) (Qt 4.2.0) on: Mon Apr 9 13:27:14 2007 # Project: srm.pro -# Template: app +# Template: lib # Command: /usr/bin/qmake -unix -o Makefile srm.pro ############################################################################# @@ -13,14 +13,11 @@ CXX = g++ LEX = flex YACC = yacc DEFINES = -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -CFLAGS = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES) -CXXFLAGS = -pipe -O2 -Wall -W -D_REENTRANT $(DEFINES) +CFLAGS = -pipe -O2 -fPIC -Wall -W -D_REENTRANT $(DEFINES) +CXXFLAGS = -pipe -O2 -fPIC -Wall -W -D_REENTRANT $(DEFINES) LEXFLAGS = YACCFLAGS = -d INCPATH = -I/usr/share/qt4/mkspecs/linux-g++ -I. -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtCore -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtGui -I/usr/include/qt4 -I. -I. -I. -LINK = g++ -LFLAGS = -LIBS = $(SUBLIBS) -L/usr/lib -lQtGui -L/build/buildd/qt4-x11-4.2.0/lib -L/usr/X11R6/lib -laudio -lXt -lpng -lSM -lICE -lXrender -lXrandr -lXfixes -lXcursor -lXinerama -lfreetype -lXext -lX11 -lQtCore -lfontconfig -lz -lm -lglib-2.0 -ldl -lpthread AR = ar cqs RANLIB = QMAKE = /usr/bin/qmake @@ -57,6 +54,8 @@ DIST = /usr/share/qt4/mkspecs/common/unix.conf \ /usr/share/qt4/mkspecs/features/default_pre.prf \ /usr/share/qt4/mkspecs/features/release.prf \ /usr/share/qt4/mkspecs/features/default_post.prf \ + /usr/share/qt4/mkspecs/features/static.prf \ + /usr/share/qt4/mkspecs/features/staticlib.prf \ /usr/share/qt4/mkspecs/features/warn_on.prf \ /usr/share/qt4/mkspecs/features/qt.prf \ /usr/share/qt4/mkspecs/features/unix/thread.prf \ @@ -66,7 +65,7 @@ DIST = /usr/share/qt4/mkspecs/common/unix.conf \ srm.pro QMAKE_TARGET = srm DESTDIR = -TARGET = srm +TARGET = libsrm.a first: all ####### Implicit rules @@ -90,10 +89,14 @@ first: all ####### Build rules -all: Makefile $(TARGET) +all: Makefile $(TARGET) + +staticlib: $(TARGET) + +$(TARGET): $(OBJECTS) $(OBJCOMP) + -$(DEL_FILE) $(TARGET) + $(AR) $(TARGET) $(OBJECTS) -$(TARGET): $(OBJECTS) - $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS) Makefile: srm.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mkspecs/common/unix.conf \ /usr/share/qt4/mkspecs/common/g++.conf \ @@ -105,6 +108,8 @@ Makefile: srm.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mk /usr/share/qt4/mkspecs/features/default_pre.prf \ /usr/share/qt4/mkspecs/features/release.prf \ /usr/share/qt4/mkspecs/features/default_post.prf \ + /usr/share/qt4/mkspecs/features/static.prf \ + /usr/share/qt4/mkspecs/features/staticlib.prf \ /usr/share/qt4/mkspecs/features/warn_on.prf \ /usr/share/qt4/mkspecs/features/qt.prf \ /usr/share/qt4/mkspecs/features/unix/thread.prf \ @@ -124,6 +129,8 @@ Makefile: srm.pro /usr/share/qt4/mkspecs/linux-g++/qmake.conf /usr/share/qt4/mk /usr/share/qt4/mkspecs/features/default_pre.prf: /usr/share/qt4/mkspecs/features/release.prf: /usr/share/qt4/mkspecs/features/default_post.prf: +/usr/share/qt4/mkspecs/features/static.prf: +/usr/share/qt4/mkspecs/features/staticlib.prf: /usr/share/qt4/mkspecs/features/warn_on.prf: /usr/share/qt4/mkspecs/features/qt.prf: /usr/share/qt4/mkspecs/features/unix/thread.prf: @@ -137,7 +144,7 @@ qmake: FORCE dist: @$(CHK_DIR_EXISTS) .tmp/srm1.0.0 || $(MKDIR) .tmp/srm1.0.0 - $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/srm1.0.0/ && $(COPY_FILE) --parents srm.cpp .tmp/srm1.0.0/ && (cd `dirname .tmp/srm1.0.0` && $(TAR) srm1.0.0.tar srm1.0.0 && $(COMPRESS) srm1.0.0.tar) && $(MOVE) `dirname .tmp/srm1.0.0`/srm1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/srm1.0.0 + $(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/srm1.0.0/ && $(COPY_FILE) --parents srm.h .tmp/srm1.0.0/ && $(COPY_FILE) --parents srm.cpp .tmp/srm1.0.0/ && (cd `dirname .tmp/srm1.0.0` && $(TAR) srm1.0.0.tar srm1.0.0 && $(COMPRESS) srm1.0.0.tar) && $(MOVE) `dirname .tmp/srm1.0.0`/srm1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/srm1.0.0 yaccclean: diff --git a/src/srm/srm.cpp b/src/srm/srm.cpp index b52a4417c..819f7cc0f 100644 --- a/src/srm/srm.cpp +++ b/src/srm/srm.cpp @@ -3,9 +3,7 @@ // (http://www.stephanmantler.com/?page_id=86). // -#include -#include -#include +#include "srm.h" #include #include #include @@ -32,18 +30,23 @@ static quint32 readLong(QDataStream &in) return htonl(value); // SRM uses big endian } +struct marker +{ + int start, end; +}; + struct blockhdr { QDateTime dt; quint16 chunkcnt; }; -int main(int argc, char *argv[]) +bool readSrmFile(QFile &file, SrmData &data, QStringList &errorStrings) { - assert(argc > 1); - QFile file(argv[1]); - if (!file.open(QFile::ReadOnly)) - assert(false); + if (!file.open(QFile::ReadOnly)) { + errorStrings << QString("can't open file %1").arg(file.fileName()); + return false; + } QDataStream in(&file); char magic[5]; @@ -65,13 +68,13 @@ int main(int argc, char *argv[]) in.readRawData(comment, sizeof(comment) - 1); comment[commentlen - 1] = '\0'; - double recint = ((double) recint1) / recint2; - unsigned recintms = (unsigned) round(recint * 1000.0); + data.recint = ((double) recint1) / recint2; + unsigned recintms = (unsigned) round(data.recint * 1000.0); printf("magic=%s\n", magic); printf("wheelcirc=%d\n", wheelcirc); printf("dayssince1880=%d\n", dayssince1880); - printf("recint=%f sec\n", recint); + printf("recint=%f sec\n", data.recint); printf("blockcnt=%d\n", blockcnt); printf("markercnt=%d\n", markercnt); printf("commentlen=%d\n", commentlen); @@ -82,6 +85,7 @@ int main(int argc, char *argv[]) printf("date=%s\n", date.toString().toAscii().constData()); + marker *markers = new marker[markercnt + 1]; for (int i = 0; i <= markercnt; ++i) { char mcomment[256]; in.readRawData(mcomment, sizeof(mcomment) - 1); @@ -95,6 +99,8 @@ int main(int argc, char *argv[]) quint16 avgcad = readShort(in); quint16 avgspeed = readShort(in); quint16 pwc150 = readShort(in); + markers[i].start = start; + markers[i].end = end; printf("marker %d:\n", i); printf(" mcomment=%s\n", mcomment); @@ -129,7 +135,15 @@ int main(int argc, char *argv[]) printf("slope=%d\n", slope); printf("datacnt=%d\n", datacnt); - for (int i = 0, blknum = 0, blkidx = 0; i < datacnt; ++i) { + assert(blockcnt > 0); + + int blknum = 0, blkidx = 0, mrknum = 0, interval = 0; + double km = 0.0, secs = 0.0; + + if (markercnt > 0) + mrknum = 1; + + for (int i = 0; i < datacnt; ++i) { quint8 ps[3]; in.readRawData((char*) ps, sizeof(ps)); quint8 cad = readByte(in); @@ -137,17 +151,76 @@ int main(int argc, char *argv[]) double kph = (((((unsigned) ps[1]) & 0xf0) << 3) | (ps[0] & 0x7f)) * 3.0 / 26.0; unsigned watts = (ps[1] & 0x0f) | (ps[2] << 0x4); - QDateTime dt = blockhdrs[blknum].dt.addMSecs(recintms * blkidx); - printf(" %s %5.1f %4d %3d %3d\n", - dt.toString().toAscii().constData(), kph, watts, hr, cad); + if (i == 0) { + data.startTime = blockhdrs[blknum].dt; + printf("startTime=%s\n", + data.startTime.toString().toAscii().constData()); + } + if (i == markers[mrknum].end) { + ++interval; + ++mrknum; + } + + if ((i > 0) && (i == markers[mrknum].start)) + ++interval; + + km += data.recint * kph / 3600.0; + + SrmDataPoint *point = new SrmDataPoint; + point->cad = cad; + point->hr = hr; + point->watts = watts; + point->interval = interval; + point->kph = kph; + point->km = km; + point->secs = secs; + data.dataPoints.append(point); + + printf("%5.1f %5.1f %5.1f %4d %3d %3d %2d\n", + secs, km, kph, watts, hr, cad, interval); + ++blkidx; - if (blkidx == blockhdrs[blknum].chunkcnt) { + if ((blkidx == blockhdrs[blknum].chunkcnt) && (blknum + 1 < blockcnt)) { + QDateTime end = blockhdrs[blknum].dt.addMSecs( + recintms * blockhdrs[blknum].chunkcnt); ++blknum; blkidx = 0; + QDateTime start = blockhdrs[blknum].dt; + qint64 endms = + ((qint64) end.toTime_t()) * 1000 + end.time().msec(); + qint64 startms = + ((qint64) start.toTime_t()) * 1000 + start.time().msec(); + qint64 diff = startms - endms; + if (diff < 0) { + errorStrings << QString("ERROR: time goes backwards by %1 ms" + " on trans " "to block %2" + ).arg(diff).arg(blknum); + secs += data.recint; // for lack of a better option + } + else { + // printf("jumping forward %lld ms\n", diff); + secs += diff / 1000.0; + } + } + else { + secs += data.recint; } } file.close(); - return 0; + return true; } +/* +int main(int argc, char *argv[]) { + assert(argc > 1); + QFile file(argv[1]); + QStringList errorStrings; + SrmData data; + if (readSrmFile(file, data, errorStrings)) + return 0; + else + return -1; +} +*/ + diff --git a/src/srm/srm.h b/src/srm/srm.h new file mode 100644 index 000000000..5c3d957f8 --- /dev/null +++ b/src/srm/srm.h @@ -0,0 +1,31 @@ + +#ifndef _srm_h +#define _srm_h + +#include +#include +#include +#include + +struct SrmDataPoint +{ + int cad, hr, watts, interval; + double kph, km, secs; +}; + +struct SrmData +{ + QDateTime startTime; + double recint; + QList dataPoints; + ~SrmData() { + QListIterator i(dataPoints); + while (i.hasNext()) + delete i.next(); + } +}; + +bool readSrmFile(QFile &file, SrmData &data, QStringList &errorStrings); + +#endif // _srm_h + diff --git a/src/srm/srm.pro b/src/srm/srm.pro index a197b4728..17744ef65 100644 --- a/src/srm/srm.pro +++ b/src/srm/srm.pro @@ -2,14 +2,15 @@ # Automatically generated by qmake (2.01a) Sun Apr 8 17:19:06 2007 ###################################################################### -TEMPLATE = app +TEMPLATE = lib TARGET = DEPENDPATH += . INCLUDEPATH += . -CXXFLAGS += -std=c99 +CONFIG += static LIBS += -lm # Input +HEADERS += srm.h SOURCES += srm.cpp