mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
44 Commits
android_5_
...
build-895
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
@@ -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;
|
||||
|
||||
23
src/characteristics/characteristicnotifier1224.cpp
Normal file
23
src/characteristics/characteristicnotifier1224.cpp
Normal 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;
|
||||
}
|
||||
15
src/characteristics/characteristicnotifier1224.h
Normal file
15
src/characteristics/characteristicnotifier1224.h
Normal 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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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"), \
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
2
src/qdomyos-zwift.pri
Executable file → Normal 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 \
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user