@@ -170,10 +170,6 @@ void cscbike::update() {
170170 QSettings settings;
171171 QString heartRateBeltName =
172172 settings.value (QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString ();
173- bool externalPowerSensorEnabled =
174- !settings.value (QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
175- .toString ()
176- .startsWith (QStringLiteral (" Disabled" ));
177173
178174 if (!noVirtualDevice) {
179175#ifdef Q_OS_ANDROID
@@ -187,24 +183,21 @@ void cscbike::update() {
187183 }
188184 }
189185
190- if (!externalPowerSensorEnabled) {
191- bool rogue_echo_bike =
192- settings.value (QZSettings::rogue_echo_bike, QZSettings::default_rogue_echo_bike).toBool ();
193-
194- if (manualResistancePowerAdjustmentActive && jorotoBike) {
195- m_watt = manualResistanceAdjustedWatts ();
196- } else if (manualResistancePowerAdjustmentActive && useCustomResistancePowerTable ()) {
197- m_watt = customResistanceAdjustedWatts (currentCadence ().value (), manualResistanceTarget);
198- } else if (rogue_echo_bike) {
199- double rpm = currentCadence ().value ();
200- m_watt = 0.000602337 * pow (rpm, 3.11762 ) + 32.6404 ;
186+ bool rogue_echo_bike = settings.value (QZSettings::rogue_echo_bike, QZSettings::default_rogue_echo_bike).toBool ();
187+
188+ if (manualResistancePowerAdjustmentActive && jorotoBike) {
189+ m_watt = manualResistanceAdjustedWatts ();
190+ } else if (manualResistancePowerAdjustmentActive && useCustomResistancePowerTable ()) {
191+ m_watt = customResistanceAdjustedWatts (currentCadence ().value (), manualResistanceTarget);
192+ } else if (rogue_echo_bike) {
193+ double rpm = currentCadence ().value ();
194+ m_watt = 0.000602337 * pow (rpm, 3.11762 ) + 32.6404 ;
195+ } else {
196+ // When cadence is zero, watts should be zero regardless of HR
197+ if (currentCadence ().value () == 0 ) {
198+ m_watt = 0 ;
201199 } else {
202- // When cadence is zero, watts should be zero regardless of HR
203- if (currentCadence ().value () == 0 ) {
204- m_watt = 0 ;
205- } else {
206- m_watt = wattFromHR (false );
207- }
200+ m_watt = wattFromHR (false );
208201 }
209202 }
210203 emit debug (QStringLiteral (" Current Watt: " ) + QString::number (m_watt.value ()));
@@ -279,15 +272,6 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
279272 qDebug () << " characteristicChanged << " << characteristic.uuid () << newValue.toHex (' ' ) << newValue.length ();
280273 Q_UNUSED (characteristic);
281274 QSettings settings;
282- bool externalCadenceSensorEnabled =
283- !settings.value (QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
284- .toString ()
285- .startsWith (QStringLiteral (" Disabled" ));
286- bool externalPowerSensorEnabled =
287- !settings.value (QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
288- .toString ()
289- .startsWith (QStringLiteral (" Disabled" ));
290- bool useMachineCadence = !externalCadenceSensorEnabled && !externalPowerSensorEnabled;
291275 // QString heartRateBeltName = //unused QString
292276 // settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
293277
@@ -309,14 +293,47 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
309293 return ;
310294 }
311295
312- if (characteristic.uuid () != QBluetoothUuid ((quint16)0x2A5B )) {
296+ bool cyclingPowerMeasurement = characteristic.uuid () == QBluetoothUuid::CyclingPowerMeasurement;
297+ if (characteristic.uuid () != QBluetoothUuid ((quint16)0x2A5B ) && !cyclingPowerMeasurement) {
313298 return ;
314299 }
315300
316301 lastPacket = newValue;
317302
318- bool CrankPresent = (newValue.at (0 ) & 0x02 ) == 0x02 ;
319- bool WheelPresent = (newValue.at (0 ) & 0x01 ) == 0x01 ;
303+ bool CrankPresent = false ;
304+ bool WheelPresent = false ;
305+ if (cyclingPowerMeasurement) {
306+ if (newValue.length () < 4 ) {
307+ return ;
308+ }
309+
310+ uint16_t flags = (((uint16_t )((uint8_t )newValue.at (1 )) << 8 ) | (uint16_t )((uint8_t )newValue.at (0 )));
311+ CrankPresent = (flags & 0x20 ) == 0x20 ;
312+ if (!CrankPresent) {
313+ return ;
314+ }
315+
316+ uint8_t index = 4 ;
317+ if ((flags & 0x01 ) == 0x01 ) {
318+ index += 1 ; // pedal power balance
319+ }
320+ if ((flags & 0x04 ) == 0x04 ) {
321+ index += 2 ; // accumulated torque
322+ }
323+ if ((flags & 0x10 ) == 0x10 ) {
324+ index += 6 ; // wheel revolutions and wheel event time
325+ }
326+ if (newValue.length () < index + 4 ) {
327+ return ;
328+ }
329+
330+ _CrankRevs = (((uint16_t )((uint8_t )newValue.at (index + 1 )) << 8 ) | (uint16_t )((uint8_t )newValue.at (index)));
331+ _LastCrankEventTime =
332+ (((uint16_t )((uint8_t )newValue.at (index + 3 )) << 8 ) | (uint16_t )((uint8_t )newValue.at (index + 2 )));
333+ } else {
334+ CrankPresent = (newValue.at (0 ) & 0x02 ) == 0x02 ;
335+ WheelPresent = (newValue.at (0 ) & 0x01 ) == 0x01 ;
336+ }
320337 qDebug () << QStringLiteral (" CrankPresent: " ) << CrankPresent;
321338 qDebug () << QStringLiteral (" WheelPresent: " ) << WheelPresent;
322339
@@ -334,14 +351,18 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
334351 emit debug (QStringLiteral (" Current Wheel Event Time: " ) + QString::number (_LastWheelEventTime));
335352 index += 2 ;
336353 }
337- if (CrankPresent) {
354+ if (CrankPresent && !cyclingPowerMeasurement ) {
338355 _CrankRevs = (((uint16_t )((uint8_t )newValue.at (index + 1 )) << 8 ) | (uint16_t )((uint8_t )newValue.at (index)));
339356 emit debug (QStringLiteral (" Current Crank Revs: " ) + QString::number (_CrankRevs));
340357 index += 2 ;
341358 _LastCrankEventTime =
342359 (((uint16_t )((uint8_t )newValue.at (index + 1 )) << 8 ) | (uint16_t )((uint8_t )newValue.at (index)));
343360 emit debug (QStringLiteral (" Current Crank Event Time: " ) + QString::number (_LastCrankEventTime));
344361 }
362+ if (cyclingPowerMeasurement) {
363+ emit debug (QStringLiteral (" Current Crank Revs: " ) + QString::number (_CrankRevs));
364+ emit debug (QStringLiteral (" Current Crank Event Time: " ) + QString::number (_LastCrankEventTime));
365+ }
345366
346367 // CSC Combo Sensor Fallback Logic
347368 //
@@ -367,12 +388,12 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
367388 LastCrankEventTime = _LastCrankEventTime;
368389 }
369390
370- int16_t deltaT = LastCrankEventTime - oldLastCrankEventTime;
391+ int32_t deltaT = LastCrankEventTime - oldLastCrankEventTime;
371392 if (deltaT < 0 ) {
372- deltaT = LastCrankEventTime + 65535 - oldLastCrankEventTime;
393+ deltaT = LastCrankEventTime + 65536 - oldLastCrankEventTime;
373394 }
374395
375- if (useMachineCadence && CrankRevs != oldCrankRevs && deltaT) {
396+ if (CrankRevs != oldCrankRevs && deltaT) {
376397 double cadence = ((CrankRevs - oldCrankRevs) / deltaT) * 1024 * 60 ;
377398
378399 // Cadence Validation Logic
@@ -393,7 +414,7 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
393414 if ((cadence >= 0 && (cadence < 256 || _CrankRevs == 0 ) && CrankPresent) || (!CrankPresent && WheelPresent))
394415 Cadence = cadence;
395416 lastGoodCadence = now;
396- } else if (useMachineCadence && lastGoodCadence.msecsTo (now) > 2000 ) {
417+ } else if (lastGoodCadence.msecsTo (now) > 2000 ) {
397418 Cadence = 0 ;
398419 }
399420 emit cadenceChanged (Cadence.value ());
@@ -490,13 +511,14 @@ void cscbike::stateChanged(QLowEnergyService::ServiceState state) {
490511 emit debug (QStringLiteral (" BTLE stateChanged " ) + QString::fromLocal8Bit (metaEnum.valueToKey (state)));
491512
492513 QBluetoothUuid CyclingSpeedAndCadence (QBluetoothUuid::CyclingSpeedAndCadence);
514+ QBluetoothUuid CyclingPower (QBluetoothUuid::CyclingPower);
493515 QBluetoothUuid Battery (QBluetoothUuid::BatteryService);
494516 for (QLowEnergyService *s : qAsConst (gattCommunicationChannelService)) {
495517 qDebug () << QStringLiteral (" stateChanged" ) << s->serviceUuid () << s->state ();
496518#ifdef Q_OS_WINDOWS
497- qDebug () << " windows workaround, check only CyclingSpeedAndCadence ftms service "
498- << (s->serviceUuid () == CyclingSpeedAndCadence);
499- if (s->serviceUuid () == CyclingSpeedAndCadence)
519+ qDebug () << " windows workaround, check only cycling sensor services "
520+ << (s->serviceUuid () == CyclingSpeedAndCadence || s-> serviceUuid () == CyclingPower );
521+ if (s->serviceUuid () == CyclingSpeedAndCadence || s-> serviceUuid () == CyclingPower )
500522#endif
501523 {
502524 if (s->state () != QLowEnergyService::ServiceDiscovered && s->state () != QLowEnergyService::InvalidService) {
@@ -511,13 +533,15 @@ void cscbike::stateChanged(QLowEnergyService::ServiceState state) {
511533 for (QLowEnergyService *s : qAsConst (gattCommunicationChannelService)) {
512534 if (s->state () == QLowEnergyService::ServiceDiscovered) {
513535
514- if (s->serviceUuid () == CyclingSpeedAndCadence) {
515- qDebug () << " CyclingSpeedAndCadence found" ;
536+ if (s->serviceUuid () == CyclingSpeedAndCadence || s-> serviceUuid () == CyclingPower ) {
537+ qDebug () << " Cycling cadence service found" << s-> serviceUuid () ;
516538 cadenceService = s;
517539 }
518540
519- if (s->serviceUuid () != CyclingSpeedAndCadence && s->serviceUuid () != Battery) {
520- // No data from sensors and avatar won’t move in Zwift (even when data showed on first try) (Issue #2178)
541+ if (s->serviceUuid () != CyclingSpeedAndCadence && s->serviceUuid () != CyclingPower &&
542+ s->serviceUuid () != Battery) {
543+ // No data from sensors and avatar won’t move in Zwift (even when data showed on first try) (Issue
544+ // #2178)
521545 qDebug () << " avoid unwaned service" ;
522546 continue ;
523547 }
@@ -536,8 +560,9 @@ void cscbike::stateChanged(QLowEnergyService::ServiceState state) {
536560
537561 auto characteristics_list = s->characteristics ();
538562 for (const QLowEnergyCharacteristic &c : qAsConst (characteristics_list)) {
539- if (c.uuid () == QBluetoothUuid ((quint16)0x2A5B )) {
540- qDebug () << " CyclingSpeedAndCadence char found" ;
563+ if (c.uuid () == QBluetoothUuid ((quint16)0x2A5B ) ||
564+ c.uuid () == QBluetoothUuid::CyclingPowerMeasurement) {
565+ qDebug () << " Cycling cadence characteristic found" << c.uuid ();
541566 cadenceChar = c;
542567 }
543568 qDebug () << QStringLiteral (" char uuid" ) << c.uuid () << QStringLiteral (" handle" ) << c.handle () << QStringLiteral (" properties" ) << c.properties ();
@@ -663,9 +688,10 @@ void cscbike::serviceScanDone(void) {
663688 for (const QBluetoothUuid &s : qAsConst (services_list)) {
664689#ifdef Q_OS_WINDOWS
665690 QBluetoothUuid CyclingSpeedAndCadence (QBluetoothUuid::CyclingSpeedAndCadence);
666- qDebug () << " windows workaround, check only the CyclingSpeedAndCadence service" << s << CyclingSpeedAndCadence
667- << (s == CyclingSpeedAndCadence);
668- if (s == CyclingSpeedAndCadence)
691+ QBluetoothUuid CyclingPower (QBluetoothUuid::CyclingPower);
692+ qDebug () << " windows workaround, check only cycling sensor services" << s << CyclingSpeedAndCadence
693+ << CyclingPower << (s == CyclingSpeedAndCadence || s == CyclingPower);
694+ if (s == CyclingSpeedAndCadence || s == CyclingPower)
669695#endif
670696 {
671697 gattCommunicationChannelService.append (m_control->createServiceObject (s));
0 commit comments