From 8ddabfb6ec4c2ec9fa6977b08cc2a50223d447d6 Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Sat, 24 Sep 2011 17:44:30 +0100 Subject: [PATCH] Improved WKO+ file support Refactored to improve support for files created in earlier versions of WKO/CyclingPeaks. The changes are largely focused on parsing charts and caches that we don't really use, but need to be waded through to land on the data points. This has been tested on over 1,500 WKO+ files and found to be ok for those. Further regression testing would be beneficial. Better support for; * Running / Swimming files (different chart setup) * Where users have customised the default charts * Earlier versions of CP/WKO+ (esp v1 and v12 format from CP v1.1/1.2) * Latest versions (v3.0) Specifically; * Better support for WKO file formats v1 and v12 * Fix parsing of distribution caches and config * Improved parsing of MeanMax caches and config * Support for Suunto devices added * Support for files with no time data Fixes #457. --- src/WkoRideFile.cpp | 720 +++++++++++++++++++++++--------------------- src/WkoRideFile.h | 45 ++- 2 files changed, 405 insertions(+), 360 deletions(-) diff --git a/src/WkoRideFile.cpp b/src/WkoRideFile.cpp index 0f6fd91a4..b6142b7b7 100644 --- a/src/WkoRideFile.cpp +++ b/src/WkoRideFile.cpp @@ -96,13 +96,14 @@ WkoParser::WkoParser(QFile &file, QStringList &errors, QList*rides) errors <29) { + } else if (version >31) { errors << ("Version of file is new and not fully supported yet: \"" + file.fileName() + "\""); } // Allocate space for newly parsed ride results = new RideFile; + results->setTag("File Format", QString("WKO v%1").arg(version)); // read header data and store details into rideFile structure rawdata = parseHeaderData(headerdata); @@ -207,7 +208,6 @@ WkoParser::parseRawData(WKO_UCHAR *fb) } else { records = us; } - //qDebug()<<"records="<setRecIntSecs(1); + rtime += 1000; + } + // Now output this sample if it is not a null record if (!isnull) { // !! needs to be modified to support the new alt patch @@ -497,7 +503,6 @@ WkoParser::parseHeaderData(WKO_UCHAR *fb) WKO_UCHAR *goal=NULL, *notes=NULL, *code=NULL; // save location of WKO metadata enum configtype lastchart; - unsigned int x,z,i; /* utility holders */ WKO_ULONG num; @@ -506,8 +511,6 @@ WkoParser::parseHeaderData(WKO_UCHAR *fb) WKO_USHORT us; double g; - boost::scoped_array txtbuf(new WKO_UCHAR[1024000]); - /* working through filebuf */ WKO_UCHAR *p = fb; @@ -671,6 +674,7 @@ WkoParser::parseHeaderData(WKO_UCHAR *fb) case 0x12 : results->setDeviceType("Garmin Edge 205/305"); break; case 0x13 : results->setDeviceType("Garmin Edge 705"); break; case 0x14 : results->setDeviceType("iBike"); break; + case 0x15 : results->setDeviceType("Suunto"); break; case 0x16 : results->setDeviceType("Cycleops 300PT"); break; case 0x19 : results->setDeviceType("Ergomo"); break; default : results->setDeviceType("WKO"); break; @@ -679,7 +683,7 @@ WkoParser::parseHeaderData(WKO_UCHAR *fb) if (version != 12) p += donumber(p, &ul); /* 29: unknown */ if (version != 1 && version !=7) { //!!! Version 1 beta support - for (i=0; i< 16; i++) { // 16 types of chart data + for (int i=0; i< 16; i++) { // 16 types of chart data if (version != 12) { p += 44; @@ -716,7 +720,7 @@ WkoParser::parseHeaderData(WKO_UCHAR *fb) // and they are post-processed after the call to // parseRawData in openRideFile above. p += doshort(p, &us); /* 237: Number of ranges XXVARIABLEXX */ - for (i=0; i references; + int charts; - // Header data parsing + // used by all the parsers as temporary storage + unsigned char txtbuf[102400]; // text buffer + WKO_ULONG num; + WKO_ULONG ul; + WKO_USHORT us; + + // Header data parsing - the first section of + // a WKO file contains general + // ride/athlete data, intervals + // device specific data and then + // charts and caches WKO_UCHAR *parseHeaderData(WKO_UCHAR *data); + WKO_UCHAR *parseCRideSettingsConfig(WKO_UCHAR *data); + WKO_UCHAR *parseCRideGoalConfig(WKO_UCHAR *data); + WKO_UCHAR *parseCRideNotesConfig(WKO_UCHAR *data); + WKO_UCHAR *parseCDistributionChartConfig(WKO_UCHAR *data); + WKO_UCHAR *parseCRideSummaryConfig(WKO_UCHAR *data); + WKO_UCHAR *parseCMeanMaxChartConfig(WKO_UCHAR *data); + WKO_UCHAR *parseCMeanMaxChartCache(WKO_UCHAR *data); + WKO_UCHAR *parseCDistributionChartCache(WKO_UCHAR *data); - // Raw bit packed data parsing - WKO_UCHAR *parseRawData(WKO_UCHAR *data); + // re-used across all the segment parsers above + WKO_UCHAR *parsePerspective(WKO_UCHAR *p); + WKO_UCHAR *parseChart(WKO_UCHAR *p, int type = 0); // Basic Field decoding unsigned int doshort(WKO_UCHAR *p, WKO_USHORT *pnum); @@ -82,19 +102,26 @@ class WkoParser unsigned int optpad(WKO_UCHAR *p), optpad2(WKO_UCHAR *p); + // Telemetry data parsing - the second section of a + // WKO file contains the ride + // telemetry, but bit packed to + // save storage space + WKO_UCHAR *parseRawData(WKO_UCHAR *data); + // Bit twiddling functions + void setxormasks(); int get_bit(WKO_UCHAR *data, unsigned bitoffset); unsigned int get_bits(WKO_UCHAR* data, unsigned bitOffset, unsigned numBits); - - // Decoding setup - void setxormasks(); - WKO_ULONG nullvals(char graph, WKO_ULONG version); unsigned long bitget(char *thelot, int offset, int count); + + // Utilities to return bit packed field sizes based + // upon the original device type (data is stored in + // different lengths (8bit, 11bit, 22bit etc) + WKO_ULONG nullvals(char graph, WKO_ULONG version); unsigned int bitsize(char graph, int device, WKO_ULONG version); void pbin(WKO_UCHAR x); // for debugging - // different Chart segment types - + // Different chart types enum configtype { CRIDESETTINGSCONFIG, CRIDEGOALCONFIG,