Skip to content

Commit

Permalink
Parse the training session *-statistics data
Browse files Browse the repository at this point in the history
Needed to TrainingSession::toHRM (aka issue #14).
  • Loading branch information
pcolby committed Jul 29, 2014
1 parent 6ef41f7 commit 169e6f9
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 16 deletions.
88 changes: 73 additions & 15 deletions src/polar/v2/trainingsession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@
#endif

// These constants match those used by Polar's V2 API.
#define CREATE QLatin1String("create")
#define LAPS QLatin1String("laps")
#define ROUTE QLatin1String("route")
#define SAMPLES QLatin1String("samples")
#define ZONES QLatin1String("zones")
#define CREATE QLatin1String("create")
#define LAPS QLatin1String("laps")
#define ROUTE QLatin1String("route")
#define SAMPLES QLatin1String("samples")
#define STATISTICS QLatin1String("statistics")
#define ZONES QLatin1String("zones")

namespace polar {
namespace v2 {
Expand Down Expand Up @@ -198,14 +199,14 @@ bool TrainingSession::parse(const QString &exerciseId, const QMap<QString, QStri
sources << fileNames.value(str); \
} \
}
PARSE_IF_CONTAINS(CREATE, CreateExercise);
PARSE_IF_CONTAINS(LAPS, Laps);
//PARSE_IF_CONTAINS(PHASES, Phases);
PARSE_IF_CONTAINS(ROUTE, Route);
PARSE_IF_CONTAINS(SAMPLES, Samples);
//PARSE_IF_CONTAINS(SENSORS, Sensors);
//PARSE_IF_CONTAINS(STATS, Stats);
PARSE_IF_CONTAINS(ZONES, Zones);
PARSE_IF_CONTAINS(CREATE, CreateExercise);
PARSE_IF_CONTAINS(LAPS, Laps);
//PARSE_IF_CONTAINS(PHASES, Phases);
PARSE_IF_CONTAINS(ROUTE, Route);
PARSE_IF_CONTAINS(SAMPLES, Samples);
//PARSE_IF_CONTAINS(SENSORS, Sensors);
PARSE_IF_CONTAINS(STATISTICS, Statistics);
PARSE_IF_CONTAINS(ZONES, Zones);
#undef PARSE_IF_CONTAINS

if (!exercise.empty()) {
Expand Down Expand Up @@ -554,6 +555,63 @@ QVariantMap TrainingSession::parseSamples(const QString &fileName) const
return parseSamples(file);
}

QVariantMap TrainingSession::parseStatistics(QIODevice &data) const
{
ProtoBuf::Message::FieldInfoMap fieldInfo;
ADD_FIELD_INFO("1", "heartrate", EmbeddedMessage);
ADD_FIELD_INFO("1/1", "minimum", Uint32);
ADD_FIELD_INFO("1/2", "average", Uint32);
ADD_FIELD_INFO("1/3", "maximum", Uint32);
ADD_FIELD_INFO("2", "speed", EmbeddedMessage);
ADD_FIELD_INFO("2/1", "average", Float);
ADD_FIELD_INFO("2/1", "maximum", Float);
ADD_FIELD_INFO("3", "cadence", EmbeddedMessage);
ADD_FIELD_INFO("3/1", "average", Uint32);
ADD_FIELD_INFO("3/1", "maximum", Uint32);
ADD_FIELD_INFO("4", "altitude", EmbeddedMessage);
ADD_FIELD_INFO("4/1", "minimum", Float);
ADD_FIELD_INFO("4/2", "average", Float);
ADD_FIELD_INFO("4/3", "maximum", Float);
ADD_FIELD_INFO("5", "power", EmbeddedMessage);
ADD_FIELD_INFO("5/1", "average", Uint32);
ADD_FIELD_INFO("5/1", "maximum", Uint32);
ADD_FIELD_INFO("6", "lr_balance", EmbeddedMessage);
ADD_FIELD_INFO("6/1", "average", Float);
ADD_FIELD_INFO("7", "temperature", EmbeddedMessage);
ADD_FIELD_INFO("7/1", "minimum", Float);
ADD_FIELD_INFO("7/2", "average", Float);
ADD_FIELD_INFO("7/3", "maximum", Float);
ADD_FIELD_INFO("8", "activity", EmbeddedMessage);
ADD_FIELD_INFO("8/1", "average", Float);
ADD_FIELD_INFO("9", "stride", EmbeddedMessage);
ADD_FIELD_INFO("9/1", "average", Uint32);
ADD_FIELD_INFO("9/1", "maximum", Uint32);
ADD_FIELD_INFO("10", "include", EmbeddedMessage);
ADD_FIELD_INFO("10/1", "average", Float);
ADD_FIELD_INFO("10/1", "maximum", Float);
ADD_FIELD_INFO("11", "declince", EmbeddedMessage);
ADD_FIELD_INFO("11/1", "average", Float);
ADD_FIELD_INFO("11/1", "maximum", Float);
ProtoBuf::Message parser(fieldInfo);

if (isGzipped(data)) {
QByteArray array = unzip(data.readAll());
return parser.parse(array);
} else {
return parser.parse(data);
}
}

QVariantMap TrainingSession::parseStatistics(const QString &fileName) const
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "failed to open stats file" << fileName;
return QVariantMap();
}
return parseStatistics(file);
}

