Skip to content

Commit 5ab7cd8

Browse files
committed
Merge branch 'master' into Garmin-Chinese-Server
2 parents d58f253 + 72f5705 commit 5ab7cd8

14 files changed

Lines changed: 177 additions & 45 deletions

File tree

build-qdomyos-zwift-Qt_5_15_2_for_iOS-Debug/qdomyoszwift.xcodeproj/project.pbxproj

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4573,7 +4573,7 @@
45734573
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
45744574
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
45754575
COPY_PHASE_STRIP = NO;
4576-
CURRENT_PROJECT_VERSION = 1271;
4576+
CURRENT_PROJECT_VERSION = 1274;
45774577
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
45784578
DEVELOPMENT_TEAM = 6335M7T29D;
45794579
ENABLE_BITCODE = NO;
@@ -4774,7 +4774,7 @@
47744774
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
47754775
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
47764776
COPY_PHASE_STRIP = NO;
4777-
CURRENT_PROJECT_VERSION = 1271;
4777+
CURRENT_PROJECT_VERSION = 1274;
47784778
DEBUG_INFORMATION_FORMAT = dwarf;
47794779
DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
47804780
DEVELOPMENT_TEAM = 6335M7T29D;
@@ -5011,7 +5011,7 @@
50115011
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
50125012
CODE_SIGN_IDENTITY = "Apple Development";
50135013
CODE_SIGN_STYLE = Automatic;
5014-
CURRENT_PROJECT_VERSION = 1271;
5014+
CURRENT_PROJECT_VERSION = 1274;
50155015
DEVELOPMENT_TEAM = 6335M7T29D;
50165016
ENABLE_BITCODE = YES;
50175017
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -5107,7 +5107,7 @@
51075107
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
51085108
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
51095109
CODE_SIGN_STYLE = Automatic;
5110-
CURRENT_PROJECT_VERSION = 1271;
5110+
CURRENT_PROJECT_VERSION = 1274;
51115111
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
51125112
DEVELOPMENT_TEAM = 6335M7T29D;
51135113
ENABLE_BITCODE = YES;
@@ -5199,7 +5199,7 @@
51995199
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
52005200
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
52015201
CODE_SIGN_STYLE = Automatic;
5202-
CURRENT_PROJECT_VERSION = 1271;
5202+
CURRENT_PROJECT_VERSION = 1274;
52035203
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
52045204
ENABLE_BITCODE = YES;
52055205
ENABLE_PREVIEWS = YES;
@@ -5315,7 +5315,7 @@
53155315
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
53165316
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
53175317
CODE_SIGN_STYLE = Automatic;
5318-
CURRENT_PROJECT_VERSION = 1271;
5318+
CURRENT_PROJECT_VERSION = 1274;
53195319
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
53205320
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
53215321
ENABLE_BITCODE = YES;
@@ -5425,7 +5425,7 @@
54255425
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
54265426
CODE_SIGN_ENTITLEMENTS = QZWidgetExtension.entitlements;
54275427
CODE_SIGN_STYLE = Automatic;
5428-
CURRENT_PROJECT_VERSION = 1271;
5428+
CURRENT_PROJECT_VERSION = 1274;
54295429
DEVELOPMENT_TEAM = 6335M7T29D;
54305430
ENABLE_STRICT_OBJC_MSGSEND = YES;
54315431
ENABLE_TESTABILITY = YES;
@@ -5516,7 +5516,7 @@
55165516
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
55175517
CODE_SIGN_ENTITLEMENTS = QZWidgetExtension.entitlements;
55185518
CODE_SIGN_STYLE = Automatic;
5519-
CURRENT_PROJECT_VERSION = 1271;
5519+
CURRENT_PROJECT_VERSION = 1274;
55205520
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
55215521
DEVELOPMENT_TEAM = 6335M7T29D;
55225522
ENABLE_NS_ASSERTIONS = NO;

