mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
4 Commits
master
...
JRNY-virtu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06a179288b | ||
|
|
d81bbad9a0 | ||
|
|
c914d147f0 | ||
|
|
0c30ac0a74 |
@@ -974,9 +974,10 @@ const QString QZSettings::tile_auto_virtual_shifting_climb_enabled = QStringLite
|
||||
const QString QZSettings::tile_auto_virtual_shifting_climb_order = QStringLiteral("tile_auto_virtual_shifting_climb_order");
|
||||
const QString QZSettings::tile_auto_virtual_shifting_sprint_enabled = QStringLiteral("tile_auto_virtual_shifting_sprint_enabled");
|
||||
const QString QZSettings::tile_auto_virtual_shifting_sprint_order = QStringLiteral("tile_auto_virtual_shifting_sprint_order");
|
||||
const QString QZSettings::jrny_virtual_treadmill = QStringLiteral("jrny_virtual_treadmill");
|
||||
|
||||
|
||||
const uint32_t allSettingsCount = 798;
|
||||
const uint32_t allSettingsCount = 800;
|
||||
|
||||
QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles},
|
||||
@@ -1795,6 +1796,7 @@ QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::tile_auto_virtual_shifting_climb_order, QZSettings::default_tile_auto_virtual_shifting_climb_order},
|
||||
{QZSettings::tile_auto_virtual_shifting_sprint_enabled, QZSettings::default_tile_auto_virtual_shifting_sprint_enabled},
|
||||
{QZSettings::tile_auto_virtual_shifting_sprint_order, QZSettings::default_tile_auto_virtual_shifting_sprint_order},
|
||||
{QZSettings::jrny_virtual_treadmill, QZSettings::default_jrny_virtual_treadmill},
|
||||
{QZSettings::rogue_echo_bike, QZSettings::default_rogue_echo_bike},
|
||||
};
|
||||
|
||||
|
||||
@@ -2660,6 +2660,12 @@ class QZSettings {
|
||||
static const QString tile_auto_virtual_shifting_sprint_order;
|
||||
static constexpr int default_tile_auto_virtual_shifting_sprint_order = 57;
|
||||
|
||||
/**
|
||||
* @brief Enable JRNY virtual treadmill (Android only)
|
||||
*/
|
||||
static const QString jrny_virtual_treadmill;
|
||||
static constexpr bool default_jrny_virtual_treadmill = false;
|
||||
|
||||
/**
|
||||
* @brief Write the QSettings values using the constants from this namespace.
|
||||
* @param showDefaults Optionally indicates if the default should be shown with the key.
|
||||
|
||||
@@ -1198,6 +1198,7 @@ import Qt.labs.platform 1.1
|
||||
property int tile_auto_virtual_shifting_sprint_order: 57
|
||||
property string proform_rower_ip: ""
|
||||
property string ftms_elliptical: "Disabled"
|
||||
property bool jrny_virtual_treadmill: false
|
||||
}
|
||||
|
||||
|
||||
@@ -11838,6 +11839,34 @@ import Qt.labs.platform 1.1
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
IndicatorOnlySwitch {
|
||||
id: jrnyVirtualTreadmillDelegate
|
||||
text: qsTr("JRNY Virtual Treadmill")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
clip: false
|
||||
checked: settings.jrny_virtual_treadmill
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
onClicked: { settings.jrny_virtual_treadmill = checked; window.settings_restart_to_apply = true; }
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Enable JRNY virtual treadmill for Android. Advertises as JOHNSON T202-5 device. Default is off.")
|
||||
font.bold: true
|
||||
font.italic: true
|
||||
font.pixelSize: Qt.application.font.pixelSize - 2
|
||||
textFormat: Text.PlainText
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
IndicatorOnlySwitch {
|
||||
id: virtualBikeForceResistanceDelegate
|
||||
text: qsTr("Zwift Force Resistance")
|
||||
@@ -12018,7 +12047,7 @@ import Qt.labs.platform 1.1
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
|
||||
onClicked: { settings.dircon_server_base_port = dirconServerPortTextField.text; toast.show("Setting saved!"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
#include "qzsettings.h"
|
||||
#include <QThread>
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
@@ -15,6 +16,20 @@ using namespace std::chrono_literals;
|
||||
virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) {
|
||||
QSettings settings;
|
||||
treadMill = t;
|
||||
|
||||
bool jrnyVirtualTreadmill = settings.value(QZSettings::jrny_virtual_treadmill, QZSettings::default_jrny_virtual_treadmill).toBool();
|
||||
|
||||
// JRNY Virtual Treadmill is only supported on Android
|
||||
if (jrnyVirtualTreadmill) {
|
||||
#ifndef Q_OS_ANDROID
|
||||
qDebug() << "JRNY Virtual Treadmill is only supported on Android";
|
||||
jrnyVirtualTreadmill = false; // Disable on non-Android platforms
|
||||
#else
|
||||
// Force heart rate service outside FTMS for JRNY compatibility
|
||||
noHeartService = true;
|
||||
qDebug() << "JRNY Virtual Treadmill: forcing heart rate service outside FTMS";
|
||||
#endif
|
||||
}
|
||||
|
||||
int bikeResistanceOffset =
|
||||
settings.value(QZSettings::bike_resistance_offset, QZSettings::default_bike_resistance_offset).toInt();
|
||||
@@ -57,11 +72,21 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) {
|
||||
//! [Advertising Data]
|
||||
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
|
||||
advertisingData.setIncludePowerLevel(true);
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
advertisingData.setLocalName(QStringLiteral("KICKR RUN"));
|
||||
#else
|
||||
advertisingData.setLocalName(QStringLiteral("DomyosBridge"));
|
||||
|
||||
if (jrnyVirtualTreadmill) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
advertisingData.setLocalName(QStringLiteral("T202-5"));
|
||||
#else
|
||||
qDebug() << "JRNY Virtual Treadmill is only supported on Android";
|
||||
return; // Exit early on non-Android platforms
|
||||
#endif
|
||||
} else {
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
advertisingData.setLocalName(QStringLiteral("KICKR RUN"));
|
||||
#else
|
||||
advertisingData.setLocalName(QStringLiteral("DomyosBridge"));
|
||||
#endif
|
||||
}
|
||||
QList<QBluetoothUuid> services;
|
||||
|
||||
// Add Wahoo Run Service UUID
|
||||
@@ -87,20 +112,68 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) {
|
||||
//! [Advertising Data]
|
||||
|
||||
// Add Device Information Service
|
||||
|
||||
QLowEnergyCharacteristicData manufacturerNameChar;
|
||||
manufacturerNameChar.setUuid(QBluetoothUuid::CharacteristicType::ManufacturerNameString);
|
||||
manufacturerNameChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
manufacturerNameChar.setValue(QByteArray("Wahoo Fitness")); // Changed to Wahoo Fitness
|
||||
if (jrnyVirtualTreadmill) {
|
||||
manufacturerNameChar.setValue(QByteArray("JOHNSON"));
|
||||
} else {
|
||||
manufacturerNameChar.setValue(QByteArray("Wahoo Fitness")); // Changed to Wahoo Fitness
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData modelNumberChar;
|
||||
modelNumberChar.setUuid(QBluetoothUuid::CharacteristicType::ModelNumberString);
|
||||
modelNumberChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
if (jrnyVirtualTreadmill) {
|
||||
modelNumberChar.setValue(QByteArray("T202-5"));
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData firmwareRevChar;
|
||||
firmwareRevChar.setUuid(QBluetoothUuid::CharacteristicType::FirmwareRevisionString);
|
||||
firmwareRevChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
firmwareRevChar.setValue(QByteArray("1.0.11"));
|
||||
if (jrnyVirtualTreadmill) {
|
||||
firmwareRevChar.setValue(QByteArray("V100.0.0"));
|
||||
} else {
|
||||
firmwareRevChar.setValue(QByteArray("1.0.11"));
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData softwareRevChar;
|
||||
softwareRevChar.setUuid(QBluetoothUuid::CharacteristicType::SoftwareRevisionString);
|
||||
softwareRevChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
if (jrnyVirtualTreadmill) {
|
||||
softwareRevChar.setValue(QByteArray("V100.0.1"));
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData hardwareRevChar;
|
||||
hardwareRevChar.setUuid(QBluetoothUuid::CharacteristicType::HardwareRevisionString);
|
||||
hardwareRevChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
hardwareRevChar.setValue(QByteArray("1"));
|
||||
if (jrnyVirtualTreadmill) {
|
||||
hardwareRevChar.setValue(QByteArray("WLT8"));
|
||||
} else {
|
||||
hardwareRevChar.setValue(QByteArray("1"));
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData serialNumberChar;
|
||||
serialNumberChar.setUuid(QBluetoothUuid::CharacteristicType::SerialNumberString);
|
||||
serialNumberChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
if (jrnyVirtualTreadmill) {
|
||||
serialNumberChar.setValue(QByteArray("V100.0.2"));
|
||||
}
|
||||
|
||||
QLowEnergyCharacteristicData systemIdChar;
|
||||
systemIdChar.setUuid(QBluetoothUuid::CharacteristicType::SystemID);
|
||||
systemIdChar.setProperties(QLowEnergyCharacteristic::Read);
|
||||
if (jrnyVirtualTreadmill) {
|
||||
QByteArray systemIdData;
|
||||
systemIdData.append(char(0xFA));
|
||||
systemIdData.append(char(0xE4));
|
||||
systemIdData.append(char(0xE3));
|
||||
systemIdData.append(char(0x4B));
|
||||
systemIdData.append(char(0x3D));
|
||||
systemIdData.append(char(0x09));
|
||||
systemIdChar.setValue(systemIdData);
|
||||
}
|
||||
|
||||
// Create Device Information Service
|
||||
serviceDataDIS.setType(QLowEnergyServiceData::ServiceTypePrimary);
|
||||
@@ -108,32 +181,41 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) {
|
||||
serviceDataDIS.addCharacteristic(manufacturerNameChar);
|
||||
serviceDataDIS.addCharacteristic(firmwareRevChar);
|
||||
serviceDataDIS.addCharacteristic(hardwareRevChar);
|
||||
|
||||
if (jrnyVirtualTreadmill) {
|
||||
serviceDataDIS.addCharacteristic(modelNumberChar);
|
||||
serviceDataDIS.addCharacteristic(softwareRevChar);
|
||||
serviceDataDIS.addCharacteristic(serialNumberChar);
|
||||
serviceDataDIS.addCharacteristic(systemIdChar);
|
||||
}
|
||||
|
||||
// Create Wahoo Run Service
|
||||
serviceDataWahoo.setType(QLowEnergyServiceData::ServiceTypePrimary);
|
||||
serviceDataWahoo.setUuid(QBluetoothUuid(QString("A026EE0E-0A7D-4AB3-97FA-F1500F9FEB8B")));
|
||||
// Create Wahoo Run Service (only when not in JRNY mode)
|
||||
if (!jrnyVirtualTreadmill) {
|
||||
serviceDataWahoo.setType(QLowEnergyServiceData::ServiceTypePrimary);
|
||||
serviceDataWahoo.setUuid(QBluetoothUuid(QString("A026EE0E-0A7D-4AB3-97FA-F1500F9FEB8B")));
|
||||
|
||||
// Add Wahoo Run Notify Characteristic
|
||||
QLowEnergyCharacteristicData wahooNotifyChar;
|
||||
wahooNotifyChar.setUuid(QBluetoothUuid(QString("A026E03D-0A7D-4AB3-97FA-F1500F9FEB8B")));
|
||||
wahooNotifyChar.setProperties(QLowEnergyCharacteristic::Read |
|
||||
QLowEnergyCharacteristic::WriteNoResponse |
|
||||
QLowEnergyCharacteristic::Notify);
|
||||
const QLowEnergyDescriptorData wahooNotifyConfig(QBluetoothUuid::ClientCharacteristicConfiguration,
|
||||
QByteArray(2, 0));
|
||||
wahooNotifyChar.addDescriptor(wahooNotifyConfig);
|
||||
// Add Wahoo Run Notify Characteristic
|
||||
QLowEnergyCharacteristicData wahooNotifyChar;
|
||||
wahooNotifyChar.setUuid(QBluetoothUuid(QString("A026E03D-0A7D-4AB3-97FA-F1500F9FEB8B")));
|
||||
wahooNotifyChar.setProperties(QLowEnergyCharacteristic::Read |
|
||||
QLowEnergyCharacteristic::WriteNoResponse |
|
||||
QLowEnergyCharacteristic::Notify);
|
||||
const QLowEnergyDescriptorData wahooNotifyConfig(QBluetoothUuid::ClientCharacteristicConfiguration,
|
||||
QByteArray(2, 0));
|
||||
wahooNotifyChar.addDescriptor(wahooNotifyConfig);
|
||||
|
||||
// Add Wahoo Run Write Characteristic
|
||||
QLowEnergyCharacteristicData wahooWriteChar;
|
||||
wahooWriteChar.setUuid(QBluetoothUuid(QString("A026E03E-0A7D-4AB3-97FA-F1500F9FEB8B")));
|
||||
wahooWriteChar.setProperties(QLowEnergyCharacteristic::WriteNoResponse |
|
||||
QLowEnergyCharacteristic::Indicate);
|
||||
const QLowEnergyDescriptorData wahooWriteConfig(QBluetoothUuid::ClientCharacteristicConfiguration,
|
||||
QByteArray(2, 0));
|
||||
wahooWriteChar.addDescriptor(wahooWriteConfig);
|
||||
// Add Wahoo Run Write Characteristic
|
||||
QLowEnergyCharacteristicData wahooWriteChar;
|
||||
wahooWriteChar.setUuid(QBluetoothUuid(QString("A026E03E-0A7D-4AB3-97FA-F1500F9FEB8B")));
|
||||
wahooWriteChar.setProperties(QLowEnergyCharacteristic::WriteNoResponse |
|
||||
QLowEnergyCharacteristic::Indicate);
|
||||
const QLowEnergyDescriptorData wahooWriteConfig(QBluetoothUuid::ClientCharacteristicConfiguration,
|
||||
QByteArray(2, 0));
|
||||
wahooWriteChar.addDescriptor(wahooWriteConfig);
|
||||
|
||||
serviceDataWahoo.addCharacteristic(wahooNotifyChar);
|
||||
serviceDataWahoo.addCharacteristic(wahooWriteChar);
|
||||
serviceDataWahoo.addCharacteristic(wahooNotifyChar);
|
||||
serviceDataWahoo.addCharacteristic(wahooWriteChar);
|
||||
}
|
||||
|
||||
//! [Service Data]
|
||||
if (ftmsServiceEnable()) {
|
||||
@@ -352,8 +434,10 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) {
|
||||
serviceDIS = leController->addService(serviceDataDIS);
|
||||
QThread::msleep(100);
|
||||
|
||||
serviceWahoo = leController->addService(serviceDataWahoo);
|
||||
QThread::msleep(100);
|
||||
if (!jrnyVirtualTreadmill) {
|
||||
serviceWahoo = leController->addService(serviceDataWahoo);
|
||||
QThread::msleep(100);
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
genericAccessServer = leController->addService(genericAccessServerData);
|
||||
@@ -368,7 +452,7 @@ virtualtreadmill::virtualtreadmill(bluetoothdevice *t, bool noHeartService) {
|
||||
QObject::connect(serviceFTMS, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualtreadmill::characteristicChanged);
|
||||
|
||||
if (serviceWahoo)
|
||||
if (!jrnyVirtualTreadmill && serviceWahoo)
|
||||
QObject::connect(serviceWahoo, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualtreadmill::wahooCharacteristicChanged);
|
||||
|
||||
@@ -467,6 +551,7 @@ void virtualtreadmill::reconnect() {
|
||||
QSettings settings;
|
||||
bool bluetooth_relaxed =
|
||||
settings.value(QZSettings::bluetooth_relaxed, QZSettings::default_bluetooth_relaxed).toBool();
|
||||
bool jrnyVirtualTreadmill = settings.value(QZSettings::jrny_virtual_treadmill, QZSettings::default_jrny_virtual_treadmill).toBool();
|
||||
|
||||
if (bluetooth_relaxed) {
|
||||
return;
|
||||
@@ -485,8 +570,10 @@ void virtualtreadmill::reconnect() {
|
||||
serviceDIS = leController->addService(serviceDataDIS);
|
||||
QThread::msleep(100);
|
||||
|
||||
serviceWahoo = leController->addService(serviceDataWahoo);
|
||||
QThread::msleep(100);
|
||||
if (!jrnyVirtualTreadmill) {
|
||||
serviceWahoo = leController->addService(serviceDataWahoo);
|
||||
QThread::msleep(100);
|
||||
}
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
genericAccessServer = leController->addService(genericAccessServerData);
|
||||
@@ -500,7 +587,7 @@ void virtualtreadmill::reconnect() {
|
||||
QLowEnergyAdvertisingParameters pars;
|
||||
pars.setInterval(100, 100);
|
||||
|
||||
if (serviceFTMS || serviceRSC || serviceWahoo) {
|
||||
if (serviceFTMS || serviceRSC || (!jrnyVirtualTreadmill && serviceWahoo) || (jrnyVirtualTreadmill && serviceDIS)) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
QAndroidJniObject::callStaticMethod<void>("org/cagnulen/qdomyoszwift/BleAdvertiser",
|
||||
"startAdvertisingTreadmill",
|
||||
|
||||
Reference in New Issue
Block a user