Skip to content

Commit

Permalink
Include power data in HRM output (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
pcolby committed Jan 3, 2015
1 parent bc801b6 commit 05aa86f
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 94 deletions.
72 changes: 52 additions & 20 deletions src/polar/v2/trainingsession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1390,9 +1390,13 @@ QStringList TrainingSession::toHRM(const bool rrDataOnly) const

const QVariantList rrsamples = map.value(RRSAMPLES).toMap().value(QLatin1String("value")).toList();

const bool haveAltitude = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("speed"))));
const bool haveCadence = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("cadence"))));
const bool haveSpeed = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("altitude"))));
const bool haveAltitude = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("speed"))));
const bool haveCadence = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("cadence"))));
const bool havePowerLeft = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("left-pedal-power"))));
const bool havePowerRight = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("right-pedal-power"))));
const bool havePower = (havePowerLeft || havePowerRight);
const bool havePowerBalance = (havePowerLeft && havePowerRight);
const bool haveSpeed = ((!rrDataOnly) && (haveAnySamples(samples, QLatin1String("altitude"))));

QString hrmData;
QTextStream stream(&hrmData);
Expand All @@ -1403,13 +1407,13 @@ QStringList TrainingSession::toHRM(const bool rrDataOnly) const
"Version=106\r\n"
"Monitor=1\r\n"
"SMode=";
stream << (haveSpeed ? '1' : '0'); // a) Speed
stream << (haveCadence ? '1' : '0'); // b) Cadence
stream << (haveAltitude ? '1' : '0'); // c) Altitude
stream << (haveSpeed ? '1' : '0'); // a) Speed
stream << (haveCadence ? '1' : '0'); // b) Cadence
stream << (haveAltitude ? '1' : '0'); // c) Altitude
stream << (havePower ? '1' : '0'); // d) Power
stream << (havePowerBalance ? '1' : '0'); // e) Power Left Right Balance
stream <<
"0" // d) Power (not supported by V800 yet).
"0" // e) Power Left Right Ballance (not supported by V800 yet).
"0" // f) Power Pedalling Index (not supported by V800 yet).
"0" // f) Power Pedalling Index (does not appear to be supported by FlowSync).
"0" // g) HR/CC data (available only with Polar XTrainer Plus).
"0" // h) US / Euro unit (always metric).
"0" // i) Air pressure (not available).
Expand Down Expand Up @@ -1545,7 +1549,7 @@ QStringList TrainingSession::toHRM(const bool rrDataOnly) const
stream << '\t' << first(hrStats.value(QLatin1String("maximum"))).toUInt();
stream << "\r\n";
// Row 2
stream << "28";
stream << "28"; // All three "extra data" fields present (on row 3).
stream << "\t0"; // Recovery time (seconds); data not available.
stream << "\t0"; // Recovery HR (bpm); data not available.
stream << "\t" << qRound(first(firstMap(stats.value(QLatin1String("speed")))
Expand All @@ -1554,8 +1558,14 @@ QStringList TrainingSession::toHRM(const bool rrDataOnly) const
.value(QLatin1String("maximum"))).toUInt();
stream << "\t0"; // Momentary altitude; not available per lap.
stream << "\r\n";
// Row 3
stream << qRound(first(header.value(QLatin1String("descent"))).toFloat() * 10.0);
// Row 3: HRM allows up to three "extra data" fields. Here we
// choose to leave out descent if power is available.
if (havePower) {
stream << first(firstMap(header.value(QLatin1String("power")))
.value(QLatin1String("average"))).toUInt() * 10;
} else {
stream << qRound(first(header.value(QLatin1String("descent"))).toFloat() * 10.0);
}
stream << '\t' << (first(firstMap(stats.value(QLatin1String("pedaling")))
.value(QLatin1String("average"))).toUInt() * 10);
stream << '\t' << qRound(first(firstMap(stats.value(QLatin1String("incline")))
Expand Down Expand Up @@ -1607,7 +1617,11 @@ QStringList TrainingSession::toHRM(const bool rrDataOnly) const
// all multiplied by 10, to extra data can hold 0..300 units.
if (!laps.isEmpty()) {
stream << "\r\n[ExtraData]\r\n";
stream << "Descent\r\nMeters\t1000\t0\r\n";
if (havePower) {
stream << "Power\r\nW\t3000\t0\r\n";
} else {
stream << "Descent\r\nMeters\t1000\t0\r\n";
}
stream << "Pedaling Index\r\n%\t100\t0\r\n";
stream << "Max Incline\r\nDegrees\t90\t0\r\n";
}
Expand Down Expand Up @@ -1702,26 +1716,44 @@ QStringList TrainingSession::toHRM(const bool rrDataOnly) const
stream << sample.toUInt() << "\r\n";
}
} else {
const QVariantList altitude = samples.value(QLatin1String("altitude")).toList();
const QVariantList cadence = samples.value(QLatin1String("cadence")).toList();
const QVariantList speed = samples.value(QLatin1String("speed")).toList();
const QVariantList altitude = samples.value(QLatin1String("altitude")).toList();
const QVariantList cadence = samples.value(QLatin1String("cadence")).toList();
const QVariantList speed = samples.value(QLatin1String("speed")).toList();
const QVariantList powerLeft = samples.value(QLatin1String("left-pedal-power")).toList();
const QVariantList powerRight = samples.value(QLatin1String("right-pedal-power")).toList();
for (int index = 0; index < heartrate.length(); ++index) {
stream << ((index < heartrate.length())
? heartrate.at(index).toUInt() : (uint)0);
if (haveSpeed) {
stream << '\t' << ((index < speed.length())
? qRound(speed.at(index).toFloat() * 10.0) : ( int)0);
? qRound(speed.at(index).toFloat() * 10.0) : (int)0);
}
if (haveCadence) {
stream << '\t' << ((index < cadence.length())
? cadence.at(index).toUInt() : (uint)0);
}
if (haveAltitude) {
stream << '\t' << ((index < altitude.length())
? qRound(altitude.at(index).toFloat()) : ( int)0);
? qRound(altitude.at(index).toFloat()) : (int)0);
}
if (havePower) {
const int currentPowerLeft = (index < powerLeft.length()) ?
first(powerLeft.at(index).toMap().value(QLatin1String("current-power"))).toInt() : 0;
const int currentPowerRight = (index < powerRight.length()) ?
first(powerRight.at(index).toMap().value(QLatin1String("current-power"))).toInt() : 0;
const int currentPower = currentPowerLeft + currentPowerRight;
stream << '\t' << currentPower;
if (havePowerBalance) {
// Convert the left and right powers into a left-right balance percentage.
const int leftBalance = (currentPower == 0) ? 0 :
qRound(100.0 * (float)currentPowerLeft / (float)currentPower);
if (leftBalance > 100) {
qWarning() << "leftBalance of " << leftBalance << "% is greater than 100%";
}
/// @todo Include Pedalling Index here, if/when available.
stream << '\t' << qMax(qMin(leftBalance, 255), 0);
}
}
// Power (Watts) - not yet supported by Polar.
// Power Balance and Pedalling Index - not yet supported by Polar.
// Air pressure - not available in protobuf data.
stream << "\r\n";
}
Expand Down
74 changes: 37 additions & 37 deletions test/polar/v2/testdata/training-sessions-42261903.LapNames.hrm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[Params]
Version=106
Monitor=1
SMode=011000000
SMode=011110000
Date=20141229
StartTime=12:58:44.0
Length=00:00:35.8
Expand Down Expand Up @@ -63,39 +63,39 @@ Inomhuscykling
0

