Compare commits

...

44 Commits

Author SHA1 Message Date
Roberto Viola
0c7ad157de fixing difficulty 2024-10-08 15:13:41 +02:00
Roberto Viola
2f4d80dda1 Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-10-08 14:43:09 +02:00
Roberto Viola
28e1bf2abf Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-10-08 14:26:58 +02:00
Roberto Viola
3ee47b9b22 Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-10-08 09:08:13 +02:00
Roberto Viola
be19850f31 handling slope 2024-10-06 15:09:26 +02:00
Roberto Viola
2c12f7cd20 Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-10-06 06:19:39 +02:00
Roberto Viola
916a664706 Update project.pbxproj 2024-09-29 07:48:22 +02:00
Roberto Viola
cf38aab0af Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-09-28 12:03:03 +02:00
Roberto Viola
70ecbacd6a increasing UI speed for the gear changing 2024-09-26 15:20:54 +02:00
Roberto Viola
d4d3a9ceb3 reverting torque not necessary 2024-09-26 14:26:41 +02:00
Roberto Viola
e58c7c6888 the gearing is working! 2024-09-26 11:40:16 +02:00
Roberto Viola
614690aec3 Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-09-26 10:46:31 +02:00
Roberto Viola
ea0221d20d accolumulated torque but it doesn't seem necessary 2024-09-26 09:05:13 +02:00
Roberto Viola
8920cf4981 Update virtualbike_zwift.swift 2024-09-26 08:26:59 +02:00
Roberto Viola
a013c73ced seems to work apart the wattage to zwift 2024-09-26 08:09:23 +02:00
Roberto Viola
3000b8e6d9 Merge branch 'Zwift-Play-Emulator-#2391' of https://github.com/cagnulein/qdomyos-zwift into Zwift-Play-Emulator-#2391 2024-09-25 11:14:59 +02:00
Roberto Viola
f8b2975558 Update virtualbike_zwift.swift 2024-09-25 11:14:46 +02:00
Roberto Viola
ba27677cae Update virtualbike_zwift.swift 2024-09-25 11:01:55 +02:00
Roberto Viola
b77a12b895 Update virtualbike_zwift.swift 2024-09-25 10:46:00 +02:00
Roberto Viola
4a8ffa343e Update virtualbike_zwift.swift 2024-09-25 10:42:19 +02:00
Roberto Viola
bb40f2475d Update virtualbike_zwift.swift 2024-09-25 10:06:46 +02:00
Roberto Viola
2f554750a5 Update virtualbike_zwift.swift 2024-09-25 10:00:47 +02:00
Roberto Viola
ea3ea7b570 zwift play ask 1 passed! 2024-09-25 09:43:02 +02:00
Roberto Viola
a0e86b9270 Update virtualbike_zwift.swift 2024-09-24 11:32:48 +02:00
Roberto Viola
ea4b93d96f Update virtualbike_zwift.swift 2024-09-24 07:46:35 +02:00
Roberto Viola
6cefcdc011 Update virtualbike.cpp 2024-09-23 16:20:37 +02:00
Roberto Viola
eb6438f591 Update virtualbike.cpp 2024-09-23 15:32:03 +02:00
Roberto Viola
da047d5e5b Update virtualbike.cpp 2024-09-23 14:13:51 +02:00
Roberto Viola
a5c3ca388d Update virtualbike.cpp 2024-09-23 13:41:51 +02:00
Roberto Viola
5fb771b9f0 Update virtualbike.cpp 2024-09-23 13:01:36 +02:00
Roberto Viola
936bb56574 porting to android too 2024-09-23 08:56:09 +02:00
Roberto Viola
d6e9227360 fixing iOS UUID? 2024-09-23 08:55:59 +02:00
Roberto Viola
6a6efebfcb Update virtualbike_zwift.swift 2024-09-22 14:23:27 +02:00
Roberto Viola
1674ec85a1 Merge branch 'master' into Zwift-Play-Emulator-#2391 2024-09-20 15:56:03 +02:00
Roberto Viola
71618d0a16 Update virtualbike_zwift.swift 2024-09-20 15:54:43 +02:00
Roberto Viola
05666dea67 adding zwift play service 2024-09-20 15:37:33 +02:00
Roberto Viola
f2c3c0c63c Merge branch 'master' into Gear-UI-on-Zwift-#2391 2024-09-06 11:30:16 +02:00
Roberto Viola
e6a7210609 Update virtualbike.cpp 2024-09-06 11:28:14 +02:00
Roberto Viola
afd1953117 gears works on android too! 2024-08-20 08:33:17 +02:00
Roberto Viola
5a18a00295 adding the android part 2024-08-20 07:29:46 +02:00
Roberto Viola
d0acc202df trying also on dircon but it doesn't work 2024-08-19 10:26:19 +02:00
Roberto Viola
97702e8ae2 dynamic gears 2024-08-19 09:19:28 +02:00
Roberto Viola
ef017273d9 Update virtualbike_zwift.swift 2024-08-18 20:29:33 +02:00
Roberto Viola
66dc8bbb6f trying on ios 2024-08-18 16:12:23 +02:00
16 changed files with 460 additions and 28 deletions

