@@ -590,6 +590,14 @@ void virtualrower::rowerProvider() {
590590 writeCharacteristic (servicePM5Rowing, charStrokeData, strokeData);
591591 qDebug () << " PM5 Stroke Data:" << strokeData.toHex (' ' );
592592 }
593+
594+ // Send Additional Stroke Data (CE060036)
595+ QByteArray additionalStrokeData = buildPM5AdditionalStrokeData ();
596+ QLowEnergyCharacteristic charAdditionalStrokeData = servicePM5Rowing->characteristic (PM5_ADDITIONAL_STROKE_DATA_UUID );
597+ if (charAdditionalStrokeData.isValid ()) {
598+ writeCharacteristic (servicePM5Rowing, charAdditionalStrokeData, additionalStrokeData);
599+ qDebug () << " PM5 Additional Stroke Data:" << additionalStrokeData.toHex (' ' );
600+ }
593601 } else {
594602 // FTMS protocol (original code)
595603 value.append ((char )0x2C );
@@ -1238,3 +1246,84 @@ QByteArray virtualrower::buildPM5StrokeData() {
12381246
12391247 return value;
12401248}
1249+
1250+ QByteArray virtualrower::buildPM5AdditionalStrokeData () {
1251+ // PM5 Additional Stroke Data - 17 bytes
1252+ // Bytes 0-2: Elapsed Time (UInt24LE, 0.01 sec)
1253+ // Bytes 3-4: Stroke Power (UInt16LE, watts)
1254+ // Bytes 5-6: Stroke Calories (UInt16LE, calories)
1255+ // Bytes 7-8: Stroke Count (UInt16LE)
1256+ // Bytes 9-11: Projected Work Time (UInt24LE, 0.01 sec)
1257+ // Bytes 12-14: Projected Work Distance (UInt24LE, meters)
1258+ // Bytes 15-16: Work Per Stroke (UInt16LE, Joules)
1259+
1260+ QByteArray value (17 , 0 );
1261+
1262+ // Calculate elapsed time in centiseconds (0.01 sec units)
1263+ uint32_t elapsedCentiseconds = (uint32_t )(
1264+ (Rower->movingTime ().hour () * 3600 +
1265+ Rower->movingTime ().minute () * 60 +
1266+ Rower->movingTime ().second ()) * 100 +
1267+ Rower->movingTime ().msec () / 10 );
1268+
1269+ // Elapsed time (24-bit LE)
1270+ value[0 ] = (char )(elapsedCentiseconds & 0xFF );
1271+ value[1 ] = (char )((elapsedCentiseconds >> 8 ) & 0xFF );
1272+ value[2 ] = (char )((elapsedCentiseconds >> 16 ) & 0xFF );
1273+
1274+ // Stroke Power in watts (16-bit LE)
1275+ uint16_t strokePower = (uint16_t )Rower->wattsMetricforUI ();
1276+ value[3 ] = (char )(strokePower & 0xFF );
1277+ value[4 ] = (char )((strokePower >> 8 ) & 0xFF );
1278+
1279+ // Stroke Calories (16-bit LE) - calories per stroke
1280+ double strokeRate = Rower->currentCadence ().value ();
1281+ uint16_t strokeCalories = 0 ;
1282+ if (strokeRate > 0 ) {
1283+ double totalCalories = Rower->calories ().value ();
1284+ double totalSeconds = Rower->movingTime ().hour () * 3600 +
1285+ Rower->movingTime ().minute () * 60 +
1286+ Rower->movingTime ().second ();
1287+ if (totalSeconds > 0 ) {
1288+ double totalStrokes = strokeRate * totalSeconds / 60.0 ;
1289+ if (totalStrokes > 0 ) {
1290+ strokeCalories = (uint16_t )(totalCalories * 1000.0 / totalStrokes); // in 0.001 kCal
1291+ }
1292+ }
1293+ }
1294+ value[5 ] = (char )(strokeCalories & 0xFF );
1295+ value[6 ] = (char )((strokeCalories >> 8 ) & 0xFF );
1296+
1297+ // Stroke Count (16-bit LE)
1298+ uint16_t pm5StrokeCount = 0 ;
1299+ if (strokeRate > 0 ) {
1300+ double totalSeconds = Rower->movingTime ().hour () * 3600 +
1301+ Rower->movingTime ().minute () * 60 +
1302+ Rower->movingTime ().second () +
1303+ Rower->movingTime ().msec () / 1000.0 ;
1304+ pm5StrokeCount = (uint16_t )(strokeRate * totalSeconds / 60.0 );
1305+ }
1306+ value[7 ] = (char )(pm5StrokeCount & 0xFF );
1307+ value[8 ] = (char )((pm5StrokeCount >> 8 ) & 0xFF );
1308+
1309+ // Projected Work Time - 0 (no target)
1310+ value[9 ] = 0x00 ;
1311+ value[10 ] = 0x00 ;
1312+ value[11 ] = 0x00 ;
1313+
1314+ // Projected Work Distance - 0 (no target)
1315+ value[12 ] = 0x00 ;
1316+ value[13 ] = 0x00 ;
1317+ value[14 ] = 0x00 ;
1318+
1319+ // Work Per Stroke in Joules (16-bit LE)
1320+ uint16_t workPerStroke = 0 ;
1321+ if (strokeRate > 0 && strokePower > 0 ) {
1322+ double strokeTime = 60.0 / strokeRate;
1323+ workPerStroke = (uint16_t )(strokePower * strokeTime);
1324+ }
1325+ value[15 ] = (char )(workPerStroke & 0xFF );
1326+ value[16 ] = (char )((workPerStroke >> 8 ) & 0xFF );
1327+
1328+ return value;
1329+ }
0 commit comments