[HRData]
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 39 0
0 39 0
0 39 0
0 47 0
0 47 0
0 55 0
0 61 0
0 66 0
0 53 0
0 58 0
0 58 0
0 75 0
0 77 0
0 77 0
0 80 0
0 79 0
0 75 0
0 69 0
0 62 0
0 55 0
0 60 0
0 71 0
0 96 0
0 106 0
0 106 0
0 51 0
0 26 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 30 0
0 0 0 25 0
0 0 0 37 32
0 0 0 55 55
0 0 0 61 49
0 39 0 31 32
0 39 0 71 70
0 39 0 101 50
0 47 0 142 57
0 47 0 123 50
0 55 0 119 40
0 61 0 47 0
0 66 0 77 25
0 53 0 105 72
0 58 0 136 49
0 58 0 141 50
0 75 0 142 46
0 77 0 132 44
0 77 0 128 49
0 80 0 136 46
0 79 0 113 39
0 75 0 51 88
0 69 0 15 0
0 62 0 19 0
0 55 0 93 5
0 60 0 271 58
0 71 0 287 49
0 96 0 249 53
0 106 0 94 50
0 106 0 0 0
0 51 0 0 0
0 26 0 0 0
74 changes: 37 additions & 37 deletions test/polar/v2/testdata/training-sessions-42261903.hrm
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[Params]
Version=106
Monitor=1
SMode=011000000
SMode=011110000
Date=20141229
StartTime=12:58:44.0
Length=00:00:35.8
Expand Down Expand Up @@ -63,39 +63,39 @@ Inomhuscykling
0

[HRData]
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 39 0
0 39 0
0 39 0
0 47 0
0 47 0
0 55 0
0 61 0
0 66 0
0 53 0
0 58 0
0 58 0
0 75 0
0 77 0
0 77 0
0 80 0
0 79 0
0 75 0
0 69 0
0 62 0
0 55 0
0 60 0
0 71 0
0 96 0
0 106 0
0 106 0
0 51 0
0 26 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 0 0
0 0 0 30 0
0 0 0 25 0
0 0 0 37 32
0 0 0 55 55
0 0 0 61 49
0 39 0 31 32
0 39 0 71 70
0 39 0 101 50
0 47 0 142 57
0 47 0 123 50
0 55 0 119 40
0 61 0 47 0
0 66 0 77 25
0 53 0 105 72
0 58 0 136 49
0 58 0 141 50
0 75 0 142 46
0 77 0 132 44
0 77 0 128 49
0 80 0 136 46
0 79 0 113 39
0 75 0 51 88
0 69 0 15 0
0 62 0 19 0
0 55 0 93 5
0 60 0 271 58
0 71 0 287 49
0 96 0 249 53
0 106 0 94 50
0 106 0 0 0
0 51 0 0 0
0 26 0 0 0

0 comments on commit 05aa86f

Please sign in to comment.