mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
60 Commits
virtualgea
...
build-906
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81150953f1 | ||
|
|
c5170b5b42 | ||
|
|
52ca1787ba | ||
|
|
e76ad7a6e8 | ||
|
|
2f1612205b | ||
|
|
b0c1054ed8 | ||
|
|
993a00a57b | ||
|
|
e6fec94f55 | ||
|
|
891c2fb4f7 | ||
|
|
f49fe67b5a | ||
|
|
727dde137f | ||
|
|
bebe505152 | ||
|
|
a0d60efab9 | ||
|
|
6eb2463259 | ||
|
|
7ed1b3f498 | ||
|
|
48880a4962 | ||
|
|
0c7ad157de | ||
|
|
2f4d80dda1 | ||
|
|
28e1bf2abf | ||
|
|
3ee47b9b22 | ||
|
|
be19850f31 | ||
|
|
2c12f7cd20 | ||
|
|
916a664706 | ||
|
|
cf38aab0af | ||
|
|
70ecbacd6a | ||
|
|
d4d3a9ceb3 | ||
|
|
e58c7c6888 | ||
|
|
614690aec3 | ||
|
|
ea0221d20d | ||
|
|
8920cf4981 | ||
|
|
a013c73ced | ||
|
|
3000b8e6d9 | ||
|
|
f8b2975558 | ||
|
|
ba27677cae | ||
|
|
b77a12b895 | ||
|
|
4a8ffa343e | ||
|
|
bb40f2475d | ||
|
|
2f554750a5 | ||
|
|
ea3ea7b570 | ||
|
|
a0e86b9270 | ||
|
|
ea4b93d96f | ||
|
|
6cefcdc011 | ||
|
|
eb6438f591 | ||
|
|
da047d5e5b | ||
|
|
a5c3ca388d | ||
|
|
5fb771b9f0 | ||
|
|
936bb56574 | ||
|
|
d6e9227360 | ||
|
|
6a6efebfcb | ||
|
|
1674ec85a1 | ||
|
|
71618d0a16 | ||
|
|
05666dea67 | ||
|
|
f2c3c0c63c | ||
|
|
e6a7210609 | ||
|
|
afd1953117 | ||
|
|
5a18a00295 | ||
|
|
d0acc202df | ||
|
|
97702e8ae2 | ||
|
|
ef017273d9 | ||
|
|
66dc8bbb6f |
@@ -1320,6 +1320,7 @@
|
||||
87A0770E29B641D500A368BF /* wahookickrheadwind.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wahookickrheadwind.h; path = ../src/devices/wahookickrheadwind/wahookickrheadwind.h; sourceTree = "<group>"; };
|
||||
87A0770F29B641D500A368BF /* wahookickrheadwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = wahookickrheadwind.cpp; path = ../src/devices/wahookickrheadwind/wahookickrheadwind.cpp; sourceTree = "<group>"; };
|
||||
87A0771129B6420200A368BF /* moc_wahookickrheadwind.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_wahookickrheadwind.cpp; sourceTree = "<group>"; };
|
||||
87A083062C73361C00567A4E /* characteristicnotifier2ad9.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = characteristicnotifier2ad9.h; path = ../src/characteristics/characteristicnotifier2ad9.h; sourceTree = "<group>"; };
|
||||
87A0C4B7262329A600121A76 /* npecablebike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = npecablebike.cpp; path = ../src/devices/npecablebike/npecablebike.cpp; sourceTree = "<group>"; };
|
||||
87A0C4B8262329A600121A76 /* cscbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cscbike.h; path = ../src/devices/cscbike/cscbike.h; sourceTree = "<group>"; };
|
||||
87A0C4B9262329A600121A76 /* cscbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cscbike.cpp; path = ../src/devices/cscbike/cscbike.cpp; sourceTree = "<group>"; };
|
||||
@@ -2078,6 +2079,7 @@
|
||||
2EB56BE3C2D93CDAB0C52E67 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
87A083062C73361C00567A4E /* characteristicnotifier2ad9.h */,
|
||||
8772B7F92CB5603A004AB8E9 /* deerruntreadmill.h */,
|
||||
8772B7F62CB55E98004AB8E9 /* deerruntreadmill.cpp */,
|
||||
8772B7F32CB55E80004AB8E9 /* moc_deerruntreadmill.cpp */,
|
||||
@@ -4066,7 +4068,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 905;
|
||||
CURRENT_PROJECT_VERSION = 906;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1";
|
||||
@@ -4257,7 +4259,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 905;
|
||||
CURRENT_PROJECT_VERSION = 906;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -4484,7 +4486,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 905;
|
||||
CURRENT_PROJECT_VERSION = 906;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -4580,7 +4582,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 905;
|
||||
CURRENT_PROJECT_VERSION = 906;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
@@ -4672,7 +4674,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 905;
|
||||
CURRENT_PROJECT_VERSION = 906;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -4786,7 +4788,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 905;
|
||||
CURRENT_PROJECT_VERSION = 906;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
#include "devices/bike.h"
|
||||
#include "qdebugfixup.h"
|
||||
#include "homeform.h"
|
||||
#include <QSettings>
|
||||
|
||||
bike::bike() { elapsed.setType(metric::METRIC_ELAPSED); }
|
||||
@@ -106,6 +107,9 @@ void bike::setGears(double gears) {
|
||||
return;
|
||||
}
|
||||
m_gears = gears;
|
||||
if(homeform::singleton()) {
|
||||
homeform::singleton()->updateGearsValue();
|
||||
}
|
||||
settings.setValue(QZSettings::gears_current_value, m_gears);
|
||||
if (lastRawRequestedResistanceValue != -1) {
|
||||
changeResistance(lastRawRequestedResistanceValue);
|
||||
|
||||
@@ -3906,6 +3906,15 @@ QString homeform::startIcon() {
|
||||
return QLatin1String("");
|
||||
}
|
||||
|
||||
void homeform::updateGearsValue() {
|
||||
QSettings settings;
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
if (settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble() == 1.0 || gears_zwift_ratio)
|
||||
this->gears->setValue(QString::number(((bike *)bluetoothManager->device())->gears()));
|
||||
else
|
||||
this->gears->setValue(QString::number(((bike *)bluetoothManager->device())->gears(), 'f', 1));
|
||||
}
|
||||
|
||||
QString homeform::signal() {
|
||||
if (!bluetoothManager) {
|
||||
return QStringLiteral("icons/icons/signal-1.png");
|
||||
@@ -4398,11 +4407,7 @@ void homeform::update() {
|
||||
this->target_power->setValue(
|
||||
QString::number(((bike *)bluetoothManager->device())->lastRequestedPower().value(), 'f', 0));
|
||||
this->resistance->setValue(QString::number(resistance, 'f', 0));
|
||||
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
|
||||
if (settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble() == 1.0 || gears_zwift_ratio)
|
||||
this->gears->setValue(QString::number(((bike *)bluetoothManager->device())->gears()));
|
||||
else
|
||||
this->gears->setValue(QString::number(((bike *)bluetoothManager->device())->gears(), 'f', 1));
|
||||
updateGearsValue();
|
||||
|
||||
this->resistance->setSecondLine(
|
||||
QStringLiteral("AVG: ") +
|
||||
|
||||
@@ -196,6 +196,7 @@ class homeform : public QObject {
|
||||
|
||||
public:
|
||||
static homeform *singleton() { return m_singleton; }
|
||||
bluetooth *bluetoothManager;
|
||||
|
||||
QByteArray currentPelotonImage();
|
||||
Q_INVOKABLE void save_screenshot() {
|
||||
@@ -603,6 +604,7 @@ class homeform : public QObject {
|
||||
QString getStravaAuthUrl() { return stravaAuthUrl; }
|
||||
bool stravaWebVisible() { return stravaAuthWebVisible; }
|
||||
trainprogram *trainingProgram() { return trainProgram; }
|
||||
void updateGearsValue();
|
||||
|
||||
DataObject *speed;
|
||||
DataObject *inclination;
|
||||
@@ -677,7 +679,6 @@ class homeform : public QObject {
|
||||
TemplateInfoSenderBuilder *innerTemplateManager = nullptr;
|
||||
QList<QObject *> dataList;
|
||||
QList<SessionLine> Session;
|
||||
bluetooth *bluetoothManager;
|
||||
QQmlApplicationEngine *engine;
|
||||
trainprogram *trainProgram = nullptr;
|
||||
trainprogram *previewTrainProgram = nullptr;
|
||||
|
||||
@@ -27,6 +27,12 @@ let PowerFeatureCharacteristicUUID = CBUUID(string: "0x2A65")
|
||||
let PowerSensorLocationCharacteristicUUID = CBUUID(string: "0x2A5D")
|
||||
let PowerMeasurementCharacteristicUUID = CBUUID(string: "0x2A63")
|
||||
|
||||
// Zwift Play
|
||||
let ZwiftPlayServiceUUID = CBUUID(string: "00000001-19ca-4651-86e5-fa29dcdd09d1")
|
||||
let ZwiftPlayWriteUUID = CBUUID(string: "00000003-19ca-4651-86e5-fa29dcdd09d1")
|
||||
let ZwiftPlayReadUUID = CBUUID(string: "00000002-19ca-4651-86e5-fa29dcdd09d1")
|
||||
let ZwiftPlayIndicateUUID = CBUUID(string:"00000004-19ca-4651-86e5-fa29dcdd09d1")
|
||||
|
||||
@objc public class virtualbike_ios_swift: NSObject {
|
||||
private var peripheralManager: BLEPeripheralManager!
|
||||
|
||||
|
||||
@@ -18,14 +18,14 @@ class lockscreen {
|
||||
void virtualbike_setHeartRate(unsigned char heartRate);
|
||||
void virtualbike_setCadence(unsigned short crankRevolutions, unsigned short lastCrankEventTime);
|
||||
|
||||
void virtualbike_zwift_ios(bool disable_hr, bool garmin_bluetooth_compatibility);
|
||||
void virtualbike_zwift_ios(bool disable_hr, bool garmin_bluetooth_compatibility, bool zwift_play_emulator);
|
||||
double virtualbike_getCurrentSlope();
|
||||
double virtualbike_getCurrentCRR();
|
||||
double virtualbike_getCurrentCW();
|
||||
double virtualbike_getPowerRequested();
|
||||
bool virtualbike_updateFTMS(unsigned short normalizeSpeed, unsigned char currentResistance,
|
||||
unsigned short currentCadence, unsigned short currentWatt,
|
||||
unsigned short CrankRevolutions, unsigned short LastCrankEventTime);
|
||||
unsigned short CrankRevolutions, unsigned short LastCrankEventTime, signed short Gears);
|
||||
int virtualbike_getLastFTMSMessage(unsigned char *message);
|
||||
|
||||
// virtualrower
|
||||
|
||||
@@ -101,9 +101,9 @@ void lockscreen::virtualbike_setCadence(unsigned short crankRevolutions, unsigne
|
||||
[_virtualbike updateCadenceWithCrankRevolutions:crankRevolutions LastCrankEventTime:lastCrankEventTime];
|
||||
}
|
||||
|
||||
void lockscreen::virtualbike_zwift_ios(bool disable_hr, bool garmin_bluetooth_compatibility)
|
||||
void lockscreen::virtualbike_zwift_ios(bool disable_hr, bool garmin_bluetooth_compatibility, bool zwift_play_emulator)
|
||||
{
|
||||
_virtualbike_zwift = [[virtualbike_zwift alloc] initWithDisable_hr:disable_hr garmin_bluetooth_compatibility:garmin_bluetooth_compatibility];
|
||||
_virtualbike_zwift = [[virtualbike_zwift alloc] initWithDisable_hr:disable_hr garmin_bluetooth_compatibility:garmin_bluetooth_compatibility zwift_play_emulator:zwift_play_emulator];
|
||||
}
|
||||
|
||||
void lockscreen::virtualrower_ios()
|
||||
@@ -147,10 +147,10 @@ double lockscreen::virtualbike_getPowerRequested()
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool lockscreen::virtualbike_updateFTMS(UInt16 normalizeSpeed, UInt8 currentResistance, UInt16 currentCadence, UInt16 currentWatt, UInt16 CrankRevolutions, UInt16 LastCrankEventTime)
|
||||
bool lockscreen::virtualbike_updateFTMS(UInt16 normalizeSpeed, UInt8 currentResistance, UInt16 currentCadence, UInt16 currentWatt, UInt16 CrankRevolutions, UInt16 LastCrankEventTime, signed short Gears)
|
||||
{
|
||||
if(_virtualbike_zwift != nil)
|
||||
return [_virtualbike_zwift updateFTMSWithNormalizeSpeed:normalizeSpeed currentCadence:currentCadence currentResistance:currentResistance currentWatt:currentWatt CrankRevolutions:CrankRevolutions LastCrankEventTime:LastCrankEventTime];
|
||||
return [_virtualbike_zwift updateFTMSWithNormalizeSpeed:normalizeSpeed currentCadence:currentCadence currentResistance:currentResistance currentWatt:currentWatt CrankRevolutions:CrankRevolutions LastCrankEventTime:LastCrankEventTime Gears:Gears];
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
|
||||
@interface swiftDebug : NSObject
|
||||
|
||||
- (void)qtDebug:(NSString *)inputString;;
|
||||
- (void)qtDebug:(NSString *)inputString;
|
||||
- (void)gearUp;
|
||||
- (void)gearDown;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
// Created by Roberto Viola on 14/12/23.
|
||||
//
|
||||
#import "swiftDebug.h"
|
||||
#import "homeform.h"
|
||||
#import "bike.h"
|
||||
#include <QDebug>
|
||||
|
||||
@implementation swiftDebug
|
||||
@@ -13,4 +15,12 @@
|
||||
qDebug() << inputString;
|
||||
}
|
||||
|
||||
- (void)gearUp {
|
||||
((bike*)(homeform::singleton()->bluetoothManager->device()))->gearUp();
|
||||
}
|
||||
|
||||
- (void)gearDown {
|
||||
((bike*)(homeform::singleton()->bluetoothManager->device()))->gearDown();
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -11,9 +11,9 @@ let TrainingStatusUuid = CBUUID(string: "0x2AD3");
|
||||
@objc public class virtualbike_zwift: NSObject {
|
||||
private var peripheralManager: BLEPeripheralManagerZwift!
|
||||
|
||||
@objc public init(disable_hr: Bool, garmin_bluetooth_compatibility: Bool) {
|
||||
@objc public init(disable_hr: Bool, garmin_bluetooth_compatibility: Bool, zwift_play_emulator: Bool) {
|
||||
super.init()
|
||||
peripheralManager = BLEPeripheralManagerZwift(disable_hr: disable_hr, garmin_bluetooth_compatibility: garmin_bluetooth_compatibility)
|
||||
peripheralManager = BLEPeripheralManagerZwift(disable_hr: disable_hr, garmin_bluetooth_compatibility: garmin_bluetooth_compatibility, zwift_play_emulator: zwift_play_emulator)
|
||||
}
|
||||
|
||||
@objc public func updateHeartRate(HeartRate: UInt8)
|
||||
@@ -41,7 +41,7 @@ let TrainingStatusUuid = CBUUID(string: "0x2AD3");
|
||||
return peripheralManager.PowerRequested;
|
||||
}
|
||||
|
||||
@objc public func updateFTMS(normalizeSpeed: UInt16, currentCadence: UInt16, currentResistance: UInt8, currentWatt: UInt16, CrankRevolutions: UInt16, LastCrankEventTime: UInt16) -> Bool
|
||||
@objc public func updateFTMS(normalizeSpeed: UInt16, currentCadence: UInt16, currentResistance: UInt8, currentWatt: UInt16, CrankRevolutions: UInt16, LastCrankEventTime: UInt16, Gears: Int16) -> Bool
|
||||
{
|
||||
peripheralManager.NormalizeSpeed = normalizeSpeed
|
||||
peripheralManager.CurrentCadence = currentCadence
|
||||
@@ -49,6 +49,7 @@ let TrainingStatusUuid = CBUUID(string: "0x2AD3");
|
||||
peripheralManager.CurrentWatt = currentWatt
|
||||
peripheralManager.lastCrankEventTime = LastCrankEventTime
|
||||
peripheralManager.crankRevolutions = CrankRevolutions
|
||||
peripheralManager.CurrentGears = Gears
|
||||
|
||||
return peripheralManager.connected;
|
||||
}
|
||||
@@ -62,6 +63,7 @@ let TrainingStatusUuid = CBUUID(string: "0x2AD3");
|
||||
|
||||
class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
private var garmin_bluetooth_compatibility: Bool = false
|
||||
private var zwift_play_emulator: Bool = false
|
||||
private var disable_hr: Bool = false
|
||||
private var peripheralManager: CBPeripheralManager!
|
||||
|
||||
@@ -84,6 +86,7 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
public var CurrentCadence: UInt16! = 0
|
||||
public var CurrentResistance: UInt8! = 0
|
||||
public var CurrentWatt: UInt16! = 0
|
||||
public var CurrentZwiftGear: UInt8! = 8
|
||||
|
||||
private var CSCService: CBMutableService!
|
||||
private var CSCFeatureCharacteristic: CBMutableCharacteristic!
|
||||
@@ -98,23 +101,33 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
private var PowerSensorLocationCharacteristic: CBMutableCharacteristic!
|
||||
private var PowerMeasurementCharacteristic: CBMutableCharacteristic!
|
||||
|
||||
private var ZwiftPlayService: CBMutableService!
|
||||
private var ZwiftPlayReadCharacteristic: CBMutableCharacteristic!
|
||||
private var ZwiftPlayWriteCharacteristic: CBMutableCharacteristic!
|
||||
private var ZwiftPlayIndicateCharacteristic: CBMutableCharacteristic!
|
||||
|
||||
|
||||
public var LastFTMSMessageReceived: Data?
|
||||
public var LastFTMSMessageReceivedAndPassed: Data?
|
||||
|
||||
public var serviceToggle: UInt8 = 0
|
||||
|
||||
public var CurrentGears: Int16 = 0
|
||||
|
||||
public var connected: Bool = false
|
||||
|
||||
private var notificationTimer: Timer! = nil
|
||||
|
||||
var updateQueue: [(characteristic: CBMutableCharacteristic, data: Data)] = []
|
||||
|
||||
let SwiftDebug = swiftDebug()
|
||||
//var delegate: BLEPeripheralManagerDelegate?
|
||||
|
||||
init(disable_hr: Bool, garmin_bluetooth_compatibility: Bool) {
|
||||
init(disable_hr: Bool, garmin_bluetooth_compatibility: Bool, zwift_play_emulator: Bool) {
|
||||
super.init()
|
||||
self.disable_hr = disable_hr
|
||||
self.garmin_bluetooth_compatibility = garmin_bluetooth_compatibility
|
||||
self.zwift_play_emulator = zwift_play_emulator
|
||||
|
||||
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
|
||||
}
|
||||
@@ -254,12 +267,54 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
PowerMeasurementCharacteristic]
|
||||
self.peripheralManager.add(PowerService)
|
||||
|
||||
|
||||
// ZwiftPlay
|
||||
if(self.zwift_play_emulator) {
|
||||
self.ZwiftPlayService = CBMutableService(type: ZwiftPlayServiceUUID, primary: true)
|
||||
|
||||
let ZwiftPlayReadProperties: CBCharacteristicProperties = [.notify, .read]
|
||||
let ZwiftPlayReadPermissions: CBAttributePermissions = [.readable]
|
||||
self.ZwiftPlayReadCharacteristic = CBMutableCharacteristic(type: ZwiftPlayReadUUID,
|
||||
properties: ZwiftPlayReadProperties,
|
||||
value: nil,
|
||||
permissions: ZwiftPlayReadPermissions)
|
||||
|
||||
let ZwiftPlayWriteProperties: CBCharacteristicProperties = [.write]
|
||||
let ZwiftPlayWritePermissions: CBAttributePermissions = [.writeable]
|
||||
self.ZwiftPlayWriteCharacteristic = CBMutableCharacteristic(type: ZwiftPlayWriteUUID,
|
||||
properties: ZwiftPlayWriteProperties,
|
||||
value: nil,
|
||||
permissions: ZwiftPlayWritePermissions)
|
||||
|
||||
let ZwiftPlayIndicateProperties: CBCharacteristicProperties = [.indicate]
|
||||
let ZwiftPlayIndicatePermissions: CBAttributePermissions = [.readable]
|
||||
self.ZwiftPlayIndicateCharacteristic = CBMutableCharacteristic(type: ZwiftPlayIndicateUUID,
|
||||
properties: ZwiftPlayIndicateProperties,
|
||||
value: nil,
|
||||
permissions: ZwiftPlayIndicatePermissions)
|
||||
|
||||
ZwiftPlayService.characteristics = [ZwiftPlayReadCharacteristic,
|
||||
ZwiftPlayWriteCharacteristic,
|
||||
ZwiftPlayIndicateCharacteristic]
|
||||
self.peripheralManager.add(ZwiftPlayService)
|
||||
}
|
||||
|
||||
default:
|
||||
print("Peripheral manager is down")
|
||||
}
|
||||
}
|
||||
|
||||
func sendUpdates() -> Bool {
|
||||
guard !updateQueue.isEmpty else { return false }
|
||||
|
||||
let update = updateQueue.removeFirst()
|
||||
let hexString = update.data.map { String(format: "%02x", $0) }.joined(separator: " ")
|
||||
let debugMessage = "virtualbike_zwift send: " + String(describing: update.characteristic) + " " + hexString
|
||||
SwiftDebug.qtDebug(debugMessage)
|
||||
peripheralManager.updateValue(update.data, for: update.characteristic, onSubscribedCentrals: nil)
|
||||
return true
|
||||
}
|
||||
|
||||
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
|
||||
if let uwError = error {
|
||||
print("Failed to add service with error: \(uwError.localizedDescription)")
|
||||
@@ -297,8 +352,13 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
}
|
||||
|
||||
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
|
||||
if requests.first!.characteristic == self.FitnessMachineControlPointCharacteristic {
|
||||
SwiftDebug.qtDebug("virtualbike_zwift didReceiveWrite: " + String(describing: requests.first!.value))
|
||||
if let value = requests.first?.value {
|
||||
let hexString = value.map { String(format: "%02x", $0) }.joined(separator: " ")
|
||||
let debugMessage = "virtualbike_zwift didReceiveWrite: " + String(describing: requests.first!.characteristic) + " " + hexString
|
||||
SwiftDebug.qtDebug(debugMessage)
|
||||
}
|
||||
|
||||
if requests.first!.characteristic == self.FitnessMachineControlPointCharacteristic {
|
||||
if(LastFTMSMessageReceived == nil || LastFTMSMessageReceived?.count == 0) {
|
||||
LastFTMSMessageReceived = requests.first!.value
|
||||
}
|
||||
@@ -323,10 +383,208 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
let responseData = Data(bytes: &response, count: 3)
|
||||
|
||||
self.peripheralManager.updateValue(responseData, for: self.FitnessMachineControlPointCharacteristic, onSubscribedCentrals: nil)
|
||||
} else if requests.first!.characteristic == ZwiftPlayWriteCharacteristic && zwift_play_emulator {
|
||||
let receivedData = requests.first!.value ?? Data()
|
||||
let expectedHexArray: [UInt8] = [0x52, 0x69, 0x64, 0x65, 0x4F, 0x6E, 0x02, 0x01]
|
||||
let expectedHexArray2: [UInt8] = [0x41, 0x08, 0x05]
|
||||
let expectedHexArray3: [UInt8] = [0x00, 0x08, 0x88, 0x04]
|
||||
let expectedHexArray4: [UInt8] = [0x04, 0x2a, 0x0a, 0x10, 0xc0, 0xbb, 0x01, 0x20]
|
||||
let expectedHexArray5: [UInt8] = [0x04, 0x22]
|
||||
let expectedHexArray6: [UInt8] = [0x04, 0x2a, 0x04, 0x10]
|
||||
let expectedHexArray7: [UInt8] = [0x04, 0x2a, 0x03, 0x10]
|
||||
|
||||
let receivedBytes = [UInt8](receivedData.prefix(expectedHexArray.count))
|
||||
|
||||
if receivedBytes == expectedHexArray {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 1")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
var response: [UInt8] = [0x2a, 0x08, 0x03, 0x12, 0x11, 0x22, 0x0f, 0x41, 0x54, 0x58, 0x20, 0x30, 0x34, 0x2c, 0x20, 0x53, 0x54, 0x58, 0x20, 0x30, 0x34, 0x00]
|
||||
var responseData = Data(bytes: &response, count: 22)
|
||||
|
||||
updateQueue.append((ZwiftPlayReadCharacteristic, responseData))
|
||||
|
||||
response = [0x2a, 0x08, 0x03, 0x12, 0x0d, 0x22, 0x0b, 0x52, 0x49, 0x44, 0x45, 0x5f, 0x4f, 0x4e, 0x28, 0x32, 0x29, 0x00]
|
||||
responseData = Data(bytes: &response, count: 18)
|
||||
|
||||
updateQueue.append((ZwiftPlayReadCharacteristic, responseData))
|
||||
|
||||
response = [0x52, 0x69, 0x64, 0x65, 0x4f, 0x6e, 0x02, 0x00]
|
||||
responseData = Data(bytes: &response, count: 8)
|
||||
|
||||
updateQueue.append((ZwiftPlayIndicateCharacteristic, responseData))
|
||||
}
|
||||
let receivedBytes2 = [UInt8](receivedData.prefix(expectedHexArray2.count))
|
||||
|
||||
if receivedBytes2 == expectedHexArray2 {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 2")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
|
||||
var response: [UInt8] = [0x3c, 0x08, 0x00, 0x12, 0x32, 0x0a, 0x30, 0x08, 0x80, 0x04, 0x12, 0x04, 0x05, 0x00, 0x05, 0x01, 0x1a, 0x0b, 0x4b, 0x49, 0x43, 0x4b, 0x52, 0x20, 0x43, 0x4f, 0x52, 0x45, 0x00, 0x32, 0x0f, 0x34, 0x30, 0x32, 0x34, 0x31, 0x38, 0x30, 0x30, 0x39, 0x38, 0x34, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x31, 0x42, 0x04, 0x08, 0x01, 0x10, 0x14 ]
|
||||
var responseData = Data(bytes: &response, count: 55)
|
||||
|
||||
updateQueue.append((ZwiftPlayIndicateCharacteristic, responseData))
|
||||
}
|
||||
let receivedBytes3 = [UInt8](receivedData.prefix(expectedHexArray3.count))
|
||||
|
||||
if receivedBytes3 == expectedHexArray3 {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 3")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
|
||||
var response: [UInt8] = [0x3c, 0x08, 0x88, 0x04, 0x12, 0x06, 0x0a, 0x04, 0x40, 0xc0, 0xbb, 0x01 ]
|
||||
var responseData = Data(bytes: &response, count: 12)
|
||||
|
||||
updateQueue.append((ZwiftPlayIndicateCharacteristic, responseData))
|
||||
}
|
||||
let receivedBytes4 = [UInt8](receivedData.prefix(expectedHexArray4.count))
|
||||
|
||||
if receivedBytes4 == expectedHexArray4 {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 4")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
|
||||
var response: [UInt8] = [ 0x03, 0x08, 0x00, 0x10, 0x00, 0x18, 0x59, 0x20, 0x00, 0x28, 0x00, 0x30, 0x9b, 0xed, 0x01]
|
||||
var responseData = Data(bytes: &response, count: 15)
|
||||
|
||||
updateQueue.append((ZwiftPlayReadCharacteristic, responseData))
|
||||
|
||||
response = [ 0x2a, 0x08, 0x03, 0x12, 0x27, 0x22, 0x25, 0x67, 0x61, 0x70, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x28, 0x32, 0x29, 0x3a, 0x20, 0x37, 0x32, 0x2c, 0x20, 0x37, 0x32, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x36, 0x30, 0x30, 0x00 ]
|
||||
responseData = Data(bytes: &response, count: 44)
|
||||
|
||||
updateQueue.append((ZwiftPlayReadCharacteristic, responseData))
|
||||
}
|
||||
let receivedBytes5 = [UInt8](receivedData.prefix(expectedHexArray5.count))
|
||||
|
||||
if receivedBytes5 == expectedHexArray5 {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 5")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
// 04 22 02 10 1a TODO
|
||||
var slope: [UInt8] = [ receivedBytes[4], 0x00 ]
|
||||
if receivedBytes[2] == 0x03 {
|
||||
slope[1] = receivedBytes[5]
|
||||
}
|
||||
self.CurrentSlope = Double(UInt16(slope[0]) + ((UInt16(slope[1]) << 8) & 0xFF00)) / 4.0
|
||||
slope[0] = UInt8(UInt16(self.CurrentSlope) & 0xFF)
|
||||
slope[1] = UInt8((UInt16(self.CurrentSlope) >> 8) & 0x00FF)
|
||||
LastFTMSMessageReceived = Data([0x11, 0x00, 0x00, slope[0], slope[1], 0x00, 0x00])
|
||||
|
||||
var response: [UInt8] = [ 0x3c, 0x08, 0x88, 0x04, 0x12, 0x06, 0x0a, 0x04, 0x40, 0xc0, 0xbb, 0x01 ]
|
||||
var responseData = Data(bytes: &response, count: 12)
|
||||
|
||||
updateQueue.append((ZwiftPlayIndicateCharacteristic, responseData))
|
||||
}
|
||||
let receivedBytes6 = [UInt8](receivedData.prefix(expectedHexArray6.count))
|
||||
|
||||
if receivedBytes6 == expectedHexArray6 {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 6")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
|
||||
var response: [UInt8] = [ 0x3c, 0x08, 0x88, 0x04, 0x12, 0x06, 0x0a, 0x04, 0x40, 0xc0, 0xbb, 0x01 ]
|
||||
response[9] = receivedData[4]
|
||||
response[10] = receivedData[5]
|
||||
response[11] = receivedData[6]
|
||||
handleZwiftGear(receivedData[4...])
|
||||
var responseData = Data(bytes: &response, count: 12)
|
||||
|
||||
updateQueue.append((ZwiftPlayIndicateCharacteristic, responseData))
|
||||
|
||||
response = [0x03, 0x08, 0x00, 0x10, 0x00, 0x18, 0xe7, 0x02, 0x20, 0x00, 0x28, 0x96, 0x14, 0x30, 0x9b, 0xed, 0x01]
|
||||
responseData = Data(bytes: &response, count: 17)
|
||||
updateQueue.append((ZwiftPlayReadCharacteristic, responseData))
|
||||
}
|
||||
let receivedBytes7 = [UInt8](receivedData.prefix(expectedHexArray7.count))
|
||||
|
||||
if receivedBytes7 == expectedHexArray7 {
|
||||
SwiftDebug.qtDebug("Zwift Play Ask 7")
|
||||
peripheral.respond(to: requests.first!, withResult: .success)
|
||||
|
||||
var response: [UInt8] = [0x03, 0x08, 0x00, 0x10, 0x00, 0x18, 0xe7, 0x02, 0x20, 0x00, 0x28, 0x00, 0x30, 0x9b, 0xed, 0x01]
|
||||
var responseData = Data(bytes: &response, count: 17)
|
||||
updateQueue.append((ZwiftPlayReadCharacteristic, responseData))
|
||||
|
||||
response = [ 0x3c, 0x08, 0x88, 0x04, 0x12, 0x05, 0x0a, 0x03, 0x40, 0x8c, 0x60 ]
|
||||
response[9] = receivedData[4]
|
||||
response[10] = receivedData[5]
|
||||
responseData = Data(bytes: &response, count: 11)
|
||||
handleZwiftGear(receivedData[4...])
|
||||
|
||||
updateQueue.append((ZwiftPlayIndicateCharacteristic, responseData))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleZwiftGear(_ array: Data) {
|
||||
var g : UInt8 = 0;
|
||||
if(array[4] == 0xCC && array[5] == 0x3a) {
|
||||
g = 1;
|
||||
} else if(array[4] == 0xFC && array[5] == 0x43) {
|
||||
g = 2;
|
||||
} else if(array[4] == 0xac && array[5] == 0x4d) {
|
||||
g = 3;
|
||||
} else if(array[4] == 0xd5 && array[5] == 0x56) {
|
||||
g = 4;
|
||||
} else if(array[4] == 0x8c && array[5] == 0x60) {
|
||||
g = 5;
|
||||
} else if(array[4] == 0xe8 && array[5] == 0x6b) {
|
||||
g = 6;
|
||||
} else if(array[4] == 0xc4 && array[5] == 0x77) {
|
||||
g = 7;
|
||||
} else if(array[4] == 0xa0 && array[5] == 0x83 && array[6] == 0x01) {
|
||||
g = 8;
|
||||
} else if(array[4] == 0xa8 && array[5] == 0x91 && array[6] == 0x01) {
|
||||
g = 9;
|
||||
} else if(array[4] == 0xb0 && array[5] == 0x9f && array[6] == 0x01) {
|
||||
g = 10;
|
||||
} else if(array[4] == 0xb8 && array[5] == 0xad && array[6] == 0x01) {
|
||||
g = 11;
|
||||
} else if(array[4] == 0xc0 && array[5] == 0xbb && array[6] == 0x01) {
|
||||
g = 12;
|
||||
} else if(array[4] == 0xf3 && array[5] == 0xcb && array[6] == 0x01) {
|
||||
g = 13;
|
||||
} else if(array[4] == 0xa8 && array[5] == 0xdc && array[6] == 0x01) {
|
||||
g = 14;
|
||||
} else if(array[4] == 0xdc && array[5] == 0xec && array[6] == 0x01) {
|
||||
g = 15;
|
||||
} else if(array[4] == 0x90 && array[5] == 0xfd && array[6] == 0x01) {
|
||||
g = 16;
|
||||
} else if(array[4] == 0xd4 && array[5] == 0x90 && array[6] == 0x02) {
|
||||
g = 17;
|
||||
} else if(array[4] == 0x98 && array[5] == 0xa4 && array[6] == 0x02) {
|
||||
g = 18;
|
||||
} else if(array[4] == 0xdc && array[5] == 0xb7 && array[6] == 0x02) {
|
||||
g = 19;
|
||||
} else if(array[4] == 0x9f && array[5] == 0xcb && array[6] == 0x02) {
|
||||
g = 20;
|
||||
} else if(array[4] == 0xd8 && array[5] == 0xe2 && array[6] == 0x02) {
|
||||
g = 21;
|
||||
} else if(array[4] == 0x90 && array[5] == 0xfa && array[6] == 0x02) {
|
||||
g = 22;
|
||||
} else if(array[4] == 0xc8 && array[5] == 0x91 && array[6] == 0x03) {
|
||||
g = 23;
|
||||
} else if(array[4] == 0xf3 && array[5] == 0xac && array[6] == 0x03) {
|
||||
g = 24;
|
||||
}
|
||||
|
||||
|
||||
if (g < self.CurrentZwiftGear) {
|
||||
for _ in 0..<(self.CurrentZwiftGear - g) {
|
||||
SwiftDebug.gearDown()
|
||||
}
|
||||
} else if (g > self.CurrentZwiftGear) {
|
||||
for _ in 0..<(g - self.CurrentZwiftGear) {
|
||||
SwiftDebug.gearUp()
|
||||
}
|
||||
}
|
||||
self.CurrentZwiftGear = g
|
||||
}
|
||||
|
||||
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
|
||||
SwiftDebug.qtDebug("virtualbike_zwift didReceiveRead: " + String(describing: request.characteristic))
|
||||
if request.characteristic == self.heartRateCharacteristic {
|
||||
request.value = self.calculateHeartRate()
|
||||
self.peripheralManager.respond(to: request, withResult: .success)
|
||||
@@ -478,13 +736,24 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
|
||||
}
|
||||
|
||||
@objc func updateSubscribers() {
|
||||
if(self.serviceToggle == 3 || garmin_bluetooth_compatibility)
|
||||
{
|
||||
let powerData = self.calculatePower()
|
||||
let ok = self.peripheralManager.updateValue(powerData, for: self.PowerMeasurementCharacteristic, onSubscribedCentrals: nil)
|
||||
if(ok) {
|
||||
self.serviceToggle = 0
|
||||
}
|
||||
if(self.serviceToggle == 4 || garmin_bluetooth_compatibility || (self.serviceToggle == 3 && !zwift_play_emulator))
|
||||
{
|
||||
let powerData = self.calculatePower()
|
||||
let ok = self.peripheralManager.updateValue(powerData, for: self.PowerMeasurementCharacteristic, onSubscribedCentrals: nil)
|
||||
if(ok) {
|
||||
self.serviceToggle = 0
|
||||
}
|
||||
} else if(self.serviceToggle == 3) {
|
||||
if(!sendUpdates()) {
|
||||
let ZwiftPlayArray : [UInt8] = [ 0x03, 0x08, 0x00, 0x10, 0x00, 0x18, 0xe7, 0x02, 0x20, 0x00, 0x28, 0x00, 0x30, 0x9b, 0xed, 0x01 ]
|
||||
let ZwiftPlayData = Data(bytes: ZwiftPlayArray, count: 16)
|
||||
let ok = self.peripheralManager.updateValue(ZwiftPlayData, for: self.ZwiftPlayReadCharacteristic, onSubscribedCentrals: nil)
|
||||
if(ok) {
|
||||
self.serviceToggle = self.serviceToggle + 1
|
||||
}
|
||||
} else {
|
||||
self.serviceToggle = self.serviceToggle + 1
|
||||
}
|
||||
} else if(self.serviceToggle == 2) {
|
||||
let cadenceData = self.calculateCadence()
|
||||
let ok = self.peripheralManager.updateValue(cadenceData, for: self.CSCMeasurementCharacteristic, onSubscribedCentrals: nil)
|
||||
|
||||
0
src/qdomyos-zwift.pri
Executable file → Normal file
0
src/qdomyos-zwift.pri
Executable file → Normal file
@@ -768,8 +768,9 @@ const QString QZSettings::peloton_date_format = QStringLiteral("peloton_date_for
|
||||
const QString QZSettings::default_peloton_date_format = QStringLiteral("MM/dd/yy");
|
||||
const QString QZSettings::force_resistance_instead_inclination = QStringLiteral("force_resistance_instead_inclination");
|
||||
const QString QZSettings::proform_treadmill_575i = QStringLiteral("proform_treadmill_575i");
|
||||
const QString QZSettings::zwift_play_emulator = QStringLiteral("zwift_play_emulator");
|
||||
|
||||
const uint32_t allSettingsCount = 650;
|
||||
const uint32_t allSettingsCount = 651;
|
||||
|
||||
QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles},
|
||||
@@ -1426,6 +1427,7 @@ QVariant allSettings[allSettingsCount][2] = {
|
||||
{QZSettings::peloton_date_format, QZSettings::default_peloton_date_format},
|
||||
{QZSettings::force_resistance_instead_inclination, QZSettings::default_force_resistance_instead_inclination},
|
||||
{QZSettings::proform_treadmill_575i, QZSettings::default_proform_treadmill_575i},
|
||||
{QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator},
|
||||
};
|
||||
|
||||
void QZSettings::qDebugAllSettings(bool showDefaults) {
|
||||
|
||||
@@ -2150,6 +2150,9 @@ class QZSettings {
|
||||
static const QString proform_treadmill_575i;
|
||||
static constexpr bool default_proform_treadmill_575i = false;
|
||||
|
||||
static const QString zwift_play_emulator;
|
||||
static constexpr bool default_zwift_play_emulator = 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.
|
||||
|
||||
@@ -984,6 +984,9 @@ import QtQuick.Dialogs 1.0
|
||||
property string peloton_date_format: "MM/dd/yy"
|
||||
property bool force_resistance_instead_inclination: false
|
||||
property bool proform_treadmill_575i: false
|
||||
|
||||
// from version 2.18.1
|
||||
property bool zwift_play_emulator: false
|
||||
}
|
||||
|
||||
function paddingZeros(text, limit) {
|
||||
@@ -4843,6 +4846,34 @@ import QtQuick.Dialogs 1.0
|
||||
color: Material.color(Material.Lime)
|
||||
}
|
||||
|
||||
SwitchDelegate {
|
||||
text: qsTr("Get Gears from Zwift")
|
||||
spacing: 0
|
||||
bottomPadding: 0
|
||||
topPadding: 0
|
||||
rightPadding: 0
|
||||
leftPadding: 0
|
||||
clip: false
|
||||
checked: settings.zwift_play_emulator
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
Layout.fillWidth: true
|
||||
onClicked: { settings.zwift_play_emulator = checked; window.settings_restart_to_apply = true; }
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("This setting bring virtual gearing from zwift to all the bikes directly from the Zwift interface. You have to configure zwift: Wahoo virtual device from QZ as for power and cadence, and your QZ device as resistance. Default: disabled.")
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
spacing: 10
|
||||
Label {
|
||||
|
||||
@@ -29,6 +29,7 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
settings.value(QZSettings::virtual_device_echelon, QZSettings::default_virtual_device_echelon).toBool();
|
||||
bool ifit = settings.value(QZSettings::virtual_device_ifit, QZSettings::default_virtual_device_ifit).toBool();
|
||||
bool garmin_bluetooth_compatibility = settings.value(QZSettings::garmin_bluetooth_compatibility, QZSettings::default_garmin_bluetooth_compatibility).toBool();
|
||||
bool zwift_play_emulator = settings.value(QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator).toBool();
|
||||
|
||||
if (settings.value(QZSettings::dircon_yes, QZSettings::default_dircon_yes).toBool()) {
|
||||
dirconManager = new DirconManager(Bike, bikeResistanceOffset, bikeResistanceGain, this);
|
||||
@@ -59,7 +60,7 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
qDebug() << "ios_zwift_workaround activated!";
|
||||
h = new lockscreen();
|
||||
h->virtualbike_zwift_ios(
|
||||
settings.value(QZSettings::bike_heartrate_service, QZSettings::default_bike_heartrate_service).toBool(), garmin_bluetooth_compatibility);
|
||||
settings.value(QZSettings::bike_heartrate_service, QZSettings::default_bike_heartrate_service).toBool(), garmin_bluetooth_compatibility, zwift_play_emulator);
|
||||
} else
|
||||
|
||||
#endif
|
||||
@@ -196,6 +197,33 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
serviceDataFIT.addCharacteristic(charDataFIT4);
|
||||
serviceDataFIT.addCharacteristic(charDataFIT5);
|
||||
serviceDataFIT.addCharacteristic(charDataFIT6);
|
||||
|
||||
if(zwift_play_emulator) {
|
||||
QLowEnergyCharacteristicData charData;
|
||||
charData.setUuid(QBluetoothUuid(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
charData.setProperties(QLowEnergyCharacteristic::Write | QLowEnergyCharacteristic::WriteNoResponse);
|
||||
|
||||
QLowEnergyCharacteristicData charData2;
|
||||
charData2.setUuid(QBluetoothUuid(QStringLiteral("00000002-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
charData2.setProperties(QLowEnergyCharacteristic::Notify);
|
||||
const QLowEnergyDescriptorData clientConfig2(QBluetoothUuid::ClientCharacteristicConfiguration, descriptor);
|
||||
charData2.addDescriptor(clientConfig2);
|
||||
|
||||
QLowEnergyCharacteristicData charData3;
|
||||
charData3.setUuid(QBluetoothUuid(QStringLiteral("00000004-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
charData3.setProperties(QLowEnergyCharacteristic::Indicate);
|
||||
QByteArray descriptorIndicate;
|
||||
descriptorIndicate.append((char)0x02);
|
||||
descriptorIndicate.append((char)0x00);
|
||||
const QLowEnergyDescriptorData clientConfig3(QBluetoothUuid::ClientCharacteristicConfiguration, descriptorIndicate);
|
||||
charData3.addDescriptor(clientConfig3);
|
||||
|
||||
serviceDataZwiftPlayBike.setType(QLowEnergyServiceData::ServiceTypePrimary);
|
||||
serviceDataZwiftPlayBike.setUuid(QBluetoothUuid(QStringLiteral("00000001-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
serviceDataZwiftPlayBike.addCharacteristic(charData);
|
||||
serviceDataZwiftPlayBike.addCharacteristic(charData2);
|
||||
serviceDataZwiftPlayBike.addCharacteristic(charData3);
|
||||
}
|
||||
} else if (power) {
|
||||
|
||||
QLowEnergyCharacteristicData charData;
|
||||
@@ -393,6 +421,10 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
if (!cadence && !power) {
|
||||
|
||||
serviceFIT = leController->addService(serviceDataFIT);
|
||||
if(zwift_play_emulator) {
|
||||
QThread::msleep(100); // give time to Android to add the service async.ly
|
||||
serviceZwiftPlayBike = leController->addService(serviceDataZwiftPlayBike);
|
||||
}
|
||||
} else {
|
||||
service = leController->addService(serviceData);
|
||||
}
|
||||
@@ -420,6 +452,8 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
if (!cadence && !power) {
|
||||
QObject::connect(serviceFIT, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualbike::characteristicChanged);
|
||||
QObject::connect(serviceZwiftPlayBike, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualbike::characteristicChanged);
|
||||
} else {
|
||||
QObject::connect(service, &QLowEnergyService::characteristicChanged, this,
|
||||
&virtualbike::characteristicChanged);
|
||||
@@ -463,6 +497,7 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
|
||||
void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QByteArray reply;
|
||||
QSettings settings;
|
||||
bool zwift_play_emulator = settings.value(QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator).toBool();
|
||||
bool echelon =
|
||||
settings.value(QZSettings::virtual_device_echelon, QZSettings::default_virtual_device_echelon).toBool();
|
||||
bool ifit = settings.value(QZSettings::virtual_device_ifit, QZSettings::default_virtual_device_ifit).toBool();
|
||||
@@ -474,14 +509,13 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
qDebug() << QStringLiteral("characteristicChanged ") + QString::number(characteristic.uuid().toUInt16()) +
|
||||
QStringLiteral(" ") + newValue.toHex(' ');
|
||||
|
||||
if (!echelon && !ifit) {
|
||||
lastFTMSFrameReceived = QDateTime::currentMSecsSinceEpoch();
|
||||
emit ftmsCharacteristicChanged(characteristic, newValue);
|
||||
}
|
||||
|
||||
switch (characteristic.uuid().toUInt16()) {
|
||||
|
||||
case 0x2AD9: // Fitness Machine Control Point
|
||||
if (!echelon && !ifit) {
|
||||
lastFTMSFrameReceived = QDateTime::currentMSecsSinceEpoch();
|
||||
emit ftmsCharacteristicChanged(characteristic, newValue);
|
||||
}
|
||||
if (writeP2AD9->writeProcess(0x2AD9, newValue, reply) == CP_OK) {
|
||||
|
||||
QLowEnergyCharacteristic characteristic =
|
||||
@@ -801,6 +835,121 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
}
|
||||
}
|
||||
|
||||
//********************ZWIFT PLAY**************
|
||||
|
||||
if(characteristic.uuid().toString().contains(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1")) && zwift_play_emulator) {
|
||||
static const QByteArray expectedHexArray = QByteArray::fromHex("52696465 4F6E0201");
|
||||
static const QByteArray expectedHexArray2 = QByteArray::fromHex("410805");
|
||||
static const QByteArray expectedHexArray3 = QByteArray::fromHex("00088804");
|
||||
static const QByteArray expectedHexArray4 = QByteArray::fromHex("042A0A10 C0BB0120");
|
||||
static const QByteArray expectedHexArray5 = QByteArray::fromHex("0422");
|
||||
static const QByteArray expectedHexArray6 = QByteArray::fromHex("042A0410");
|
||||
static const QByteArray expectedHexArray7 = QByteArray::fromHex("042A0310");
|
||||
|
||||
QByteArray receivedData = newValue;
|
||||
|
||||
QLowEnergyCharacteristic zwiftPlayRead =
|
||||
serviceZwiftPlayBike->characteristic(QBluetoothUuid(QStringLiteral("00000002-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
|
||||
QLowEnergyCharacteristic zwiftPlayIndicate =
|
||||
serviceZwiftPlayBike->characteristic(QBluetoothUuid(QStringLiteral("00000004-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
|
||||
if (receivedData.startsWith(expectedHexArray)) {
|
||||
qDebug() << "Zwift Play Ask 1";
|
||||
|
||||
QByteArray response = QByteArray::fromHex("2a08031211220f4154582030342c2053545820303400");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayRead, response);
|
||||
|
||||
response = QByteArray::fromHex("2a0803120d220b524944455f4f4e28322900");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayRead, response);
|
||||
|
||||
response = QByteArray::fromHex("526964654f6e0200");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayIndicate, response);
|
||||
}
|
||||
else if (receivedData.startsWith(expectedHexArray2)) {
|
||||
qDebug() << "Zwift Play Ask 2";
|
||||
|
||||
QByteArray response = QByteArray::fromHex("3c080012320a3008800412040500050"
|
||||
"11a0b4b49434b5220434f524500320f"
|
||||
"3430323431383030393834000000003a01314204080110140");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayIndicate, response);
|
||||
}
|
||||
else if (receivedData.startsWith(expectedHexArray3)) {
|
||||
qDebug() << "Zwift Play Ask 3";
|
||||
|
||||
QByteArray response = QByteArray::fromHex("3c0888041206 0a0440c0bb01");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayIndicate, response);
|
||||
}
|
||||
else if (receivedData.startsWith(expectedHexArray4)) {
|
||||
qDebug() << "Zwift Play Ask 4";
|
||||
|
||||
QByteArray response = QByteArray::fromHex("0308001000185920002800309bed01");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayRead, response);
|
||||
|
||||
response = QByteArray::fromHex("2a08031227222567"
|
||||
"61705f706172616d735f6368616e6765"
|
||||
"2832293a2037322c2037322c20302c20"
|
||||
"36303000");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayRead, response);
|
||||
}
|
||||
else if (receivedData.startsWith(expectedHexArray5)) {
|
||||
qDebug() << "Zwift Play Ask 5";
|
||||
|
||||
QByteArray slope(2, 0);
|
||||
slope[0] = receivedData[4];
|
||||
if (receivedData.at(2) == (uint8_t)0x03) {
|
||||
slope[1] = receivedData[5];
|
||||
}
|
||||
double CurrentSlope = (qint16(slope[0]) + ((qint16(slope[1]) << 8) & 0xFF00)) / 4.0;
|
||||
slope[0] = quint8(qint16(CurrentSlope) & 0xFF);
|
||||
slope[1] = quint8((qint16(CurrentSlope) >> 8) & 0x00FF);
|
||||
|
||||
QBluetoothUuid targetUuid = QBluetoothUuid(quint16(0x2ad9));
|
||||
QLowEnergyCharacteristic targetCharacteristic;
|
||||
|
||||
for (const QLowEnergyCharacteristic &characteristic : serviceFIT->characteristics()) {
|
||||
if (characteristic.uuid() == targetUuid) {
|
||||
targetCharacteristic = characteristic;
|
||||
break; // Abbiamo trovato la caratteristica, usciamo dal ciclo
|
||||
}
|
||||
}
|
||||
|
||||
if (targetCharacteristic.isValid()) {
|
||||
characteristicChanged(targetCharacteristic, QByteArray::fromHex("110000") + slope + QByteArray::fromHex("0000"));
|
||||
|
||||
QByteArray response = QByteArray::fromHex("3c0888041206 0a0440c0bb01");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayIndicate, response);
|
||||
} else {
|
||||
qDebug() << "ERROR! Zwift Play Ask 5 without answer!";
|
||||
}
|
||||
}
|
||||
else if (receivedData.startsWith(expectedHexArray6)) {
|
||||
qDebug() << "Zwift Play Ask 6";
|
||||
|
||||
QByteArray response = QByteArray::fromHex("3c0888041206 0a0440c0bb01");
|
||||
response[9] = receivedData[4];
|
||||
response[10] = receivedData[5];
|
||||
response[11] = receivedData[6];
|
||||
handleZwiftGear(receivedData.mid(4));
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayIndicate, response);
|
||||
|
||||
response = QByteArray::fromHex("03080010001827e7 20002896143093ed01");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayRead, response);
|
||||
}
|
||||
else if (receivedData.startsWith(expectedHexArray7)) {
|
||||
qDebug() << "Zwift Play Ask 7";
|
||||
|
||||
QByteArray response = QByteArray::fromHex("03080010001827e7 2000 28 00 3093ed01");
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayRead, response);
|
||||
|
||||
response = QByteArray::fromHex("3c088804120503408c60");
|
||||
response[9] = receivedData[4];
|
||||
response[10] = receivedData[5];
|
||||
handleZwiftGear(receivedData.mid(4));
|
||||
writeCharacteristic(serviceZwiftPlayBike, zwiftPlayIndicate, response);
|
||||
}
|
||||
}
|
||||
|
||||
//******************** ECHELON ***************
|
||||
if (characteristic.uuid().toString().contains(QStringLiteral("0bf669f2-45f2-11e7-9598-0800200c9a66"))) {
|
||||
QLowEnergyCharacteristic characteristic =
|
||||
@@ -884,6 +1033,48 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
}
|
||||
}
|
||||
|
||||
void virtualbike::handleZwiftGear(const QByteArray &array)
|
||||
{
|
||||
uint8_t g = 0;
|
||||
if (array.size() >= 3) {
|
||||
if ((uint8_t)array[0] == (uint8_t)0xCC && (uint8_t)array[1] == (uint8_t)0x3A) g = 1;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xFC && (uint8_t)array[1] == (uint8_t)0x43) g = 2;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xAC && (uint8_t)array[1] == (uint8_t)0x4D) g = 3;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xD5 && (uint8_t)array[1] == (uint8_t)0x56) g = 4;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0x8C && (uint8_t)array[1] == (uint8_t)0x60) g = 5;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xE8 && (uint8_t)array[1] == (uint8_t)0x6B) g = 6;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xC4 && (uint8_t)array[1] == (uint8_t)0x77) g = 7;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xA0 && (uint8_t)array[1] == (uint8_t)0x83 && (uint8_t)array[2] == (uint8_t)0x01) g = 8;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xA8 && (uint8_t)array[1] == (uint8_t)0x91 && (uint8_t)array[2] == (uint8_t)0x01) g = 9;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xB0 && (uint8_t)array[1] == (uint8_t)0x9F && (uint8_t)array[2] == (uint8_t)0x01) g = 10;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xB8 && (uint8_t)array[1] == (uint8_t)0xAD && (uint8_t)array[2] == (uint8_t)0x01) g = 11;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xC0 && (uint8_t)array[1] == (uint8_t)0xBB && (uint8_t)array[2] == (uint8_t)0x01) g = 12;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xF3 && (uint8_t)array[1] == (uint8_t)0xCB && (uint8_t)array[2] == (uint8_t)0x01) g = 13;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xA8 && (uint8_t)array[1] == (uint8_t)0xDC && (uint8_t)array[2] == (uint8_t)0x01) g = 14;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xDC && (uint8_t)array[1] == (uint8_t)0xEC && (uint8_t)array[2] == (uint8_t)0x01) g = 15;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0x90 && (uint8_t)array[1] == (uint8_t)0xFD && (uint8_t)array[2] == (uint8_t)0x01) g = 16;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xD4 && (uint8_t)array[1] == (uint8_t)0x90 && (uint8_t)array[2] == (uint8_t)0x02) g = 17;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0x98 && (uint8_t)array[1] == (uint8_t)0xA4 && (uint8_t)array[2] == (uint8_t)0x02) g = 18;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xDC && (uint8_t)array[1] == (uint8_t)0xB7 && (uint8_t)array[2] == (uint8_t)0x02) g = 19;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0x9F && (uint8_t)array[1] == (uint8_t)0xCB && (uint8_t)array[2] == (uint8_t)0x02) g = 20;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xD8 && (uint8_t)array[1] == (uint8_t)0xE2 && (uint8_t)array[2] == (uint8_t)0x02) g = 21;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0x90 && (uint8_t)array[1] == (uint8_t)0xFA && (uint8_t)array[2] == (uint8_t)0x02) g = 22;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xC8 && (uint8_t)array[1] == (uint8_t)0x91 && (uint8_t)array[2] == (uint8_t)0x03) g = 23;
|
||||
else if ((uint8_t)array[0] == (uint8_t)0xF3 && (uint8_t)array[1] == (uint8_t)0xAC && (uint8_t)array[2] == (uint8_t)0x03) g = 24;
|
||||
}
|
||||
|
||||
if (g < CurrentZwiftGear) {
|
||||
for (int i = 0; i < CurrentZwiftGear - g; ++i) {
|
||||
((bike*)Bike)->gearDown();
|
||||
}
|
||||
} else if (g > CurrentZwiftGear) {
|
||||
for (int i = 0; i < g - CurrentZwiftGear; ++i) {
|
||||
((bike*)Bike)->gearUp();
|
||||
}
|
||||
}
|
||||
CurrentZwiftGear = g;
|
||||
}
|
||||
|
||||
int virtualbike::iFit_pelotonToBikeResistance(int pelotonResistance) {
|
||||
if (pelotonResistance <= 10) {
|
||||
return 2;
|
||||
@@ -996,6 +1187,7 @@ void virtualbike::reconnect() {
|
||||
return;
|
||||
}
|
||||
|
||||
bool zwift_play_emulator = settings.value(QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool battery = settings.value(QZSettings::battery_service, QZSettings::default_battery_service).toBool();
|
||||
bool power = settings.value(QZSettings::bike_power_sensor, QZSettings::default_bike_power_sensor).toBool();
|
||||
@@ -1019,6 +1211,10 @@ void virtualbike::reconnect() {
|
||||
if (!cadence && !power) {
|
||||
|
||||
serviceFIT = leController->addService(serviceDataFIT);
|
||||
if(zwift_play_emulator) {
|
||||
QThread::msleep(100); // give time to Android to add the service async.ly
|
||||
serviceZwiftPlayBike = leController->addService(serviceDataZwiftPlayBike);
|
||||
}
|
||||
} else {
|
||||
service = leController->addService(serviceData);
|
||||
}
|
||||
@@ -1048,6 +1244,7 @@ void virtualbike::reconnect() {
|
||||
void virtualbike::bikeProvider() {
|
||||
|
||||
QSettings settings;
|
||||
bool zwift_play_emulator = settings.value(QZSettings::zwift_play_emulator, QZSettings::default_zwift_play_emulator).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool battery = settings.value(QZSettings::battery_service, QZSettings::default_battery_service).toBool();
|
||||
bool power = settings.value(QZSettings::bike_power_sensor, QZSettings::default_bike_power_sensor).toBool();
|
||||
@@ -1070,7 +1267,7 @@ void virtualbike::bikeProvider() {
|
||||
// really connected to a device
|
||||
if (h->virtualbike_updateFTMS(normalizeSpeed, (char)Bike->currentResistance().value(),
|
||||
(uint16_t)Bike->currentCadence().value() * 2, (uint16_t)normalizeWattage,
|
||||
Bike->currentCrankRevolutions(), Bike->lastCrankEventTime())) {
|
||||
Bike->currentCrankRevolutions(), Bike->lastCrankEventTime(), ((bike*)Bike)->gears())) {
|
||||
h->virtualbike_setHeartRate(Bike->currentHeart().value());
|
||||
|
||||
uint8_t ftms_message[255];
|
||||
@@ -1157,6 +1354,14 @@ void virtualbike::bikeProvider() {
|
||||
return;
|
||||
}
|
||||
writeCharacteristic(serviceFIT, characteristic, value);
|
||||
|
||||
if(zwift_play_emulator) {
|
||||
QLowEnergyCharacteristic characteristic1 =
|
||||
serviceZwiftPlayBike->characteristic(QBluetoothUuid(QStringLiteral("00000002-19ca-4651-86e5-fa29dcdd09d1")));
|
||||
const uint8_t v[] = {0x03, 0x08, 0x00, 0x10, 0x00, 0x18, 0xe7, 0x02, 0x20, 0x00, 0x28, 0x00, 0x30, 0x9b, 0xed, 0x01};
|
||||
value = QByteArray::fromRawData((char*)v, 16);
|
||||
writeCharacteristic(serviceZwiftPlayBike, characteristic1, value);
|
||||
}
|
||||
}
|
||||
} else if (power) {
|
||||
value.clear();
|
||||
|
||||
@@ -50,6 +50,7 @@ class virtualbike : public virtualdevice {
|
||||
QLowEnergyService *serviceFIT = nullptr;
|
||||
QLowEnergyService *service = nullptr;
|
||||
QLowEnergyService *serviceChanged = nullptr;
|
||||
QLowEnergyService *serviceZwiftPlayBike = nullptr;
|
||||
QLowEnergyAdvertisingData advertisingData;
|
||||
QLowEnergyServiceData serviceDataHR;
|
||||
QLowEnergyServiceData serviceDataBattery;
|
||||
@@ -57,6 +58,7 @@ class virtualbike : public virtualdevice {
|
||||
QLowEnergyServiceData serviceData;
|
||||
QLowEnergyServiceData serviceDataChanged;
|
||||
QLowEnergyServiceData serviceEchelon;
|
||||
QLowEnergyServiceData serviceDataZwiftPlayBike;
|
||||
QTimer bikeTimer;
|
||||
bluetoothdevice *Bike;
|
||||
CharacteristicWriteProcessor2AD9 *writeP2AD9 = 0;
|
||||
@@ -73,6 +75,7 @@ class virtualbike : public virtualdevice {
|
||||
int8_t bikeResistanceOffset = 4;
|
||||
double bikeResistanceGain = 1.0;
|
||||
DirconManager *dirconManager = 0;
|
||||
uint8_t CurrentZwiftGear = 8;
|
||||
int iFit_pelotonToBikeResistance(int pelotonResistance);
|
||||
int iFit_resistanceToIfit(int ifitResistance);
|
||||
qint64 iFit_timer = 0;
|
||||
@@ -81,6 +84,8 @@ class virtualbike : public virtualdevice {
|
||||
resistance_t iFit_LastResistanceRequested = 0;
|
||||
bool iFit_Stop = false;
|
||||
|
||||
void handleZwiftGear(const QByteArray &array);
|
||||
|
||||
bool echelonInitDone = false;
|
||||
void echelonWriteResistance();
|
||||
void echelonWriteStatus();
|
||||
|
||||
Reference in New Issue
Block a user