View File

@@ -414,6 +414,7 @@
879F74152893D732009A64C8 /* CoreMedia.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 879F74142893D732009A64C8 /* CoreMedia.framework */; };
87A0771029B641D600A368BF /* wahookickrheadwind.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0770F29B641D500A368BF /* wahookickrheadwind.cpp */; };
87A0771229B6420200A368BF /* moc_wahookickrheadwind.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0771129B6420200A368BF /* moc_wahookickrheadwind.cpp */; };
87A083082C73361C00567A4E /* characteristicnotifier1224.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A083052C73361B00567A4E /* characteristicnotifier1224.cpp */; };
87A0C4BB262329A600121A76 /* npecablebike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0C4B7262329A600121A76 /* npecablebike.cpp */; };
87A0C4BC262329A600121A76 /* cscbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0C4B9262329A600121A76 /* cscbike.cpp */; };
87A0C4BF262329B500121A76 /* moc_cscbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0C4BD262329B500121A76 /* moc_cscbike.cpp */; };
@@ -1320,6 +1321,9 @@
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>"; };
87A083052C73361B00567A4E /* characteristicnotifier1224.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = characteristicnotifier1224.cpp; path = ../src/characteristics/characteristicnotifier1224.cpp; sourceTree = "<group>"; };
87A083062C73361C00567A4E /* characteristicnotifier2ad9.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = characteristicnotifier2ad9.h; path = ../src/characteristics/characteristicnotifier2ad9.h; sourceTree = "<group>"; };
87A083072C73361C00567A4E /* characteristicnotifier1224.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = characteristicnotifier1224.h; path = ../src/characteristics/characteristicnotifier1224.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 +2082,9 @@
2EB56BE3C2D93CDAB0C52E67 /* Sources */ = {
isa = PBXGroup;
children = (
87A083062C73361C00567A4E /* characteristicnotifier2ad9.h */,
87A083052C73361B00567A4E /* characteristicnotifier1224.cpp */,
87A083072C73361C00567A4E /* characteristicnotifier1224.h */,
8772B7F92CB5603A004AB8E9 /* deerruntreadmill.h */,
8772B7F62CB55E98004AB8E9 /* deerruntreadmill.cpp */,
8772B7F32CB55E80004AB8E9 /* moc_deerruntreadmill.cpp */,
@@ -3606,6 +3613,7 @@
87D2699F25F535200076AA48 /* m3ibike.cpp in Compile Sources */,
87917A7528E768D200F8D9AC /* Connection.swift in Compile Sources */,
87FFA13727BBE3FF00924E4E /* solebike.cpp in Compile Sources */,
87A083082C73361C00567A4E /* characteristicnotifier1224.cpp in Compile Sources */,
87F4FB5A29D550C00061BB4A /* schwinn170bike.cpp in Compile Sources */,
7352E0F0EE5366AC809B9D64 /* qrc_qml.cpp in Compile Sources */,
873824E727E647A8004F1B46 /* record.cpp in Compile Sources */,
@@ -4066,7 +4074,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 894;
CURRENT_PROJECT_VERSION = 895;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1";
@@ -4257,7 +4265,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 894;
CURRENT_PROJECT_VERSION = 895;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = NO;
@@ -4484,7 +4492,7 @@
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 894;
CURRENT_PROJECT_VERSION = 895;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -4580,7 +4588,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 894;
CURRENT_PROJECT_VERSION = 895;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = YES;
@@ -4672,7 +4680,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 894;
CURRENT_PROJECT_VERSION = 895;
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
ENABLE_BITCODE = YES;
ENABLE_PREVIEWS = YES;
@@ -4786,7 +4794,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 894;
CURRENT_PROJECT_VERSION = 895;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
ENABLE_BITCODE = YES;

View File

@@ -0,0 +1,23 @@
#include "characteristicnotifier1224.h"
#include "devices/elliptical.h"
#include "devices/rower.h"
#include "devices/treadmill.h"
#include <QSettings>
static uint8_t sequenceChar1224 = 0;
CharacteristicNotifier1224::CharacteristicNotifier1224(bluetoothdevice *Bike, QObject *parent)
: CharacteristicNotifier(0x2ad2, parent), Bike(Bike) {}
int CharacteristicNotifier1224::notify(QByteArray &value) {
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
++sequenceChar1224;
value.append((char)sequenceChar1224);
value.append((char)0x03);
value.append((char)(0xb6));
value.append((char)(0x01));
return CN_OK;
}

View File

@@ -0,0 +1,15 @@
#ifndef CHARACTERISTICNOTIFIER1224_H
#define CHARACTERISTICNOTIFIER1224_H
#include "devices/bluetoothdevice.h"
#include "characteristicnotifier.h"
class CharacteristicNotifier1224 : public CharacteristicNotifier {
bluetoothdevice *Bike;
public:
explicit CharacteristicNotifier1224(bluetoothdevice *Bike, QObject *parent = nullptr);
int notify(QByteArray &out) override;
};
#endif // CHARACTERISTICNOTIFIER1224_H

View File

@@ -1,6 +1,7 @@
#include "devices/bike.h"
#include "qdebugfixup.h"
#include "homeform.h"
#include <QSettings>
bike::bike() { elapsed.setType(metric::METRIC_ELAPSED); }
@@ -105,6 +106,9 @@ void bike::setGears(double gears) {
qDebug() << "new gear value ignored because of gears_zwift_ratio setting!";
return;
}
if(homeform::singleton()) {
homeform::singleton()->gears->setValue(QString::number(gears, 'f', 0));
}
m_gears = gears;
settings.setValue(QZSettings::gears_current_value, m_gears);
if (lastRawRequestedResistanceValue != -1) {

View File

@@ -10,6 +10,7 @@ using namespace std::chrono_literals;
#define DM_SERV_OP(OP, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x1826, WAHOO_KICKR, P1, P2, P3) \
OP(WATTBIKEATOM, 0x1223, WAHOO_KICKR, P1, P2, P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x1826, WAHOO_TREADMILL, P1, P2, P3) \
OP(CYCLING_POWER, 0x1818, WAHOO_KICKR, P1, P2, P3) \
OP(CYCLING_SPEED_AND_CADENCE, 0x1816, WAHOO_KICKR, P1, P2, P3) \
@@ -41,6 +42,8 @@ using namespace std::chrono_literals;
OP(FITNESS_MACHINE_CYCLE, 0xE005, DPKT_CHAR_PROP_FLAG_WRITE, DM_BT("\x00"), DP_PROCESS_WRITE_E005, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD2, DPKT_CHAR_PROP_FLAG_NOTIFY, DM_BT("\x00"), DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_CYCLE, 0x2AD3, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x00\x01"), DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(WATTBIKEATOM, 0x1225, DPKT_CHAR_PROP_FLAG_WRITE, DM_BT("\x00"), DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(WATTBIKEATOM, 0x1224, DPKT_CHAR_PROP_FLAG_NOTIFY, DM_BT("\x00"), DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x2ACC, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x08\x14\x00\x00\x00\x00\x00\x00"), \
DP_PROCESS_WRITE_NULL, P1, P2, P3) \
OP(FITNESS_MACHINE_TREADMILL, 0x2AD6, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x0A\x00\x96\x00\x0A\x00"), \

View File

@@ -10,6 +10,7 @@
#include "characteristics/characteristicnotifier2acd.h"
#include "characteristics/characteristicnotifier2ad2.h"
#include "characteristics/characteristicnotifier2ad9.h"
#include "characteristics/characteristicnotifier1224.h"
#include "characteristics/characteristicwriteprocessor2ad9.h"
#include "characteristics/characteristicwriteprocessore005.h"
#include "devices/dircon/dirconpacket.h"
@@ -20,7 +21,7 @@
OP(2AD2, P1, P2, P3) \
OP(2A63, P1, P2, P3) \
OP(2A37, P1, P2, P3) OP(2A5B, P1, P2, P3) OP(2A53, P1, P2, P3) OP(2ACD, P1, P2, P3) OP(2ACC, P1, P2, P3) \
OP(2AD9, P1, P2, P3)
OP(2AD9, P1, P2, P3) OP(1224, P1, P2, P3)
#define DM_CHAR_NOTIF_DEFINE_OP(UUID, P1, P2, P3) CharacteristicNotifier##UUID *notif##UUID = 0;

View File

@@ -196,6 +196,7 @@ class homeform : public QObject {
public:
static homeform *singleton() { return m_singleton; }
bluetooth *bluetoothManager;
QByteArray currentPelotonImage();
Q_INVOKABLE void save_screenshot() {
@@ -677,7 +678,6 @@ class homeform : public QObject {
TemplateInfoSenderBuilder *innerTemplateManager = nullptr;
QList<QObject *> dataList;
QList<SessionLine> Session;
bluetooth *bluetoothManager;
QQmlApplicationEngine *engine;
trainprogram *trainProgram = nullptr;
trainprogram *previewTrainProgram = nullptr;

View File

@@ -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!

View File

@@ -25,7 +25,7 @@ class lockscreen {
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

View File

@@ -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;
}

View File

@@ -13,7 +13,9 @@
@interface swiftDebug : NSObject
- (void)qtDebug:(NSString *)inputString;;
- (void)qtDebug:(NSString *)inputString;
- (void)gearUp;
- (void)gearDown;
@end

View File

@@ -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

View File

@@ -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;
}
@@ -84,6 +85,7 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
public var CurrentCadence: UInt16! = 0
public var CurrentResistance: UInt8! = 0
public var CurrentWatt: UInt16! = 0
public var CurrentZwiftGear: UInt8! = 12
private var CSCService: CBMutableService!
private var CSCFeatureCharacteristic: CBMutableCharacteristic!
@@ -98,16 +100,25 @@ 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?
@@ -254,12 +265,52 @@ class BLEPeripheralManagerZwift: NSObject, CBPeripheralManagerDelegate {
PowerMeasurementCharacteristic]
self.peripheralManager.add(PowerService)
// ZwiftPlay
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 +348,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 +379,204 @@ 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 {
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) {
SwiftDebug.gearDown();
} else if(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 +728,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)
{
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)

2
src/qdomyos-zwift.pri Executable file → Normal file
View File

@@ -75,6 +75,7 @@ DEFINES += QT_DEPRECATED_WARNINGS IO_UNDER_QT SMTP_BUILD NOMINMAX
# include(../qtzeroconf/qtzeroconf.pri)
SOURCES += \
$$PWD/characteristics/characteristicnotifier1224.cpp \
$$PWD/devices/antbike/antbike.cpp \
$$PWD/devices/crossrope/crossrope.cpp \
$$PWD/devices/deeruntreadmill/deerruntreadmill.cpp \
@@ -301,6 +302,7 @@ else: unix:!android: target.path = /opt/$${TARGET}/bin
INCLUDEPATH += fit-sdk/ devices/
HEADERS += \
$$PWD/characteristics/characteristicnotifier1224.h \
$$PWD/CRC16IBM.h \
$$PWD/EventHandler.h \
$$PWD/devices/antbike/antbike.h \

View File

@@ -45,6 +45,7 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
notif2AD9 = new CharacteristicNotifier2AD9(Bike, this);
notif2A63 = new CharacteristicNotifier2A63(Bike, this);
notif2A37 = new CharacteristicNotifier2A37(Bike, this);
notif1224 = new CharacteristicNotifier1224(Bike, this);
notif2A5B = new CharacteristicNotifier2A5B(Bike, this);
writeP2AD9 = new CharacteristicWriteProcessor2AD9(bikeResistanceGain, bikeResistanceOffset, Bike, notif2AD9, this);
connect(writeP2AD9, SIGNAL(changeInclination(double, double)), this, SIGNAL(changeInclination(double, double)));
@@ -196,6 +197,31 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
serviceDataFIT.addCharacteristic(charDataFIT4);
serviceDataFIT.addCharacteristic(charDataFIT5);
serviceDataFIT.addCharacteristic(charDataFIT6);
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 +419,8 @@ virtualbike::virtualbike(bluetoothdevice *t, bool noWriteResistance, bool noHear
if (!cadence && !power) {
serviceFIT = leController->addService(serviceDataFIT);
QThread::msleep(100); // give time to Android to add the service async.ly
serviceZwiftPlayBike = leController->addService(serviceDataZwiftPlayBike);
} else {
service = leController->addService(serviceData);
}
@@ -420,6 +448,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);
@@ -474,14 +504,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 +830,62 @@ void virtualbike::characteristicChanged(const QLowEnergyCharacteristic &characte
}
}
//********************ZWIFT PLAY**************
if(characteristic.uuid().toString().contains(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1"))) {
const QByteArray expectedHexArray = QByteArray::fromHex("526964654F6E0201");
const QByteArray expectedHexArray2 = QByteArray::fromHex("000800");
const QByteArray expectedHexArray3 = QByteArray::fromHex("00088804");
const QByteArray expectedHexArray4 = QByteArray::fromHex("042a0a10c0bb0120bf0628b442");
QByteArray receivedBytes = newValue.left(expectedHexArray.size());
QLowEnergyCharacteristic characteristic =
serviceZwiftPlayBike->characteristic(QBluetoothUuid(QStringLiteral("00000002-19ca-4651-86e5-fa29dcdd09d1")));
QLowEnergyCharacteristic characteristicIndicate =
serviceZwiftPlayBike->characteristic(QBluetoothUuid(QStringLiteral("00000004-19ca-4651-86e5-fa29dcdd09d1")));
if (receivedBytes == expectedHexArray) {
qDebug() << "Zwift Play Ask 1";
QByteArray response = QByteArray::fromHex("2a08031211220f4154582030342c2053545820303400");
writeCharacteristic(serviceZwiftPlayBike, characteristic, response);
response = QByteArray::fromHex("2a0803120d220b524944455f4f4e28322900");
writeCharacteristic(serviceZwiftPlayBike, characteristic, response);
response = QByteArray::fromHex("526964654f6e0200");
writeCharacteristic(serviceZwiftPlayBike, characteristicIndicate, response);
}
QByteArray receivedBytes2 = newValue.left(expectedHexArray2.size());
if (receivedBytes2 == expectedHexArray2) {
qDebug() << "Zwift Play Ask 2";
QByteArray response = QByteArray::fromHex("3c080012320a3008800412040500050110a0b4b4c4b52000320f3430323431383030393834000000003a0131420408011014");
writeCharacteristic(serviceZwiftPlayBike, characteristicIndicate, response);
}
QByteArray receivedBytes3 = newValue.left(expectedHexArray3.size());
if (receivedBytes3 == expectedHexArray3) {
qDebug() << "Zwift Play Ask 3";
QByteArray response = QByteArray::fromHex("3c08880412060a0440c0bb01");
writeCharacteristic(serviceZwiftPlayBike, characteristicIndicate, response);
}
QByteArray receivedBytes4 = newValue.left(expectedHexArray4.size());
if (receivedBytes4 == expectedHexArray4) {
qDebug() << "Zwift Play Ask 4";
QByteArray response = QByteArray::fromHex("03080010001859200028003097ed01");
writeCharacteristic(serviceZwiftPlayBike, characteristic, response);
}
}
//******************** ECHELON ***************
if (characteristic.uuid().toString().contains(QStringLiteral("0bf669f2-45f2-11e7-9598-0800200c9a66"))) {
QLowEnergyCharacteristic characteristic =
@@ -1019,6 +1104,9 @@ void virtualbike::reconnect() {
if (!cadence && !power) {
serviceFIT = leController->addService(serviceDataFIT);
QThread::msleep(100); // give time to Android to add the service async.ly
serviceZwiftPlayBike = leController->addService(serviceDataZwiftPlayBike);
} else {
service = leController->addService(serviceData);
}
@@ -1070,7 +1158,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 +1245,12 @@ void virtualbike::bikeProvider() {
return;
}
writeCharacteristic(serviceFIT, characteristic, value);
QLowEnergyCharacteristic characteristic1 =
serviceZwiftPlayBike->characteristic(QBluetoothUuid(QStringLiteral("00000002-19ca-4651-86e5-fa29dcdd09d1")));
const uint8_t v[] = {0x03, 0x08, 0x00, 0x10, 0x00, 0x18, 0x59, 0x20, 0x00, 0x28, 0x00, 0x30, 0x9b, 0xed, 0x01};
value = QByteArray::fromRawData((char*)v, 15);
writeCharacteristic(serviceZwiftPlayBike, characteristic1, value);
}
} else if (power) {
value.clear();

View File

@@ -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;
@@ -65,6 +67,7 @@ class virtualbike : public virtualdevice {
CharacteristicNotifier2A63 *notif2A63 = 0;
CharacteristicNotifier2A37 *notif2A37 = 0;
CharacteristicNotifier2A5B *notif2A5B = 0;
CharacteristicNotifier1224 *notif1224 = 0;
qint64 lastFTMSFrameReceived = 0;
qint64 lastDirconFTMSFrameReceived = 0;