QVariantMap TrainingSession::parseZones(QIODevice &data) const
{
ProtoBuf::Message::FieldInfoMap fieldInfo;
Expand Down Expand Up @@ -1015,7 +1073,7 @@ QDomDocument TrainingSession::toTCX(const QString &buildTime) const

foreach (const QVariant &exercise, parsedExercises) {
const QVariantMap map = exercise.toMap();
if (!map.contains(QLatin1String("create"))) {
if (!map.contains(CREATE)) {
qWarning() << "skipping exercise with no 'create' request data";
continue;
}
Expand All @@ -1034,7 +1092,7 @@ QDomDocument TrainingSession::toTCX(const QString &buildTime) const
}
Q_ASSERT(!activity.parentNode().isNull());

const QVariantMap create = map.value(QLatin1String("create")).toMap();
const QVariantMap create = map.value(CREATE).toMap();

// Get the sport type.
activity.setAttribute(QLatin1String("Sport"),
Expand Down
2 changes: 2 additions & 0 deletions src/polar/v2/trainingsession.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class TrainingSession : public QObject {
QVariantMap parseRoute(const QString &fileName) const;
QVariantMap parseSamples(QIODevice &data) const;
QVariantMap parseSamples(const QString &fileName) const;
QVariantMap parseStatistics(QIODevice &data) const;
QVariantMap parseStatistics(const QString &fileName) const;
QVariantMap parseZones(QIODevice &data) const;
QVariantMap parseZones(const QString &fileName) const;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

Uw�
��@?5A"��5C]K�C�+D:33�A�}�AffB
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"altitude": [
{
"average": [
368.58877563476562
],
"maximum": [
528.6820068359375
],
"minimum": [
181.66300964355469
]
}
],
"heartrate": [
{
"average": [
119
],
"maximum": [
161
],
"minimum": [
85
]
}
],
"speed": [
{
"2": [
"3f350641"
],
"maximum": [
4.219667911529541
]
}
],
"temperature": [
{
"average": [
24.811319351196289
],
"maximum": [
32.349998474121094
],
"minimum": [
21.399999618530273
]
}
]
}
Binary file not shown.
2 changes: 1 addition & 1 deletion test/polar/v2/testdata/training-sessions-19946380.gpx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<time>2014-07-15T12:34:56Z</time>
</metadata>
<trk>
<src>training-sessions-19946380-exercises-19896844-create training-sessions-19946380-exercises-19896844-route training-sessions-19946380-exercises-19896844-samples training-sessions-19946380-exercises-19896844-zones</src>
<src>training-sessions-19946380-exercises-19896844-create training-sessions-19946380-exercises-19896844-route training-sessions-19946380-exercises-19896844-samples training-sessions-19946380-exercises-19896844-statistics training-sessions-19946380-exercises-19896844-zones</src>
<trkseg>
<trkpt lat="-37.890685" lon="145.3174816666667">
<ele>176</ele>
Expand Down
39 changes: 39 additions & 0 deletions test/polar/v2/testtrainingsession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,45 @@ void TestTrainingSession::parseSamples()
QCOMPARE(result, expected);
}

void TestTrainingSession::parseStatistics_data()
{
QTest::addColumn<QString>("fileName");
QTest::addColumn<QVariantMap>("expected");

#define LOAD_TEST_DATA(name) { \
QFile expectedFile(QFINDTESTDATA("testdata/" name ".expected.var")); \
expectedFile.open(QIODevice::ReadOnly); \
QDataStream expectedStream(&expectedFile); \
QVariantMap expectedMap; \
expectedStream >> expectedMap; \
QTest::newRow(name) << QFINDTESTDATA("testdata/" name) << expectedMap; \
}

LOAD_TEST_DATA("training-sessions-19946380-exercises-19896844-statistics");

#undef LOAD_TEST_DATA
}

void TestTrainingSession::parseStatistics()
{
QFETCH(QString, fileName);
QFETCH(QVariantMap, expected);

QVERIFY2(!fileName.isEmpty(), "failed to find testdata");

// Parse the route (protobuf) message.
const polar::v2::TrainingSession session;
const QVariantMap result = session.parseStatistics(fileName);

// Write the result to files for optional post-mortem investigations.
tools::variant::writeAll(result,
QString::fromLatin1("polar/v2/testdata/%1.result")
.arg(QString::fromLatin1(QTest::currentDataTag())));

// Compare the result.
QCOMPARE(result, expected);
}

void TestTrainingSession::parseZones_data()
{
QTest::addColumn<QString>("fileName");
Expand Down
3 changes: 3 additions & 0 deletions test/polar/v2/testtrainingsession.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ private slots:
void parseSamples_data();
void parseSamples();

void parseStatistics_data();
void parseStatistics();

void parseZones_data();
void parseZones();

Expand Down

0 comments on commit 169e6f9

Please sign in to comment.