src/devices/bluetooth.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
968968
}
969969
this->signalBluetoothDeviceConnected(nordictrackifitadbRower);
970970
} else if (((csc_as_bike && b.name().startsWith(cscName)) ||
971-
b.name().toUpper().startsWith(QStringLiteral("JOROTO-BK-"))) &&
971+
b.name().toUpper().startsWith(QStringLiteral("JOROTO-BK-")) ||
972+
(b.name().toUpper().startsWith(QStringLiteral("BGYM")) && b.name().length() == 8)) &&
972973
!cscBike && filter) {
973974
this->setLastBluetoothDevice(b);
974975
this->stopDiscovery();
@@ -1568,7 +1569,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
15681569
(b.name().toUpper().startsWith(QStringLiteral("TC-"))) || // FTMS (Focus Fitness Jet 7 iPlus)
15691570
b.name().toUpper().startsWith(QStringLiteral("TM XP_")) || // FTMS
15701571
b.name().toUpper().startsWith(QStringLiteral("THERUN T15")) || // FTMS
1571-
b.name().toUpper().startsWith(QStringLiteral("BODYCRAFT_")) // Bodycraft T850 Treadmill
1572+
b.name().toUpper().startsWith(QStringLiteral("BODYCRAFT_")) || // Bodycraft T850 Treadmill
1573+
(b.name().toUpper().startsWith(QStringLiteral("WT")) && b.name().length() == 5 && b.name().midRef(2).toInt() > 0) // WT treadmill (e.g. WT703)
15721574
) &&
15731575
!horizonTreadmill && filter) {
15741576
this->setLastBluetoothDevice(b);

src/devices/ftmsbike/ftmsbike.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1477,6 +1477,29 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact
14771477
if (gattWriteCharControlPointId.isValid()) {
14781478
qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' ');
14791479

1480+
// D500V2 workaround: track request control (0x00) and start simulation (0x07) commands
1481+
// If we receive simulation params (0x11) without start simulation, inject it first
1482+
if (D500V2 && b.length() > 0) {
1483+
uint8_t commandCode = (uint8_t)b.at(0);
1484+
1485+
if (commandCode == FTMS_REQUEST_CONTROL) {
1486+
// Command 0x00: Request Control - expect start simulation next
1487+
awaiting_start_simulation_after_request_control = true;
1488+
qDebug() << "D500V2 workaround: received REQUEST_CONTROL (0x00), now awaiting START_RESUME (0x07)";
1489+
} else if (commandCode == FTMS_START_RESUME) {
1490+
// Command 0x07: Start Resume - no longer awaiting
1491+
awaiting_start_simulation_after_request_control = false;
1492+
qDebug() << "D500V2 workaround: received START_RESUME (0x07), ready for simulation params";
1493+
} else if (commandCode == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && D500V2 && awaiting_start_simulation_after_request_control) {
1494+
// Command 0x11: Set Simulation Params - but we're still awaiting start simulation
1495+
// For D500V2, inject the start simulation command (0x07) first
1496+
qDebug() << "D500V2 workaround: received SET_INDOOR_BIKE_SIMULATION_PARAMS (0x11) without START_RESUME, injecting 0x07 first";
1497+
uint8_t startSimulation[] = {FTMS_START_RESUME};
1498+
writeCharacteristic(startSimulation, sizeof(startSimulation), "injectWrite [D500V2 workaround: start simulation 0x07]", false, true);
1499+
awaiting_start_simulation_after_request_control = false;
1500+
}
1501+
}
1502+
14801503
// handling gears
14811504
if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS && (zwiftPlayService == nullptr || !gears_zwift_ratio)) {
14821505
double min_inclination = settings.value(QZSettings::min_inclination, QZSettings::default_min_inclination).toDouble();
@@ -1684,6 +1707,9 @@ void ftmsbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
16841707
ergModeSupported = false;
16851708
max_resistance = 32;
16861709
DOMYOS = true;
1710+
} else if (bluetoothDevice.name().toUpper().startsWith("D500V2")) {
1711+
qDebug() << QStringLiteral("D500V2 found - enabling workaround for start simulation command");
1712+
D500V2 = true;
16871713
} else if ((bluetoothDevice.name().toUpper().startsWith("3G Cardio RB"))) {
16881714
qDebug() << QStringLiteral("_3G_Cardio_RB found");
16891715
_3G_Cardio_RB = true;

src/devices/ftmsbike/ftmsbike.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,13 @@ class ftmsbike : public bike {
135135
bool resistance_received = false;
136136
inclinationResistanceTable _inclinationResistanceTable;
137137

138+
// D500V2 workaround: track if we're awaiting start simulation command after request control
139+
bool awaiting_start_simulation_after_request_control = false;
140+
138141
bool DU30_bike = false;
139142
bool ICSE = false;
140143
bool DOMYOS = false;
144+
bool D500V2 = false;
141145
bool _3G_Cardio_RB = false;
142146
bool SCH_190U = false;
143147
bool SCH_290R = false;

src/devices/horizontreadmill/horizontreadmill.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,7 +1261,7 @@ void horizontreadmill::forceSpeed(double requestSpeed) {
12611261
if(BOWFLEX_T9) {
12621262
requestSpeed *= miles_conversion; // this treadmill wants the speed in miles, at least seems so!!
12631263
}
1264-
if(TM4800 || TM6500 || T3G_ELITE) {
1264+
if(TM4800 || TM6500 || T3G_ELITE || WT_TREADMILL) {
12651265
bool miles = settings.value(QZSettings::miles_unit, QZSettings::default_miles_unit).toBool();
12661266
if(miles) {
12671267
requestSpeed *= miles_conversion; // these treadmills want the speed in miles when miles_unit is enabled
@@ -1918,7 +1918,10 @@ void horizontreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
19181918
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
19191919

19201920
if (Flags.inclination) {
1921-
if(!tunturi_t60_treadmill && !ICONCEPT_FTMS_treadmill && !T01)
1921+
if(domyos_treadmill_ts100) {
1922+
// Domyos TS100 has a fixed 15° inclination
1923+
Inclination = 15;
1924+
} else if(!tunturi_t60_treadmill && !ICONCEPT_FTMS_treadmill && !T01)
19221925
parseInclination(treadmillInclinationOverride((double)(
19231926
(int16_t)(
19241927
((int16_t)(int8_t)newValue.at(index + 1) << 8) |
@@ -1965,6 +1968,10 @@ void horizontreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
19651968
}
19661969
index += 4; // the ramo value is useless
19671970
emit debug(QStringLiteral("Current Inclination: ") + QString::number(Inclination.value()));
1971+
} else if(domyos_treadmill_ts100) {
1972+
// Domyos TS100 has a fixed 15° inclination (no inclination flag in 2ACD)
1973+
Inclination = 15;
1974+
emit debug(QStringLiteral("Current Inclination (TS100 fixed): ") + QString::number(Inclination.value()));
19681975
}
19691976

19701977
if (Flags.elevation) {
@@ -2656,6 +2663,10 @@ void horizontreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) {
26562663
} else if ((device.name().toUpper().startsWith("DOMYOS"))) {
26572664
qDebug() << QStringLiteral("DOMYOS found");
26582665
DOMYOS = true;
2666+
domyos_treadmill_ts100 = settings.value(QZSettings::domyos_treadmill_ts100, QZSettings::default_domyos_treadmill_ts100).toBool();
2667+
if(domyos_treadmill_ts100) {
2668+
qDebug() << QStringLiteral("Domyos TS100 mode ON - Fixed 15° inclination");
2669+
}
26592670
} else if ((device.name().toUpper().startsWith(QStringLiteral("BFX_T9_")))) {
26602671
qDebug() << QStringLiteral("BOWFLEX T9 found");
26612672
BOWFLEX_T9 = true;
@@ -2687,6 +2698,9 @@ void horizontreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) {
26872698
qDebug() << QStringLiteral("TM6500 treadmill found");
26882699
TM6500 = true;
26892700
minInclination = -3.0;
2701+
} else if (device.name().toUpper().startsWith(QStringLiteral("WT")) && device.name().length() == 5) {
2702+
qDebug() << QStringLiteral("WT treadmill found");
2703+
WT_TREADMILL = true;
26902704
}
26912705

26922706
if (device.name().toUpper().startsWith(QStringLiteral("TRX3500"))) {

src/devices/horizontreadmill/horizontreadmill.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class horizontreadmill : public treadmill {
106106
bool ICONCEPT_FTMS_treadmill = false;
107107
bool iconcept_ftms_treadmill_inclination_table = false;
108108
bool DOMYOS = false;
109+
bool domyos_treadmill_ts100 = false;
109110
bool SW_TREADMILL = false;
110111
bool BOWFLEX_T9 = false;
111112
bool YPOO_MINI_PRO = false;
@@ -118,6 +119,7 @@ class horizontreadmill : public treadmill {
118119
bool T01 = false;
119120
bool TM4800 = false;
120121
bool TM6500 = false;
122+
bool WT_TREADMILL = false;
121123

122124
void testProfileCRC();
123125
void updateProfileCRC();

src/devices/strydrunpowersensor/strydrunpowersensor.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,16 @@ void strydrunpowersensor::serviceScanDone(void) {
654654
emit debug(QStringLiteral("serviceScanDone"));
655655

656656
auto services_list = m_control->services();
657+
bool isZwiftPod = bluetoothDevice.name().contains(QStringLiteral("Zwift RunPod"), Qt::CaseInsensitive);
658+
657659
for (const QBluetoothUuid &s : qAsConst(services_list)) {
660+
// For Zwift RunPod, skip both fff0 and ffc0 services that cause discovery issues
661+
if (isZwiftPod && (s.toString() == QStringLiteral("{0000fff0-0000-1000-8000-00805f9b34fb}") ||
662+
s.toString() == QStringLiteral("{f000ffc0-0451-4000-b000-000000000000}"))) {
663+
qDebug() << QStringLiteral("Skipping problematic services for Zwift RunPod:") << s.toString();
664+
continue;
665+
}
666+
658667
gattCommunicationChannelService.append(m_control->createServiceObject(s));
659668
connect(gattCommunicationChannelService.constLast(), &QLowEnergyService::stateChanged, this,
660669
&strydrunpowersensor::stateChanged);

src/homeform.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ class homeform : public QObject {
203203
Q_PROPERTY(QString previewWorkoutDescription READ previewWorkoutDescription NOTIFY previewWorkoutDescriptionChanged)
204204
Q_PROPERTY(QString previewWorkoutTags READ previewWorkoutTags NOTIFY previewWorkoutTagsChanged)
205205
Q_PROPERTY(bool miles_unit READ miles_unit)
206+
Q_PROPERTY(bool iPadMultiWindowMode READ iPadMultiWindowMode)
206207

207208
Q_PROPERTY(bool currentCoordinateValid READ currentCoordinateValid)
208209
Q_PROPERTY(bool trainProgramLoadedWithVideo READ trainProgramLoadedWithVideo)
@@ -705,6 +706,18 @@ class homeform : public QObject {
705706
return settings.value(QZSettings::miles_unit, QZSettings::default_miles_unit).toBool();
706707
}
707708

709+
bool iPadMultiWindowMode() {
710+
#ifdef Q_OS_IOS
711+
#ifndef IO_UNDER_QT
712+
return lockscreen::isInMultiWindowMode();
713+
#else
714+
return false;
715+
#endif
716+
#else
717+
return false;
718+
#endif
719+
}
720+
708721
bool currentCoordinateValid() {
709722
if (bluetoothManager && bluetoothManager->device()) {
710723
return bluetoothManager->device()->currentCordinate().isValid();

src/ios/lockscreen.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class lockscreen {
111111
static void set_action_profile(const char* profile);
112112
static const char* get_action_profile();
113113

114+
// multi-window detection for iPadOS
115+
static bool isInMultiWindowMode();
114116
};
115117

116118
#endif // LOCKSCREEN_H

src/ios/lockscreen.mm

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -616,13 +616,43 @@
616616

617617
void lockscreen::zwiftClickRemote_WriteCharacteristic(unsigned char* qdata, unsigned char length, void* deviceClass) {
618618
if (ios_zwiftClickRemotes == nil) return;
619-
619+
620620
// Get the specific remote for this device
621621
NSValue *key = [NSValue valueWithPointer:deviceClass];
622622
ios_zwiftclickremote *remote = [ios_zwiftClickRemotes objectForKey:key];
623-
623+
624624
if(remote) {
625625
[remote writeCharacteristic:qdata length:length];
626626
}
627627
}
628+
629+
bool lockscreen::isInMultiWindowMode() {
630+
// Check if we're on iPad and in multi-window mode (Stage Manager, Split View, Slide Over)
631+
if (UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPad) {
632+
return false;
633+
}
634+
635+
if (@available(iOS 13.0, *)) {
636+
// Get the foreground active scene
637+
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
638+
if (scene.activationState == UISceneActivationStateForegroundActive &&
639+
[scene isKindOfClass:[UIWindowScene class]]) {
640+
UIWindowScene *windowScene = (UIWindowScene *)scene;
641+
642+
// Get the window bounds and screen bounds
643+
CGRect windowBounds = windowScene.coordinateSpace.bounds;
644+
CGRect screenBounds = windowScene.screen.bounds;
645+
646+
// If window is smaller than screen in either dimension, we're in multi-window mode
647+
// Add a small tolerance for floating point comparison
648+
if (windowBounds.size.width < screenBounds.size.width - 1 ||
649+
windowBounds.size.height < screenBounds.size.height - 1) {
650+
return true;
651+
}
652+
}
653+
}
654+
}
655+
656+
return false;
657+
}
628658
#endif

0 commit comments

Comments
 (0)