mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
334 Commits
android_ap
...
android_pi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
215b9897dd | ||
|
|
bb7dc3f4e9 | ||
|
|
e9c383ce8b | ||
|
|
395973b0ae | ||
|
|
8cdbc8463a | ||
|
|
9f1d6a163f | ||
|
|
44b304bcf7 | ||
|
|
b0bea930e0 | ||
|
|
6ce71c69f6 | ||
|
|
1bf665ae98 | ||
|
|
a3e6cbd416 | ||
|
|
c2ef787a74 | ||
|
|
c00f2a81ca | ||
|
|
b4164cd10f | ||
|
|
f95a0510c7 | ||
|
|
b6c5099e07 | ||
|
|
bc26307c63 | ||
|
|
ee0b7993de | ||
|
|
93a6a352a1 | ||
|
|
1e98454070 | ||
|
|
a90d3f227f | ||
|
|
0ad5ca8651 | ||
|
|
8daf02afb6 | ||
|
|
422bf4144f | ||
|
|
57455ee7d6 | ||
|
|
032636b3b6 | ||
|
|
536067d731 | ||
|
|
9aaa1a0d18 | ||
|
|
17db301d5d | ||
|
|
0e4945f15b | ||
|
|
94ba539de4 | ||
|
|
9c9d540585 | ||
|
|
9f6e54dfc4 | ||
|
|
3b1d24381e | ||
|
|
563e7708f0 | ||
|
|
5127420097 | ||
|
|
9202958a39 | ||
|
|
c2ca7a06fe | ||
|
|
0a852644bc | ||
|
|
fd32d29c87 | ||
|
|
c4c1091147 | ||
|
|
fd15b1ac4f | ||
|
|
7b53ee0dc9 | ||
|
|
59fc9864ec | ||
|
|
c59e8a0079 | ||
|
|
96ff845abe | ||
|
|
62f504bdc7 | ||
|
|
8113bccb77 | ||
|
|
ab14cbfa49 | ||
|
|
ee252a313d | ||
|
|
293ff2eda1 | ||
|
|
f084b88312 | ||
|
|
bc9c36624a | ||
|
|
b49af71c2e | ||
|
|
118684ebff | ||
|
|
9e8c8322e3 | ||
|
|
cce52fcdfa | ||
|
|
e29b7f1356 | ||
|
|
036f0c4fc9 | ||
|
|
2ff9cdeba6 | ||
|
|
1b7e61e77a | ||
|
|
5affe4b687 | ||
|
|
5f6d3cc7f3 | ||
|
|
c651c682c3 | ||
|
|
6163b967f7 | ||
|
|
0c1c25823c | ||
|
|
30046c8177 | ||
|
|
c893180e4d | ||
|
|
5d49fa8174 | ||
|
|
e0f8c30a94 | ||
|
|
a4b7eb7ebb | ||
|
|
ee3067baa0 | ||
|
|
73a1d8dbb6 | ||
|
|
63f778c32d | ||
|
|
9d50363a9c | ||
|
|
7dc112b6f5 | ||
|
|
3b1a478822 | ||
|
|
e114745d5f | ||
|
|
a18818d5fe | ||
|
|
c5fdf4a9bf | ||
|
|
f45610343b | ||
|
|
f45dd3bfed | ||
|
|
5d0f0138a5 | ||
|
|
827285ede0 | ||
|
|
df759a14a1 | ||
|
|
2b38d4fbe3 | ||
|
|
2dccd4016a | ||
|
|
06ccf9136b | ||
|
|
66e3420abc | ||
|
|
650fc81c6d | ||
|
|
dff786dd2a | ||
|
|
78bc2b2d97 | ||
|
|
bd79b30eda | ||
|
|
2a6a4e3db8 | ||
|
|
8af33b0845 | ||
|
|
cdb09471b1 | ||
|
|
f5c7b1d891 | ||
|
|
7908420622 | ||
|
|
e0ba6e6f08 | ||
|
|
c9cb0e5728 | ||
|
|
43c263bd22 | ||
|
|
1f38aee4d0 | ||
|
|
424d98cb80 | ||
|
|
8869913c4e | ||
|
|
69d9b23b6e | ||
|
|
c9b215ff44 | ||
|
|
ee8c66d3e8 | ||
|
|
c2589f7f26 | ||
|
|
8dd3ff6340 | ||
|
|
82e075798c | ||
|
|
732e84d2e3 | ||
|
|
c2d0176b67 | ||
|
|
01ef11496d | ||
|
|
0c768a4943 | ||
|
|
9e63e31954 | ||
|
|
c7efa0e5ad | ||
|
|
0b9de9509c | ||
|
|
92dbbcaf5a | ||
|
|
d8951ab83e | ||
|
|
a4bd3cfd6e | ||
|
|
83637aa626 | ||
|
|
f65ecd3df7 | ||
|
|
7e11c740ac | ||
|
|
7b4102964e | ||
|
|
c706b2db71 | ||
|
|
70f5b627d1 | ||
|
|
547bd51673 | ||
|
|
b42f684bbf | ||
|
|
8434cebdc7 | ||
|
|
9f7886af58 | ||
|
|
82f3cf227d | ||
|
|
8708bb76cc | ||
|
|
3a23d6798a | ||
|
|
9d3457b53c | ||
|
|
e0f5c90d93 | ||
|
|
46d2d0c346 | ||
|
|
dc2876f80a | ||
|
|
73767d68fe | ||
|
|
ee840abd5e | ||
|
|
31d401a1df | ||
|
|
05a0184f03 | ||
|
|
1707f7c8ff | ||
|
|
c0b4ea071e | ||
|
|
7a2528d007 | ||
|
|
1a37a4c3b2 | ||
|
|
ed1568c583 | ||
|
|
69d95ee27d | ||
|
|
1cfb556e6c | ||
|
|
20a0b9e968 | ||
|
|
57dd826033 | ||
|
|
fe7e259db3 | ||
|
|
88ba5a5239 | ||
|
|
bbd586895a | ||
|
|
ae1d25208e | ||
|
|
2b19896498 | ||
|
|
ea6c5c1190 | ||
|
|
50bb52c15c | ||
|
|
be4454563b | ||
|
|
0ac29a4470 | ||
|
|
136c807f16 | ||
|
|
c74e3545d4 | ||
|
|
a05345264c | ||
|
|
92c10f3042 | ||
|
|
76935090a4 | ||
|
|
2b0accb933 | ||
|
|
26e2146051 | ||
|
|
f552f27224 | ||
|
|
05deaa76fc | ||
|
|
8d79fb3f35 | ||
|
|
ec748b695e | ||
|
|
8618384bb6 | ||
|
|
11e1117611 | ||
|
|
ba08f656fe | ||
|
|
af875a7295 | ||
|
|
56e38e650a | ||
|
|
3b75f4fa94 | ||
|
|
7e18946909 | ||
|
|
6edde653b6 | ||
|
|
caedc73901 | ||
|
|
19e552f4cd | ||
|
|
6dc46aa689 | ||
|
|
2cce91beea | ||
|
|
4824b65590 | ||
|
|
f327d13252 | ||
|
|
e1a4bbb19a | ||
|
|
e11d4610a9 | ||
|
|
68d1eb678f | ||
|
|
95d1f1fd8e | ||
|
|
ceaa5f0fa2 | ||
|
|
efede4bee0 | ||
|
|
18787431a6 | ||
|
|
e30e3c85e3 | ||
|
|
e5724b43db | ||
|
|
2428b4c230 | ||
|
|
cf111ab23c | ||
|
|
3c37f1d77b | ||
|
|
e0a79b51d3 | ||
|
|
5de8e7f1d8 | ||
|
|
45ddd78624 | ||
|
|
b47d605999 | ||
|
|
b2ea235729 | ||
|
|
875764ac5c | ||
|
|
832fd25edb | ||
|
|
c526d4e675 | ||
|
|
bb8e0f0417 | ||
|
|
9cbf72d594 | ||
|
|
df65f0d951 | ||
|
|
2325635b28 | ||
|
|
1d9c24ba91 | ||
|
|
39ba7402d7 | ||
|
|
4e29df685a | ||
|
|
d1f5afce4c | ||
|
|
641783d90a | ||
|
|
7f6cdf82cf | ||
|
|
6e414f8e02 | ||
|
|
5f41e9a08d | ||
|
|
115cbc0fa1 | ||
|
|
a702d7e4c3 | ||
|
|
cbe3f7de78 | ||
|
|
0803236439 | ||
|
|
5c8c8881e0 | ||
|
|
1bbca34ca5 | ||
|
|
37e98fa0a6 | ||
|
|
9498aa5501 | ||
|
|
e659322a0b | ||
|
|
b74a5b3f8b | ||
|
|
6e2541d1b7 | ||
|
|
647717cd73 | ||
|
|
56a09fad21 | ||
|
|
b156396d1c | ||
|
|
ae1f099703 | ||
|
|
07d62ed9ad | ||
|
|
a8cf95380c | ||
|
|
48f2d479a3 | ||
|
|
67515b94c9 | ||
|
|
f1b05c5975 | ||
|
|
2e1d3b03c7 | ||
|
|
79e3be71ca | ||
|
|
82717a6775 | ||
|
|
1f0582e0d0 | ||
|
|
f4b9be340f | ||
|
|
43d6e6c233 | ||
|
|
2e608cae22 | ||
|
|
0d8dd957ad | ||
|
|
810391f03b | ||
|
|
386484d03b | ||
|
|
2c2436a430 | ||
|
|
06c178cbff | ||
|
|
ce22fef00d | ||
|
|
4c49918a97 | ||
|
|
88344438a7 | ||
|
|
09d8881b43 | ||
|
|
83fe4e19ec | ||
|
|
5733889e8a | ||
|
|
5895f5cc7c | ||
|
|
94830044f6 | ||
|
|
3200cf2b28 | ||
|
|
38cb8f4ccd | ||
|
|
73a20b9980 | ||
|
|
57b06c2143 | ||
|
|
583ab09dc4 | ||
|
|
67a5f8612f | ||
|
|
14c91a308b | ||
|
|
8995cf866c | ||
|
|
3808619f3e | ||
|
|
3206a28199 | ||
|
|
216e6874b2 | ||
|
|
28aaf7fbff | ||
|
|
55d4467886 | ||
|
|
f1887b7ea1 | ||
|
|
a8bc82c2d0 | ||
|
|
3b2dcaef43 | ||
|
|
cd217d4f38 | ||
|
|
c5e113bd20 | ||
|
|
d63eafe0b3 | ||
|
|
ea69aa2251 | ||
|
|
e697842df7 | ||
|
|
909bc2dbc5 | ||
|
|
d152c5d9c6 | ||
|
|
dad642e82d | ||
|
|
c3d757a872 | ||
|
|
a1cd69d68f | ||
|
|
cd6edddea0 | ||
|
|
22a8352963 | ||
|
|
997b04ee54 | ||
|
|
835b1c3956 | ||
|
|
097e23d20b | ||
|
|
51e55a81e7 | ||
|
|
95eeae56cc | ||
|
|
90278bd6b2 | ||
|
|
32c0019f89 | ||
|
|
f8df2c580b | ||
|
|
38dce24e26 | ||
|
|
5bfa16ace1 | ||
|
|
7b0819dce2 | ||
|
|
c349e3d6e4 | ||
|
|
e6a3ce0d3c | ||
|
|
85f8d4454f | ||
|
|
3ea6780fe7 | ||
|
|
8c2598f2c6 | ||
|
|
6c987ef4bf | ||
|
|
970915996a | ||
|
|
7159812dbc | ||
|
|
515ec1605b | ||
|
|
00802d1374 | ||
|
|
428f07dc6f | ||
|
|
dcfb1f9588 | ||
|
|
5736cc6a97 | ||
|
|
146ebd156c | ||
|
|
0ad2c37dcb | ||
|
|
253244abda | ||
|
|
0ac3d3e944 | ||
|
|
c6b1398aa9 | ||
|
|
4ba6862c61 | ||
|
|
9066c4e02a | ||
|
|
9349996989 | ||
|
|
da5157970a | ||
|
|
28efbcdd9b | ||
|
|
10200c1e29 | ||
|
|
e37e0853d1 | ||
|
|
4b464ba041 | ||
|
|
ff7863a25c | ||
|
|
72af1701a2 | ||
|
|
487ff2e8e9 | ||
|
|
6cda7cd02c | ||
|
|
77b34e2f41 | ||
|
|
0e27c87480 | ||
|
|
fb1bac5e5e | ||
|
|
27ea164da1 | ||
|
|
2ec9abc4ad | ||
|
|
bb1d903e07 | ||
|
|
9ccb1ef5d5 | ||
|
|
065ee078a2 | ||
|
|
8b876ac17f |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -7,6 +7,6 @@ ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
issuehunt: cagnulein
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: ['https://www.buymeacoffee.com/cagnulein'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
||||
|
||||
2
.github/workflows/main.yml
vendored
2
.github/workflows/main.yml
vendored
@@ -142,7 +142,7 @@ jobs:
|
||||
ref: "zwift"
|
||||
|
||||
- name: Install packages required to run QZ inside workflow
|
||||
run: sudo apt update -y && sudo apt-get install -y qt5-default qtquickcontrols2-5-dev libqt5bluetooth5 libqt5widgets5 libqt5positioning5 libqt5xml5 qtconnectivity5-dev qtpositioning5-dev libqt5charts5-dev libqt5charts5 qt5-default libqt5networkauth5-dev libqt5websockets5* libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev
|
||||
run: sudo apt update -y && sudo apt-get install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtquickcontrols2-5-dev libqt5bluetooth5 libqt5widgets5 libqt5positioning5 libqt5xml5 qtconnectivity5-dev qtpositioning5-dev libqt5charts5-dev libqt5charts5 libqt5networkauth5-dev libqt5websockets5* libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v2
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -45,3 +45,4 @@ template-examples/train-program-saver/debug.js
|
||||
*build-*
|
||||
!build-qdomyos-zwift-Qt_*_for_iOS-Debug # Needed for Apple Watch
|
||||
src/inner_templates/googlemaps/cesium-key.js
|
||||
*.autosave
|
||||
|
||||
@@ -167,6 +167,8 @@
|
||||
872261F0289EA887006A6F75 /* moc_nordictrackelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872261EF289EA887006A6F75 /* moc_nordictrackelliptical.cpp */; };
|
||||
8727A47727849EA600019B5D /* paferstreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727A47627849EA600019B5D /* paferstreadmill.cpp */; };
|
||||
8727A47927849EB200019B5D /* moc_paferstreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727A47827849EB200019B5D /* moc_paferstreadmill.cpp */; };
|
||||
872A20DA28C5EC380037774D /* faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20D928C5EC380037774D /* faketreadmill.cpp */; };
|
||||
872A20DC28C5F5CE0037774D /* moc_faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */; };
|
||||
872BAB4E261750EE006A59AB /* libQt5Charts.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 872BAB4D261750EE006A59AB /* libQt5Charts.a */; };
|
||||
872BAB50261751FB006A59AB /* libqtchartsqml2.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 872BAB4F261751FB006A59AB /* libqtchartsqml2.a */; };
|
||||
873063BE259DF20000DA0F44 /* heartratebelt.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873063BC259DF20000DA0F44 /* heartratebelt.cpp */; };
|
||||
@@ -259,6 +261,7 @@
|
||||
8762D5132601F89500F6F049 /* scanrecordresult.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8762D5112601F89500F6F049 /* scanrecordresult.cpp */; };
|
||||
87646C2027B5064600F82131 /* bhfitnesselliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87646C1E27B5064500F82131 /* bhfitnesselliptical.cpp */; };
|
||||
87646C2227B5065100F82131 /* moc_bhfitnesselliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87646C2127B5065100F82131 /* moc_bhfitnesselliptical.cpp */; };
|
||||
8767EF1E29448D6700810C0F /* characteristicwriteprocessor.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8767EF1D29448D6700810C0F /* characteristicwriteprocessor.cpp */; };
|
||||
8768D1FB285081FE00F58E3A /* nordictrackifitadbtreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8768D1F9285081FE00F58E3A /* nordictrackifitadbtreadmill.cpp */; };
|
||||
8768D1FD2850820B00F58E3A /* moc_nordictrackifitadbtreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8768D1FC2850820B00F58E3A /* moc_nordictrackifitadbtreadmill.cpp */; };
|
||||
876BFC9C27BE35C5001D7645 /* proformelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876BFC9827BE35C4001D7645 /* proformelliptical.cpp */; };
|
||||
@@ -314,6 +317,10 @@
|
||||
87900DC8268B673C000CB351 /* moc_renphobike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87900DC7268B673C000CB351 /* moc_renphobike.cpp */; };
|
||||
8790FDDF277B0ABA00247550 /* nautilustreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8790FDDD277B0ABA00247550 /* nautilustreadmill.cpp */; };
|
||||
8790FDE1277B0AC600247550 /* moc_nautilustreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8790FDE0277B0AC600247550 /* moc_nautilustreadmill.cpp */; };
|
||||
87917A7328E768D200F8D9AC /* Browser.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87917A6E28E768D200F8D9AC /* Browser.swift */; };
|
||||
87917A7528E768D200F8D9AC /* Connection.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87917A7028E768D200F8D9AC /* Connection.swift */; };
|
||||
87917A7628E768D200F8D9AC /* Server.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87917A7128E768D200F8D9AC /* Server.swift */; };
|
||||
87917A7728E768D200F8D9AC /* Client.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87917A7228E768D200F8D9AC /* Client.swift */; };
|
||||
8791A8AA25C8603F003B50B2 /* moc_inspirebike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8791A8A925C8603F003B50B2 /* moc_inspirebike.cpp */; };
|
||||
8791A8AB25C861BD003B50B2 /* inspirebike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8791A8A825C8602A003B50B2 /* inspirebike.cpp */; };
|
||||
87958F1927628D4500124B24 /* elitesterzosmart.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87958F1827628D4500124B24 /* elitesterzosmart.cpp */; };
|
||||
@@ -389,6 +396,10 @@
|
||||
87CC3B9E25A08812001EC5A8 /* moc_elliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87CC3B9C25A08812001EC5A8 /* moc_elliptical.cpp */; };
|
||||
87CC3BA325A0885F001EC5A8 /* domyoselliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87CC3B9F25A0885D001EC5A8 /* domyoselliptical.cpp */; };
|
||||
87CC3BA425A0885F001EC5A8 /* elliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87CC3BA025A0885D001EC5A8 /* elliptical.cpp */; };
|
||||
87CF5169293C879800A7CABC /* characteristicwriteprocessore005.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87CF5167293C879700A7CABC /* characteristicwriteprocessore005.cpp */; };
|
||||
87CF516B293C87B000A7CABC /* moc_characteristicwriteprocessore005.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87CF516A293C87AF00A7CABC /* moc_characteristicwriteprocessore005.cpp */; };
|
||||
87D10552290996EA00B3935B /* mepanelbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D10550290996EA00B3935B /* mepanelbike.cpp */; };
|
||||
87D105542909971100B3935B /* moc_mepanelbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D105532909971100B3935B /* moc_mepanelbike.cpp */; };
|
||||
87D2699F25F535200076AA48 /* m3ibike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D2699A25F535160076AA48 /* m3ibike.cpp */; };
|
||||
87D269A025F535200076AA48 /* skandikawiribike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D2699D25F535180076AA48 /* skandikawiribike.cpp */; };
|
||||
87D269A325F535340076AA48 /* moc_skandikawiribike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D269A125F535300076AA48 /* moc_skandikawiribike.cpp */; };
|
||||
@@ -414,6 +425,8 @@
|
||||
87DF68BF25E2675100FCDA46 /* moc_schwinnic4bike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87DF68BC25E2675100FCDA46 /* moc_schwinnic4bike.cpp */; };
|
||||
87E0761D277A081A00FDA0F9 /* technogymmyruntreadmillrfcomm.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E0761B277A081900FDA0F9 /* technogymmyruntreadmillrfcomm.cpp */; };
|
||||
87E0761F277A082300FDA0F9 /* moc_technogymmyruntreadmillrfcomm.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E0761E277A082300FDA0F9 /* moc_technogymmyruntreadmillrfcomm.cpp */; };
|
||||
87E2F85D291ED308002BDC65 /* lifefitnesstreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E2F85C291ED308002BDC65 /* lifefitnesstreadmill.cpp */; };
|
||||
87E2F85F291ED315002BDC65 /* moc_lifefitnesstreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E2F85E291ED315002BDC65 /* moc_lifefitnesstreadmill.cpp */; };
|
||||
87E34C2B2886F95400CEDE4B /* octanetreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E34C2A2886F95400CEDE4B /* octanetreadmill.cpp */; };
|
||||
87E34C2D2886F99A00CEDE4B /* moc_octanetreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E34C2C2886F99900CEDE4B /* moc_octanetreadmill.cpp */; };
|
||||
87E5D2C625E69F3100BDBE6C /* horizontreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87E5D2C525E69F3100BDBE6C /* horizontreadmill.cpp */; };
|
||||
@@ -433,7 +446,10 @@
|
||||
87EFB57025BD704A0039DD5A /* moc_proformtreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87EFB56F25BD704A0039DD5A /* moc_proformtreadmill.cpp */; };
|
||||
87EFE45927A518F5006EA1C3 /* nautiluselliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87EFE45827A518F5006EA1C3 /* nautiluselliptical.cpp */; };
|
||||
87EFE45B27A51901006EA1C3 /* moc_nautiluselliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87EFE45A27A51900006EA1C3 /* moc_nautiluselliptical.cpp */; };
|
||||
87F02E4029178524000DB52C /* octaneelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F02E3E29178523000DB52C /* octaneelliptical.cpp */; };
|
||||
87F02E4229178545000DB52C /* moc_octaneelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F02E4129178545000DB52C /* moc_octaneelliptical.cpp */; };
|
||||
87F1179E26A5FBDE00541B3A /* libqtwebview_darwin.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 87420DF7269D7CE1000C5EC6 /* libqtwebview_darwin.a */; };
|
||||
87F527BE28EEB5AA00A9F8D5 /* qzsettings.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F527BC28EEB5AA00A9F8D5 /* qzsettings.cpp */; };
|
||||
87F93427278E0EC00088B596 /* domyosrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F93426278E0EC00088B596 /* domyosrower.cpp */; };
|
||||
87F93429278E0ECF0088B596 /* moc_domyosrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F93428278E0ECF0088B596 /* moc_domyosrower.cpp */; };
|
||||
87FA11AB27C5ECD1008AC5D1 /* ultrasportbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87FA11AA27C5ECD1008AC5D1 /* ultrasportbike.cpp */; };
|
||||
@@ -833,6 +849,9 @@
|
||||
8727A47527849EA600019B5D /* paferstreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = paferstreadmill.h; path = ../src/paferstreadmill.h; sourceTree = "<group>"; };
|
||||
8727A47627849EA600019B5D /* paferstreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = paferstreadmill.cpp; path = ../src/paferstreadmill.cpp; sourceTree = "<group>"; };
|
||||
8727A47827849EB200019B5D /* moc_paferstreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_paferstreadmill.cpp; sourceTree = "<group>"; };
|
||||
872A20D828C5EC380037774D /* faketreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = faketreadmill.h; path = ../src/faketreadmill.h; sourceTree = "<group>"; };
|
||||
872A20D928C5EC380037774D /* faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = faketreadmill.cpp; path = ../src/faketreadmill.cpp; sourceTree = "<group>"; };
|
||||
872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_faketreadmill.cpp; sourceTree = "<group>"; };
|
||||
872BAB4D261750EE006A59AB /* libQt5Charts.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libQt5Charts.a; path = ../../Qt/5.15.2/ios/lib/libQt5Charts.a; sourceTree = "<group>"; };
|
||||
872BAB4F261751FB006A59AB /* libqtchartsqml2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libqtchartsqml2.a; path = ../../Qt/5.15.2/ios/qml/QtCharts/libqtchartsqml2.a; sourceTree = "<group>"; };
|
||||
873063BC259DF20000DA0F44 /* heartratebelt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = heartratebelt.cpp; path = ../src/heartratebelt.cpp; sourceTree = "<group>"; };
|
||||
@@ -972,6 +991,7 @@
|
||||
87646C1E27B5064500F82131 /* bhfitnesselliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bhfitnesselliptical.cpp; path = ../src/bhfitnesselliptical.cpp; sourceTree = "<group>"; };
|
||||
87646C1F27B5064500F82131 /* bhfitnesselliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bhfitnesselliptical.h; path = ../src/bhfitnesselliptical.h; sourceTree = "<group>"; };
|
||||
87646C2127B5065100F82131 /* moc_bhfitnesselliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_bhfitnesselliptical.cpp; sourceTree = "<group>"; };
|
||||
8767EF1D29448D6700810C0F /* characteristicwriteprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = characteristicwriteprocessor.cpp; path = ../src/characteristicwriteprocessor.cpp; sourceTree = "<group>"; };
|
||||
8768D1F9285081FE00F58E3A /* nordictrackifitadbtreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nordictrackifitadbtreadmill.cpp; path = ../src/nordictrackifitadbtreadmill.cpp; sourceTree = "<group>"; };
|
||||
8768D1FA285081FE00F58E3A /* nordictrackifitadbtreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nordictrackifitadbtreadmill.h; path = ../src/nordictrackifitadbtreadmill.h; sourceTree = "<group>"; };
|
||||
8768D1FC2850820B00F58E3A /* moc_nordictrackifitadbtreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_nordictrackifitadbtreadmill.cpp; sourceTree = "<group>"; };
|
||||
@@ -1059,6 +1079,10 @@
|
||||
8790FDDD277B0ABA00247550 /* nautilustreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nautilustreadmill.cpp; path = ../src/nautilustreadmill.cpp; sourceTree = "<group>"; };
|
||||
8790FDDE277B0ABA00247550 /* nautilustreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nautilustreadmill.h; path = ../src/nautilustreadmill.h; sourceTree = "<group>"; };
|
||||
8790FDE0277B0AC600247550 /* moc_nautilustreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_nautilustreadmill.cpp; sourceTree = "<group>"; };
|
||||
87917A6E28E768D200F8D9AC /* Browser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Browser.swift; path = ../src/ios/AppleWatchToIpad/Browser.swift; sourceTree = "<group>"; };
|
||||
87917A7028E768D200F8D9AC /* Connection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Connection.swift; path = ../src/ios/AppleWatchToIpad/Connection.swift; sourceTree = "<group>"; };
|
||||
87917A7128E768D200F8D9AC /* Server.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Server.swift; path = ../src/ios/AppleWatchToIpad/Server.swift; sourceTree = "<group>"; };
|
||||
87917A7228E768D200F8D9AC /* Client.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Client.swift; path = ../src/ios/AppleWatchToIpad/Client.swift; sourceTree = "<group>"; };
|
||||
8791A8A725C8602A003B50B2 /* inspirebike.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = inspirebike.h; path = ../src/inspirebike.h; sourceTree = "<group>"; };
|
||||
8791A8A825C8602A003B50B2 /* inspirebike.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = inspirebike.cpp; path = ../src/inspirebike.cpp; sourceTree = "<group>"; };
|
||||
8791A8A925C8603F003B50B2 /* moc_inspirebike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_inspirebike.cpp; sourceTree = "<group>"; };
|
||||
@@ -1173,6 +1197,12 @@
|
||||
87CC3BA025A0885D001EC5A8 /* elliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elliptical.cpp; path = ../src/elliptical.cpp; sourceTree = "<group>"; };
|
||||
87CC3BA125A0885E001EC5A8 /* elliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elliptical.h; path = ../src/elliptical.h; sourceTree = "<group>"; };
|
||||
87CC3BA225A0885E001EC5A8 /* domyoselliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = domyoselliptical.h; path = ../src/domyoselliptical.h; sourceTree = "<group>"; };
|
||||
87CF5167293C879700A7CABC /* characteristicwriteprocessore005.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = characteristicwriteprocessore005.cpp; path = ../src/characteristicwriteprocessore005.cpp; sourceTree = "<group>"; };
|
||||
87CF5168293C879700A7CABC /* characteristicwriteprocessore005.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = characteristicwriteprocessore005.h; path = ../src/characteristicwriteprocessore005.h; sourceTree = "<group>"; };
|
||||
87CF516A293C87AF00A7CABC /* moc_characteristicwriteprocessore005.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_characteristicwriteprocessore005.cpp; sourceTree = "<group>"; };
|
||||
87D10550290996EA00B3935B /* mepanelbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mepanelbike.cpp; path = ../src/mepanelbike.cpp; sourceTree = "<group>"; };
|
||||
87D10551290996EA00B3935B /* mepanelbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mepanelbike.h; path = ../src/mepanelbike.h; sourceTree = "<group>"; };
|
||||
87D105532909971100B3935B /* moc_mepanelbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_mepanelbike.cpp; sourceTree = "<group>"; };
|
||||
87D2699925F535160076AA48 /* m3ibike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = m3ibike.h; path = ../src/m3ibike.h; sourceTree = "<group>"; };
|
||||
87D2699A25F535160076AA48 /* m3ibike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = m3ibike.cpp; path = ../src/m3ibike.cpp; sourceTree = "<group>"; };
|
||||
87D2699C25F535170076AA48 /* skandikawiribike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = skandikawiribike.h; path = ../src/skandikawiribike.h; sourceTree = "<group>"; };
|
||||
@@ -1209,6 +1239,9 @@
|
||||
87E0761B277A081900FDA0F9 /* technogymmyruntreadmillrfcomm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = technogymmyruntreadmillrfcomm.cpp; path = ../src/technogymmyruntreadmillrfcomm.cpp; sourceTree = "<group>"; };
|
||||
87E0761C277A081900FDA0F9 /* technogymmyruntreadmillrfcomm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = technogymmyruntreadmillrfcomm.h; path = ../src/technogymmyruntreadmillrfcomm.h; sourceTree = "<group>"; };
|
||||
87E0761E277A082300FDA0F9 /* moc_technogymmyruntreadmillrfcomm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_technogymmyruntreadmillrfcomm.cpp; sourceTree = "<group>"; };
|
||||
87E2F85B291ED308002BDC65 /* lifefitnesstreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lifefitnesstreadmill.h; path = ../src/lifefitnesstreadmill.h; sourceTree = "<group>"; };
|
||||
87E2F85C291ED308002BDC65 /* lifefitnesstreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = lifefitnesstreadmill.cpp; path = ../src/lifefitnesstreadmill.cpp; sourceTree = "<group>"; };
|
||||
87E2F85E291ED315002BDC65 /* moc_lifefitnesstreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_lifefitnesstreadmill.cpp; sourceTree = "<group>"; };
|
||||
87E34C292886F95300CEDE4B /* octanetreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = octanetreadmill.h; path = ../src/octanetreadmill.h; sourceTree = "<group>"; };
|
||||
87E34C2A2886F95400CEDE4B /* octanetreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = octanetreadmill.cpp; path = ../src/octanetreadmill.cpp; sourceTree = "<group>"; };
|
||||
87E34C2C2886F99900CEDE4B /* moc_octanetreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_octanetreadmill.cpp; sourceTree = "<group>"; };
|
||||
@@ -1237,6 +1270,11 @@
|
||||
87EFE45727A518F5006EA1C3 /* nautiluselliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nautiluselliptical.h; path = ../src/nautiluselliptical.h; sourceTree = "<group>"; };
|
||||
87EFE45827A518F5006EA1C3 /* nautiluselliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nautiluselliptical.cpp; path = ../src/nautiluselliptical.cpp; sourceTree = "<group>"; };
|
||||
87EFE45A27A51900006EA1C3 /* moc_nautiluselliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_nautiluselliptical.cpp; sourceTree = "<group>"; };
|
||||
87F02E3E29178523000DB52C /* octaneelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = octaneelliptical.cpp; path = ../src/octaneelliptical.cpp; sourceTree = "<group>"; };
|
||||
87F02E3F29178524000DB52C /* octaneelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = octaneelliptical.h; path = ../src/octaneelliptical.h; sourceTree = "<group>"; };
|
||||
87F02E4129178545000DB52C /* moc_octaneelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_octaneelliptical.cpp; sourceTree = "<group>"; };
|
||||
87F527BC28EEB5AA00A9F8D5 /* qzsettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = qzsettings.cpp; path = ../src/qzsettings.cpp; sourceTree = "<group>"; };
|
||||
87F527BD28EEB5AA00A9F8D5 /* qzsettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qzsettings.h; path = ../src/qzsettings.h; sourceTree = "<group>"; };
|
||||
87F93425278E0EC00088B596 /* domyosrower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = domyosrower.h; path = ../src/domyosrower.h; sourceTree = "<group>"; };
|
||||
87F93426278E0EC00088B596 /* domyosrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = domyosrower.cpp; path = ../src/domyosrower.cpp; sourceTree = "<group>"; };
|
||||
87F93428278E0ECF0088B596 /* moc_domyosrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_domyosrower.cpp; sourceTree = "<group>"; };
|
||||
@@ -1593,6 +1631,7 @@
|
||||
0FF051564C679F373AD93E32 /* ios */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
87917A6D28E768B000F8D9AC /* AppleWatchToIpad */,
|
||||
8754D24B27F786F0003D7054 /* virtualrower.swift */,
|
||||
2F0E70F726316F3600E11F3A /* virtualbike_zwift.swift */,
|
||||
871E4CD025A6FB5A00E18D6D /* BLEPeripheralManager.swift */,
|
||||
@@ -1615,6 +1654,11 @@
|
||||
25B08E2869634E9BCBA333A2 /* Generated Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
87CF516A293C87AF00A7CABC /* moc_characteristicwriteprocessore005.cpp */,
|
||||
87E2F85E291ED315002BDC65 /* moc_lifefitnesstreadmill.cpp */,
|
||||
87F02E4129178545000DB52C /* moc_octaneelliptical.cpp */,
|
||||
87D105532909971100B3935B /* moc_mepanelbike.cpp */,
|
||||
872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */,
|
||||
878C9E6A28B77E9800669129 /* moc_nordictrackifitadbbike.cpp */,
|
||||
872261EF289EA887006A6F75 /* moc_nordictrackelliptical.cpp */,
|
||||
879E5AA9289C05A500FEA38A /* moc_proformwifitreadmill.cpp */,
|
||||
@@ -1767,6 +1811,19 @@
|
||||
2EB56BE3C2D93CDAB0C52E67 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8767EF1D29448D6700810C0F /* characteristicwriteprocessor.cpp */,
|
||||
87CF5167293C879700A7CABC /* characteristicwriteprocessore005.cpp */,
|
||||
87CF5168293C879700A7CABC /* characteristicwriteprocessore005.h */,
|
||||
87E2F85C291ED308002BDC65 /* lifefitnesstreadmill.cpp */,
|
||||
87E2F85B291ED308002BDC65 /* lifefitnesstreadmill.h */,
|
||||
87F02E3E29178523000DB52C /* octaneelliptical.cpp */,
|
||||
87F02E3F29178524000DB52C /* octaneelliptical.h */,
|
||||
87D10550290996EA00B3935B /* mepanelbike.cpp */,
|
||||
87D10551290996EA00B3935B /* mepanelbike.h */,
|
||||
87F527BC28EEB5AA00A9F8D5 /* qzsettings.cpp */,
|
||||
87F527BD28EEB5AA00A9F8D5 /* qzsettings.h */,
|
||||
872A20D928C5EC380037774D /* faketreadmill.cpp */,
|
||||
872A20D828C5EC380037774D /* faketreadmill.h */,
|
||||
878C9E6828B77E7B00669129 /* nordictrackifitadbbike.cpp */,
|
||||
878C9E6728B77E7B00669129 /* nordictrackifitadbbike.h */,
|
||||
872261EC289EA873006A6F75 /* nordictrackelliptical.cpp */,
|
||||
@@ -2154,6 +2211,17 @@
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
87917A6D28E768B000F8D9AC /* AppleWatchToIpad */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
87917A6E28E768D200F8D9AC /* Browser.swift */,
|
||||
87917A7228E768D200F8D9AC /* Client.swift */,
|
||||
87917A7028E768D200F8D9AC /* Connection.swift */,
|
||||
87917A7128E768D200F8D9AC /* Server.swift */,
|
||||
);
|
||||
name = AppleWatchToIpad;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
87DF60DE337FB58864343E39 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2768,6 +2836,7 @@
|
||||
8738249127E646E3004F1B46 /* dirconpacket.cpp in Compile Sources */,
|
||||
87C5F0BB26285E5F0067A1B5 /* mimetext.cpp in Compile Sources */,
|
||||
8732C17F27353464006DF424 /* iconceptbike.cpp in Compile Sources */,
|
||||
87CF5169293C879800A7CABC /* characteristicwriteprocessore005.cpp in Compile Sources */,
|
||||
873824C027E64707004F1B46 /* moc_dirconmanager.cpp in Compile Sources */,
|
||||
2F0E70F826316F3600E11F3A /* virtualbike_zwift.swift in Compile Sources */,
|
||||
8772A0E825E43AE70080718C /* moc_trxappgateusbbike.cpp in Compile Sources */,
|
||||
@@ -2814,6 +2883,9 @@
|
||||
C6B3CD471768392E18F85819 /* fit_accumulated_field.cpp in Compile Sources */,
|
||||
3D7395B0A17915A06361C7F3 /* fit_accumulator.cpp in Compile Sources */,
|
||||
2A61806454201575EDB3F94F /* fit_buffer_encode.cpp in Compile Sources */,
|
||||
87F02E4229178545000DB52C /* moc_octaneelliptical.cpp in Compile Sources */,
|
||||
87E2F85D291ED308002BDC65 /* lifefitnesstreadmill.cpp in Compile Sources */,
|
||||
87917A7328E768D200F8D9AC /* Browser.swift in Compile Sources */,
|
||||
873CD20B27EF8D8A000131BC /* inapptransaction.cpp in Compile Sources */,
|
||||
873824EF27E647A9004F1B46 /* query.cpp in Compile Sources */,
|
||||
876F45FF279350D9003CDA5A /* moc_concept2skierg.cpp in Compile Sources */,
|
||||
@@ -2827,6 +2899,7 @@
|
||||
87368825259C602800C71C7E /* watchAppStart.swift in Compile Sources */,
|
||||
876ED21925C3E9000065F3DC /* moc_ftmsbike.cpp in Compile Sources */,
|
||||
87C5F0BD26285E5F0067A1B5 /* chronobike.cpp in Compile Sources */,
|
||||
872A20DA28C5EC380037774D /* faketreadmill.cpp in Compile Sources */,
|
||||
87900DC8268B673C000CB351 /* moc_renphobike.cpp in Compile Sources */,
|
||||
87CC3B9E25A08812001EC5A8 /* moc_elliptical.cpp in Compile Sources */,
|
||||
876BFC9C27BE35C5001D7645 /* proformelliptical.cpp in Compile Sources */,
|
||||
@@ -2839,6 +2912,7 @@
|
||||
87CC3B9D25A08812001EC5A8 /* moc_domyoselliptical.cpp in Compile Sources */,
|
||||
87900DC6268B672E000CB351 /* renphobike.cpp in Compile Sources */,
|
||||
879F16462847E55C00CE4945 /* proformellipticaltrainer.cpp in Compile Sources */,
|
||||
87917A7728E768D200F8D9AC /* Client.swift in Compile Sources */,
|
||||
873824B927E64707004F1B46 /* moc_provider.cpp in Compile Sources */,
|
||||
8727A47727849EA600019B5D /* paferstreadmill.cpp in Compile Sources */,
|
||||
DF1FD9718B75FA591A7E3D80 /* fit_decode.cpp in Compile Sources */,
|
||||
@@ -2920,6 +2994,7 @@
|
||||
87C5F0B726285E5F0067A1B5 /* mimecontentformatter.cpp in Compile Sources */,
|
||||
23191C28CB29474279752FD3 /* fit_protocol_validator.cpp in Compile Sources */,
|
||||
275D55B5D956B2E5F1B7E46E /* fit_unicode.cpp in Compile Sources */,
|
||||
87F527BE28EEB5AA00A9F8D5 /* qzsettings.cpp in Compile Sources */,
|
||||
8703BAEB273C67A90058E206 /* pafersbike.cpp in Compile Sources */,
|
||||
87061399286D8D6500D2446E /* moc_wobjectdefs.cpp in Compile Sources */,
|
||||
873824BA27E64707004F1B46 /* moc_server_p.cpp in Compile Sources */,
|
||||
@@ -2939,6 +3014,7 @@
|
||||
87A3BC222656429600D302E3 /* rower.cpp in Compile Sources */,
|
||||
C719682D8D421AF6B2DAAEA9 /* main.cpp in Compile Sources */,
|
||||
87BB1774269E983200F46A1C /* moc_webserverinfosender.cpp in Compile Sources */,
|
||||
87E2F85F291ED315002BDC65 /* moc_lifefitnesstreadmill.cpp in Compile Sources */,
|
||||
876BFCA127BE35D8001D7645 /* moc_bowflext216treadmill.cpp in Compile Sources */,
|
||||
25FCD41CCCAF49293B9369E8 /* qfit.cpp in Compile Sources */,
|
||||
87ADD2BD27634C2100B7A0AB /* moc_technogymmyruntreadmill.cpp in Compile Sources */,
|
||||
@@ -2961,6 +3037,7 @@
|
||||
873824BB27E64707004F1B46 /* moc_prober_p.cpp in Compile Sources */,
|
||||
8742C2B227C92C30007D3FA0 /* wahookickrsnapbike.cpp in Compile Sources */,
|
||||
87EB918327EE5FE7002535E1 /* moc_inappstore.cpp in Compile Sources */,
|
||||
87CF516B293C87B000A7CABC /* moc_characteristicwriteprocessore005.cpp in Compile Sources */,
|
||||
8780D949264FB8B800192D41 /* moc_smartspin2k.cpp in Compile Sources */,
|
||||
8768D1FD2850820B00F58E3A /* moc_nordictrackifitadbtreadmill.cpp in Compile Sources */,
|
||||
87D5DC402823047D008CCDE7 /* truetreadmill.cpp in Compile Sources */,
|
||||
@@ -2996,9 +3073,11 @@
|
||||
87AE0CB227760DCB00E547E9 /* virtualtreadmill_zwift.swift in Compile Sources */,
|
||||
87062643259480A200D06586 /* AppDelegate.swift in Compile Sources */,
|
||||
873824F027E647A9004F1B46 /* server.cpp in Compile Sources */,
|
||||
872A20DC28C5F5CE0037774D /* moc_faketreadmill.cpp in Compile Sources */,
|
||||
873CD20927EF8D8A000131BC /* inapppurchasebackend.cpp in Compile Sources */,
|
||||
87E0761F277A082300FDA0F9 /* moc_technogymmyruntreadmillrfcomm.cpp in Compile Sources */,
|
||||
87433F2127D8B722003D1672 /* simplecrypt.cpp in Compile Sources */,
|
||||
87917A7628E768D200F8D9AC /* Server.swift in Compile Sources */,
|
||||
2B42755BF45173E11E2110CB /* FitFieldDefinition.mm in Compile Sources */,
|
||||
873824AE27E64706004F1B46 /* moc_browser.cpp in Compile Sources */,
|
||||
8738249727E646E3004F1B46 /* characteristicnotifier2a53.cpp in Compile Sources */,
|
||||
@@ -3015,10 +3094,12 @@
|
||||
873824E527E647A8004F1B46 /* message.cpp in Compile Sources */,
|
||||
210F6A0A7E2FA7CDD3CA0084 /* qdomyoszwift_qml_plugin_import.cpp in Compile Sources */,
|
||||
87062644259480A600D06586 /* APIFetcher.swift in Compile Sources */,
|
||||
87F02E4029178524000DB52C /* octaneelliptical.cpp in Compile Sources */,
|
||||
878531682711A3EC004B153D /* moc_activiotreadmill.cpp in Compile Sources */,
|
||||
87C5F0D626285E7E0067A1B5 /* moc_emailaddress.cpp in Compile Sources */,
|
||||
39FAA19B9285AB16AE3A39BA /* qrc_icons.cpp in Compile Sources */,
|
||||
87D2699F25F535200076AA48 /* m3ibike.cpp in Compile Sources */,
|
||||
87917A7528E768D200F8D9AC /* Connection.swift in Compile Sources */,
|
||||
87FFA13727BBE3FF00924E4E /* solebike.cpp in Compile Sources */,
|
||||
7352E0F0EE5366AC809B9D64 /* qrc_qml.cpp in Compile Sources */,
|
||||
873824E727E647A8004F1B46 /* record.cpp in Compile Sources */,
|
||||
@@ -3032,6 +3113,7 @@
|
||||
873824BD27E64707004F1B46 /* moc_resolver_p.cpp in Compile Sources */,
|
||||
876ED21A25C3E9010065F3DC /* moc_material.cpp in Compile Sources */,
|
||||
87A4B76125AF27CB0027EF3C /* metric.cpp in Compile Sources */,
|
||||
87D10552290996EA00B3935B /* mepanelbike.cpp in Compile Sources */,
|
||||
9D9484EED654597C394345DE /* moc_echelonconnectsport.cpp in Compile Sources */,
|
||||
87DED80627D1273900BE4FBB /* filedownloader.cpp in Compile Sources */,
|
||||
7DEEAF0C3D671FBFD84ACFCE /* moc_homeform.cpp in Compile Sources */,
|
||||
@@ -3043,6 +3125,7 @@
|
||||
E62DA5FF2436135448C94671 /* moc_toorxtreadmill.cpp in Compile Sources */,
|
||||
87586A4325B8341B00A243C4 /* moc_proformbike.cpp in Compile Sources */,
|
||||
87CC3BA325A0885F001EC5A8 /* domyoselliptical.cpp in Compile Sources */,
|
||||
87D105542909971100B3935B /* moc_mepanelbike.cpp in Compile Sources */,
|
||||
87B617F325F260150094A1CB /* moc_snodebike.cpp in Compile Sources */,
|
||||
87DA8467284933DE00B550E9 /* moc_fakeelliptical.cpp in Compile Sources */,
|
||||
87C5F0D726285E7E0067A1B5 /* moc_mimefile.cpp in Compile Sources */,
|
||||
@@ -3061,6 +3144,7 @@
|
||||
879E5AA8289C057E00FEA38A /* proformwifitreadmill.cpp in Compile Sources */,
|
||||
873824B227E64706004F1B46 /* moc_hostname.cpp in Compile Sources */,
|
||||
873824EB27E647A8004F1B46 /* prober.cpp in Compile Sources */,
|
||||
8767EF1E29448D6700810C0F /* characteristicwriteprocessor.cpp in Compile Sources */,
|
||||
87B617F425F260150094A1CB /* moc_screencapture.cpp in Compile Sources */,
|
||||
87B617ED25F25FED0094A1CB /* fitshowtreadmill.cpp in Compile Sources */,
|
||||
87A0C4BC262329A600121A76 /* cscbike.cpp in Compile Sources */,
|
||||
@@ -3452,7 +3536,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2.11.24;
|
||||
CURRENT_PROJECT_VERSION = 2.12.10;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
@@ -3481,6 +3565,7 @@
|
||||
../src/purchasing/qmltypes,
|
||||
../src/purchasing/ios,
|
||||
../../Qt/5.15.2/ios/include/QtTextToSpeech,
|
||||
../../Qt/5.15.2/ios/include/QtMultimedia,
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/platforms,
|
||||
@@ -3526,7 +3611,7 @@
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/playlistformats,
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/audio,
|
||||
);
|
||||
MARKETING_VERSION = 2.11;
|
||||
MARKETING_VERSION = 2.12;
|
||||
OTHER_CFLAGS = (
|
||||
"-pipe",
|
||||
"-g",
|
||||
@@ -3619,7 +3704,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2.11.24;
|
||||
CURRENT_PROJECT_VERSION = 2.12.10;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -3650,6 +3735,7 @@
|
||||
../src/purchasing/qmltypes,
|
||||
../src/purchasing/ios,
|
||||
../../Qt/5.15.2/ios/include/QtTextToSpeech,
|
||||
../../Qt/5.15.2/ios/include/QtMultimedia,
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/platforms,
|
||||
@@ -3695,7 +3781,7 @@
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/playlistformats,
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/audio,
|
||||
);
|
||||
MARKETING_VERSION = 2.11;
|
||||
MARKETING_VERSION = 2.12;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = (
|
||||
"-pipe",
|
||||
@@ -3822,7 +3908,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2.11.24;
|
||||
CURRENT_PROJECT_VERSION = 2.12.10;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -3843,7 +3929,7 @@
|
||||
IBSC_MODULE = watchkit_Extension;
|
||||
INFOPLIST_FILE = watchkit/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MARKETING_VERSION = 2.11;
|
||||
MARKETING_VERSION = 2.12;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
@@ -3914,7 +4000,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2.11.24;
|
||||
CURRENT_PROJECT_VERSION = 2.12.10;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
@@ -3931,7 +4017,7 @@
|
||||
IBSC_MODULE = watchkit_Extension;
|
||||
INFOPLIST_FILE = watchkit/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MARKETING_VERSION = 2.11;
|
||||
MARKETING_VERSION = 2.12;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
@@ -4001,7 +4087,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2.11.24;
|
||||
CURRENT_PROJECT_VERSION = 2.12.10;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -4020,9 +4106,29 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../src,
|
||||
.,
|
||||
../../Qt/5.15.2/ios/mkspecs/common/uikit,
|
||||
"../src/fit-sdk",
|
||||
../../Qt/5.15.2/ios/include,
|
||||
../../Qt/5.15.2/ios/include/QtWidgets,
|
||||
../../Qt/5.15.2/ios/include/QtQuick,
|
||||
../../Qt/5.15.2/ios/include/QtGui,
|
||||
../../Qt/5.15.2/ios/include/QtBluetooth,
|
||||
../../Qt/5.15.2/ios/include/QtXml,
|
||||
../../Qt/5.15.2/ios/include/QtPositioning,
|
||||
../../Qt/5.15.2/ios/include/QtQmlModels,
|
||||
../../Qt/5.15.2/ios/include/QtQml,
|
||||
../../Qt/5.15.2/ios/include/QtNetwork,
|
||||
../../Qt/5.15.2/ios/include/QtCore,
|
||||
.,
|
||||
"../../Qt/5.15.2/ios/mkspecs/macx-ios-clang",
|
||||
../../Qt/5.15.2/ios/include/QtMultimedia,
|
||||
);
|
||||
INFOPLIST_FILE = "watchkit Extension/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 2.11;
|
||||
MARKETING_VERSION = 2.12;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
@@ -4091,7 +4197,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2.11.24;
|
||||
CURRENT_PROJECT_VERSION = 2.12.10;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
@@ -4106,9 +4212,29 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
../src,
|
||||
.,
|
||||
../../Qt/5.15.2/ios/mkspecs/common/uikit,
|
||||
"../src/fit-sdk",
|
||||
../../Qt/5.15.2/ios/include,
|
||||
../../Qt/5.15.2/ios/include/QtWidgets,
|
||||
../../Qt/5.15.2/ios/include/QtQuick,
|
||||
../../Qt/5.15.2/ios/include/QtGui,
|
||||
../../Qt/5.15.2/ios/include/QtBluetooth,
|
||||
../../Qt/5.15.2/ios/include/QtXml,
|
||||
../../Qt/5.15.2/ios/include/QtPositioning,
|
||||
../../Qt/5.15.2/ios/include/QtQmlModels,
|
||||
../../Qt/5.15.2/ios/include/QtQml,
|
||||
../../Qt/5.15.2/ios/include/QtNetwork,
|
||||
../../Qt/5.15.2/ios/include/QtCore,
|
||||
.,
|
||||
"../../Qt/5.15.2/ios/mkspecs/macx-ios-clang",
|
||||
../../Qt/5.15.2/ios/include/QtMultimedia,
|
||||
);
|
||||
INFOPLIST_FILE = "watchkit Extension/Info.plist";
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
|
||||
MARKETING_VERSION = 2.11;
|
||||
MARKETING_VERSION = 2.12;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
|
||||
@@ -17,16 +17,33 @@ class MainController: WKInterfaceController {
|
||||
@IBOutlet weak var distanceLabel: WKInterfaceLabel!
|
||||
@IBOutlet weak var heartRateLabel: WKInterfaceLabel!
|
||||
@IBOutlet weak var startButton: WKInterfaceButton!
|
||||
@IBOutlet weak var cmbSports: WKInterfacePicker!
|
||||
static var start: Bool! = false
|
||||
let pedometer = CMPedometer()
|
||||
var sport: Int = 0
|
||||
|
||||
override func awake(withContext context: Any?) {
|
||||
super.awake(withContext: context)
|
||||
let sports: [WKPickerItem] = [WKPickerItem(),WKPickerItem(),WKPickerItem(),WKPickerItem(),WKPickerItem()]
|
||||
sports[0].title = "Bike"
|
||||
sports[1].title = "Run"
|
||||
sports[2].title = "Walk"
|
||||
sports[3].title = "Elliptical"
|
||||
sports[4].title = "Rowing"
|
||||
cmbSports.setItems(sports)
|
||||
sport = UserDefaults.standard.value(forKey: "sport") as? Int ?? 0
|
||||
cmbSports.setSelectedItemIndex(sport)
|
||||
|
||||
// Configure interface objects here.
|
||||
print("AWAKE")
|
||||
}
|
||||
|
||||
@IBAction func changeSport(_ value: Int) {
|
||||
self.sport = value
|
||||
UserDefaults.standard.set(value, forKey: "sport")
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
||||
override func willActivate() {
|
||||
// This method is called when watch view controller is about to be visible to user
|
||||
super.willActivate()
|
||||
@@ -57,6 +74,7 @@ extension MainController {
|
||||
MainController.start = true
|
||||
startButton.setTitle("Stop")
|
||||
WorkoutTracking.authorizeHealthKit()
|
||||
WorkoutTracking.shared.setSport(sport)
|
||||
WorkoutTracking.shared.startWorkOut()
|
||||
WorkoutTracking.shared.delegate = self
|
||||
|
||||
@@ -86,8 +104,12 @@ extension MainController: WorkoutTrackingDelegate {
|
||||
"\(heartRate)" as AnyObject])
|
||||
WorkoutTracking.distance = WatchKitConnection.distance
|
||||
WorkoutTracking.kcal = WatchKitConnection.kcal
|
||||
|
||||
self.distanceLabel.setText("Distance \(Double(WorkoutTracking.distance))")
|
||||
|
||||
if Locale.current.measurementSystem != "Metric" {
|
||||
self.distanceLabel.setText("Distance \(String(format:"%.2f", WorkoutTracking.distance))")
|
||||
} else {
|
||||
self.distanceLabel.setText("Distance \(String(format:"%.2f", WorkoutTracking.distance * 1.60934))")
|
||||
}
|
||||
self.caloriesLabel.setText("KCal \(Int(WorkoutTracking.kcal))")
|
||||
//WorkoutTracking.cadenceSteps = pedometer.
|
||||
}
|
||||
@@ -105,3 +127,11 @@ extension MainController: WatchKitConnectionDelegate {
|
||||
userNameLabel.setText(userName)
|
||||
}
|
||||
}
|
||||
|
||||
extension Locale
|
||||
{
|
||||
var measurementSystem : String?
|
||||
{
|
||||
return (self as NSLocale).object(forKey: NSLocale.Key.measurementSystem) as? String
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ class WorkoutTracking: NSObject {
|
||||
public static var cadenceTimeStamp = NSDate().timeIntervalSince1970
|
||||
public static var cadenceLastSteps = Double()
|
||||
public static var cadenceSteps = 0
|
||||
var sport: Int = 0
|
||||
let healthStore = HKHealthStore()
|
||||
let configuration = HKWorkoutConfiguration()
|
||||
var workoutSession: HKWorkoutSession!
|
||||
@@ -101,8 +102,23 @@ extension WorkoutTracking {
|
||||
}
|
||||
}
|
||||
|
||||
func setSport(_ sport: Int) {
|
||||
self.sport = sport
|
||||
}
|
||||
|
||||
private func configWorkout() {
|
||||
configuration.activityType = .cycling
|
||||
var activityType = HKWorkoutActivityType.cycling
|
||||
if self.sport == 1 {
|
||||
activityType = HKWorkoutActivityType.running
|
||||
} else if self.sport == 2 {
|
||||
activityType = HKWorkoutActivityType.walking
|
||||
} else if self.sport == 3 {
|
||||
activityType = HKWorkoutActivityType.elliptical
|
||||
} else if self.sport == 4 {
|
||||
activityType = HKWorkoutActivityType.rowing
|
||||
}
|
||||
|
||||
configuration.activityType = activityType
|
||||
configuration.locationType = .indoor
|
||||
|
||||
do {
|
||||
@@ -134,6 +150,7 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
@@ -159,6 +176,10 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
|
||||
if self.sport > 0 {
|
||||
self.workoutBuilder.dataSource?.enableCollection(for: HKQuantityType.quantityType(forIdentifier: .distanceWalkingRunning)!, predicate: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,29 +204,72 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
end: Date())
|
||||
|
||||
workoutBuilder.add([sample]) {(success, error) in}
|
||||
|
||||
guard let quantityTypeDistance = HKQuantityType.quantityType(
|
||||
forIdentifier: .distanceCycling) else {
|
||||
return
|
||||
}
|
||||
|
||||
let unitDistance = HKUnit.mile()
|
||||
let miles = WorkoutTracking.distance
|
||||
let quantityMiles = HKQuantity(unit: unitDistance,
|
||||
doubleValue: miles)
|
||||
|
||||
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
|
||||
quantity: quantityMiles,
|
||||
start: workoutSession.startDate!,
|
||||
end: Date())
|
||||
|
||||
workoutBuilder.add([sample]) {(success, error) in}
|
||||
workoutBuilder.add([sampleDistance]) {(success, error) in}
|
||||
|
||||
workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
|
||||
if(sport == 0) {
|
||||
|
||||
guard let quantityTypeDistance = HKQuantityType.quantityType(
|
||||
forIdentifier: .distanceCycling) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
|
||||
quantity: quantityMiles,
|
||||
start: workoutSession.startDate!,
|
||||
end: Date())
|
||||
|
||||
workoutBuilder.add([sampleDistance]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
self.workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
self.workoutBuilder.finishWorkout{ (workout, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
workout?.setValue(quantityMiles, forKey: "totalDistance")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
guard let quantityTypeDistance = HKQuantityType.quantityType(
|
||||
forIdentifier: .distanceWalkingRunning) else {
|
||||
return
|
||||
}
|
||||
|
||||
let sampleDistance = HKCumulativeQuantitySeriesSample(type: quantityTypeDistance,
|
||||
quantity: quantityMiles,
|
||||
start: workoutSession.startDate!,
|
||||
end: Date())
|
||||
|
||||
workoutBuilder.add([sampleDistance]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
self.workoutBuilder.endCollection(withEnd: Date()) { (success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
self.workoutBuilder.finishWorkout{ (workout, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
workout?.setValue(quantityMiles, forKey: "totalDistance")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
workoutBuilder.finishWorkout{ (success, error) in }
|
||||
|
||||
|
||||
}
|
||||
|
||||
func fetchStepCounts() {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="19529" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Tpn-rd-UUX">
|
||||
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="20037" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Tpn-rd-UUX">
|
||||
<device id="watch38"/>
|
||||
<dependencies>
|
||||
<deployment identifier="watchOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="19514"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="20006"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Main-->
|
||||
@@ -22,9 +22,15 @@
|
||||
<label width="136" alignment="left" text="Step Counts" id="HpA-e9-6YV"/>
|
||||
<label width="136" alignment="left" text="Calories" id="Szi-Jp-J3S"/>
|
||||
<label width="136" alignment="left" text="Distance" id="eRf-NJ-6If"/>
|
||||
<picker height="100" alignment="left" id="OTR-HF-vYb">
|
||||
<connections>
|
||||
<action selector="changeSport:" destination="Tpn-rd-UUX" id="3vY-lq-IhZ"/>
|
||||
</connections>
|
||||
</picker>
|
||||
</items>
|
||||
<connections>
|
||||
<outlet property="caloriesLabel" destination="Szi-Jp-J3S" id="trd-YS-bJy"/>
|
||||
<outlet property="cmbSports" destination="OTR-HF-vYb" id="Ws5-w9-ZT8"/>
|
||||
<outlet property="distanceLabel" destination="eRf-NJ-6If" id="ZE2-OB-jqN"/>
|
||||
<outlet property="heartRateLabel" destination="Nda-m1-XRw" id="1la-8R-3jG"/>
|
||||
<outlet property="startButton" destination="vZg-X8-uY5" id="pJc-09-kfV"/>
|
||||
|
||||
@@ -25,13 +25,13 @@ $ sudo ./qdomyos-zwift
|
||||
You will need to (at a minimum) to install the xcode Command Line Tools (CLI) thanks to @richardwait
|
||||
https://developer.apple.com/download/more/?=xcode
|
||||
|
||||
Download and install http://download.qt.io/official_releases/qt/5.12/5.12.9/qt-opensource-mac-x64-5.12.9.dmg and simply run the qdomyos-zwift relase for MacOs
|
||||
Download and install http://download.qt.io/official_releases/qt/5.12/5.12.9/qt-opensource-mac-x64-5.12.9.dmg and simply run the qdomyos-zwift release for MacOs
|
||||
|
||||
## On Raspberry Pi Zero W
|
||||
|
||||

|
||||
|
||||
This guide will walk you through steps to setup an autonomous, headless raspberry brigde.
|
||||
This guide will walk you through steps to setup an autonomous, headless raspberry bridge.
|
||||
|
||||
|
||||
### Initial System Preparation
|
||||
|
||||
@@ -26,5 +26,5 @@ You can have ae true 4k video stream while you ride ("extreme quality" setting)
|
||||
The application do not read the FTMS value. It is required to start the application with `-heart-service` or `bike_heartrate_service: true` in settings.
|
||||
|
||||
### Resistance management
|
||||
You can adjust resistence using arrows [up and down](img/21_zwift-resistance-buttons.jpg) rom the riding screen.
|
||||
You can adjust resistance using arrows [up and down](img/21_zwift-resistance-buttons.jpg) rom the riding screen.
|
||||
|
||||
|
||||
@@ -24,8 +24,9 @@ This is the list of settings available in the application. These settings needs
|
||||
| **Option** | **Type** | **Default** | **Function** |
|
||||
|:------------------------------|:---------|:------------|:-----------------------------------------------------------------------------|
|
||||
| -no-gui | Boolean | False | Disable GUI |
|
||||
| -qml | Boolean | False | Enables the QML interface |
|
||||
| -miles | Boolean | False | Swithes to Imperial Units System |
|
||||
| -qml | Boolean | True | Enables the QML interface |
|
||||
| -noqml | Boolean | False | Enables the NativeQT interface |
|
||||
| -miles | Boolean | False | Switches to Imperial Units System |
|
||||
| -no-console | Boolean | False | Not in use |
|
||||
| -test-resistance | Boolean | False | |
|
||||
| -no-log | Boolean | False | Disable Logging |
|
||||
@@ -42,10 +43,10 @@ This is the list of settings available in the application. These settings needs
|
||||
| -service-changed | Boolean | False | |
|
||||
| -bike-wheel-revs | Boolean | False | |
|
||||
| -run-cadence-sensor | Boolean | False | |
|
||||
| -nordictrack-10-treadmill | Boolean | False | Enable NordicTrack compatibility mode |
|
||||
| -nordictrack-10-treadmill | Boolean | False | Enable NordicTrack compatibility mode |
|
||||
| -train | String | | Force training program |
|
||||
| -name | String | | Force bluetooth device name (if QZ struggles finding your fitness equipment) |
|
||||
| -poll-device-time | Int | 200 (ms) | Frequency to refresh informations from QZ to Fitness equipment |
|
||||
| -poll-device-time | Int | 200 (ms) | Frequency to refresh information from QZ to Fitness equipment |
|
||||
| -bike-resistance-gain | Int | | Adjust resistance from the fitness application |
|
||||
| -bike-resistance-offset | Int | | Set another resistance point than default |
|
||||
|
||||
|
||||
272
docs/specs/org.bluetooth.characteristic.cross_trainer_data.xml
Normal file
272
docs/specs/org.bluetooth.characteristic.cross_trainer_data.xml
Normal file
@@ -0,0 +1,272 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--Copyright 2017 Bluetooth SIG, Inc. All rights reserved.-->
|
||||
<Characteristic xsi:noNamespaceSchemaLocation="http://schemas.bluetooth.org/Documents/characteristic.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
name="Cross Trainer Data"
|
||||
type="org.bluetooth.characteristic.cross_trainer_data" uuid="2ACE"
|
||||
last-modified="2017-02-14" approved="Yes">
|
||||
<InformativeText>
|
||||
<Summary>The Cross Trainer Data characteristic is used to send
|
||||
training-related data to the Client from a cross trainer
|
||||
(Server).</Summary>
|
||||
</InformativeText>
|
||||
<Value>
|
||||
<Field name="Flags">
|
||||
<Requirement>Mandatory</Requirement>
|
||||
<Format>24bit</Format>
|
||||
<BitField>
|
||||
<Bit index="0" size="1" name="More Data">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" requires="C1" />
|
||||
<Enumeration key="1" value="True" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="1" size="1" name="Average Speed present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C2" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="2" size="1" name="Total Distance Present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C3" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="3" size="1" name="Step Count present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C4" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="4" size="1" name="Stride Count present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C5" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="5" size="1" name="Elevation Gain present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C6" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="6" size="1"
|
||||
name="Inclination and Ramp Angle Setting present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C7" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="7" size="1" name="Resistance Level Present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C8" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="8" size="1" name="Instantaneous Power present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C9" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="9" size="1" name="Average Power present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C10" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="10" size="1" name="Expended Energy present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C11" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="11" size="1" name="Heart Rate present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C12" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="12" size="1"
|
||||
name="Metabolic Equivalent present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C13" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="13" size="1" name="Elapsed Time present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C14" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="14" size="1" name="Remaining Time present">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="False" />
|
||||
<Enumeration key="1" value="True" requires="C15" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<Bit index="15" size="1" name="Movement Direction">
|
||||
<Enumerations>
|
||||
<Enumeration key="0" value="Forward" />
|
||||
<Enumeration key="1" value="Backward" />
|
||||
</Enumerations>
|
||||
</Bit>
|
||||
<ReservedForFutureUse index="16" size="8" />
|
||||
</BitField>
|
||||
</Field>
|
||||
<Field name="Instantaneous Speed">
|
||||
<InformativeText>Kilometer per hour with a resolution of
|
||||
0.01</InformativeText>
|
||||
<Requirement>C1</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.velocity.kilometre_per_hour</Unit>
|
||||
<DecimalExponent>-2</DecimalExponent>
|
||||
</Field>
|
||||
<Field name="Average Speed">
|
||||
<InformativeText>Kilometer per hour with a resolution of
|
||||
0.01</InformativeText>
|
||||
<Requirement>C2</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.velocity.kilometre_per_hour</Unit>
|
||||
<DecimalExponent>-2</DecimalExponent>
|
||||
</Field>
|
||||
<Field name="Total Distance">
|
||||
<InformativeText>Meters with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C3</Requirement>
|
||||
<Format>uint24</Format>
|
||||
<Unit>org.bluetooth.unit.length.metre</Unit>
|
||||
</Field>
|
||||
<Field name="Step Per Minute">
|
||||
<InformativeText>Step/minute with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C4</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.step_per_minute</Unit>
|
||||
</Field>
|
||||
<Field name="Average Step Rate">
|
||||
<InformativeText>Step/minute with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C4</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.step_per_minute</Unit>
|
||||
</Field>
|
||||
<Field name="Stride Count">
|
||||
<InformativeText>Unitless with a resolution of
|
||||
0.1</InformativeText>
|
||||
<Requirement>C5</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<DecimalExponent>-1</DecimalExponent>
|
||||
<Unit>org.bluetooth.unit.unitless</Unit>
|
||||
</Field>
|
||||
<Field name="Positive Elevation Gain">
|
||||
<InformativeText>Meters with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C6</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.length.metre</Unit>
|
||||
</Field>
|
||||
<Field name="Negative Elevation Gain">
|
||||
<InformativeText>Meters with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C6</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.length.metre</Unit>
|
||||
</Field>
|
||||
<Field name="Inclination">
|
||||
<InformativeText>Percent with a resolution of
|
||||
0.1</InformativeText>
|
||||
<Requirement>C7</Requirement>
|
||||
<Format>sint16</Format>
|
||||
<Unit>org.bluetooth.unit.percentage</Unit>
|
||||
<DecimalExponent>-1</DecimalExponent>
|
||||
</Field>
|
||||
<Field name="Ramp Angle Setting">
|
||||
<InformativeText>Degree with a resolution of
|
||||
0.1</InformativeText>
|
||||
<Requirement>C7</Requirement>
|
||||
<Format>sint16</Format>
|
||||
<Unit>org.bluetooth.unit.plane_angle.degree</Unit>
|
||||
<DecimalExponent>-1</DecimalExponent>
|
||||
</Field>
|
||||
<Field name="Resistance Level">
|
||||
<InformativeText>Unitless with a resolution of
|
||||
0.1</InformativeText>
|
||||
<Requirement>C8</Requirement>
|
||||
<Format>sint16</Format>
|
||||
<DecimalExponent>-1</DecimalExponent>
|
||||
<Unit>org.bluetooth.unit.unitless</Unit>
|
||||
</Field>
|
||||
<Field name="Instantaneous Power">
|
||||
<InformativeText>Watts with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C9</Requirement>
|
||||
<Format>sint16</Format>
|
||||
<Unit>org.bluetooth.unit.power.watt</Unit>
|
||||
</Field>
|
||||
<Field name="Average Power">
|
||||
<InformativeText>Watts with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C10</Requirement>
|
||||
<Format>sint16</Format>
|
||||
<Unit>org.bluetooth.unit.power.watt</Unit>
|
||||
</Field>
|
||||
<Field name="Total Energy">
|
||||
<InformativeText>Kilo Calorie with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C11</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.energy.kilogram_calorie</Unit>
|
||||
</Field>
|
||||
<Field name="Energy Per Hour">
|
||||
<InformativeText>Kilo Calorie with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C11</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.energy.kilogram_calorie</Unit>
|
||||
</Field>
|
||||
<Field name="Energy Per Minute">
|
||||
<InformativeText>Kilo Calorie with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C11</Requirement>
|
||||
<Format>uint8</Format>
|
||||
<Unit>org.bluetooth.unit.energy.kilogram_calorie</Unit>
|
||||
</Field>
|
||||
<Field name="Heart Rate">
|
||||
<InformativeText>Beats per minute with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C12</Requirement>
|
||||
<Format>uint8</Format>
|
||||
<Unit>org.bluetooth.unit.period.beats_per_minute</Unit>
|
||||
</Field>
|
||||
<Field name="Metabolic Equivalent">
|
||||
<InformativeText>Metabolic Equivalent with a resolution of
|
||||
0.1</InformativeText>
|
||||
<Requirement>C13</Requirement>
|
||||
<Format>uint8</Format>
|
||||
<DecimalExponent>-1</DecimalExponent>
|
||||
<Unit>org.bluetooth.unit.metabolic_equivalent</Unit>
|
||||
</Field>
|
||||
<Field name="Elapsed Time">
|
||||
<InformativeText>Second with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C14</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.time.second</Unit>
|
||||
</Field>
|
||||
<Field name="Remaining Time">
|
||||
<InformativeText>Second with a resolution of
|
||||
1</InformativeText>
|
||||
<Requirement>C15</Requirement>
|
||||
<Format>uint16</Format>
|
||||
<Unit>org.bluetooth.unit.time.second</Unit>
|
||||
</Field>
|
||||
</Value>
|
||||
<Note>The fields in the above table, reading from top to bottom,
|
||||
are shown in the order of LSO to MSO, where LSO = Least
|
||||
Significant Octet and MSO = Most Significant Octet. The Least
|
||||
Significant Octet represents the eight bits numbered 0 to
|
||||
7.</Note>
|
||||
</Characteristic>
|
||||
@@ -1018,7 +1018,7 @@ public class QtBluetoothLE {
|
||||
|
||||
/*
|
||||
* Already executed in GattCallback so executed by the HandlerThread. No need to
|
||||
* post it to the Hander.
|
||||
* post it to the Handler.
|
||||
*/
|
||||
private void scheduleMtuExchange() {
|
||||
ReadWriteJob newJob = new ReadWriteJob();
|
||||
|
||||
@@ -385,11 +385,11 @@ QT_USE_NAMESPACE
|
||||
}
|
||||
|
||||
[uuids addObject:nsUuid];
|
||||
// With the latest CoreBluetooth, we can synchronously retrive peripherals:
|
||||
// With the latest CoreBluetooth, we can synchronously retrieve peripherals:
|
||||
QT_BT_MAC_AUTORELEASEPOOL;
|
||||
NSArray *const peripherals = [manager retrievePeripheralsWithIdentifiers:uuids];
|
||||
if (!peripherals || peripherals.count != 1) {
|
||||
qCWarning(QT_BT_OSX) << "failed to retrive a peripheral";
|
||||
qCWarning(QT_BT_OSX) << "failed to retrieve a peripheral";
|
||||
if (notifier)
|
||||
emit notifier->CBManagerError(QLowEnergyController::UnknownRemoteDeviceError);
|
||||
return;
|
||||
@@ -648,7 +648,7 @@ QT_USE_NAMESPACE
|
||||
servicesToDiscoverDetails.removeAll(serviceUuid);
|
||||
|
||||
const NSUInteger nHandles = qt_countGATTEntries(service);
|
||||
Q_ASSERT_X(nHandles, Q_FUNC_INFO, "unexpected number of GATT entires");
|
||||
Q_ASSERT_X(nHandles, Q_FUNC_INFO, "unexpected number of GATT entries");
|
||||
|
||||
const QLowEnergyHandle maxHandle = std::numeric_limits<QLowEnergyHandle>::max();
|
||||
if (nHandles >= maxHandle || lastValidHandle > maxHandle - nHandles) {
|
||||
@@ -1058,7 +1058,7 @@ QT_USE_NAMESPACE
|
||||
|
||||
// TODO: test that we NEVER have the same characteristic twice in array!
|
||||
// At the moment I just protect against this by iterating in a reverse
|
||||
// order (at least avoiding a potential inifite loop with '-indexOfObject:').
|
||||
// order (at least avoiding a potential infinite loop with '-indexOfObject:').
|
||||
NSArray *const cs = service.characteristics;
|
||||
if (cs.count == 1)
|
||||
return nil;
|
||||
@@ -1091,7 +1091,7 @@ QT_USE_NAMESPACE
|
||||
|
||||
// TODO: test that we NEVER have the same characteristic twice in array!
|
||||
// At the moment I just protect against this by iterating in a reverse
|
||||
// order (at least avoiding a potential inifite loop with '-indexOfObject:').
|
||||
// order (at least avoiding a potential infinite loop with '-indexOfObject:').
|
||||
NSArray *const cs = service.characteristics;
|
||||
if (cs.count == 1)
|
||||
return nil;
|
||||
@@ -1597,8 +1597,8 @@ QT_USE_NAMESPACE
|
||||
} else {
|
||||
// This is (probably) the result of update notification.
|
||||
// It's very possible we can have an invalid handle here (0) -
|
||||
// if something esle is wrong (we subscribed for a notification),
|
||||
// disconnected (but other application is connected) and still receiveing
|
||||
// if something else is wrong (we subscribed for a notification),
|
||||
// disconnected (but other application is connected) and still receiving
|
||||
// updated values ...
|
||||
// TODO: this must be properly tested.
|
||||
if (!chHandle) {
|
||||
|
||||
@@ -61,6 +61,12 @@ ColumnLayout {
|
||||
id: filterField
|
||||
onTextChanged: updateFilter()
|
||||
}
|
||||
Button {
|
||||
anchors.left: mainRect.right
|
||||
anchors.leftMargin: 5
|
||||
text: "←"
|
||||
onClicked: folderModel.folder = folderModel.parentFolder
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
@@ -78,6 +84,8 @@ ColumnLayout {
|
||||
folder: "file://" + rootItem.getWritableAppDir() + 'gpx'
|
||||
showDotAndDotDot: false
|
||||
showDirs: true
|
||||
sortField: "Name"
|
||||
showDirsFirst: true
|
||||
}
|
||||
model: folderModel
|
||||
delegate: Component {
|
||||
@@ -96,7 +104,7 @@ ColumnLayout {
|
||||
clip: true
|
||||
Text {
|
||||
id: fileTextBox
|
||||
color: Material.color(Material.Grey)
|
||||
color: (!folderModel.isFolder(index)?Material.color(Material.Grey):Material.color(Material.Orange))
|
||||
font.pixelSize: Qt.application.font.pixelSize * 1.6
|
||||
text: fileName.substring(0, fileName.length-4)
|
||||
NumberAnimation on x {
|
||||
@@ -124,9 +132,11 @@ ColumnLayout {
|
||||
console.log('onclicked ' + index+ " count "+list.count);
|
||||
if (index == list.currentIndex) {
|
||||
let fileUrl = folderModel.get(list.currentIndex, 'fileUrl') || folderModel.get(list.currentIndex, 'fileURL');
|
||||
if (fileUrl) {
|
||||
if (fileUrl && !folderModel.isFolder(list.currentIndex)) {
|
||||
trainprogram_open_clicked(fileUrl);
|
||||
popup.open()
|
||||
} else {
|
||||
folderModel.folder = fileURL
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
392
src/Home.qml
392
src/Home.qml
@@ -5,6 +5,7 @@ import QtGraphicalEffects 1.12
|
||||
import QtQuick.Window 2.12
|
||||
import Qt.labs.settings 1.0
|
||||
import Qt.labs.platform 1.1
|
||||
import QtMultimedia 5.15
|
||||
|
||||
HomeForm{
|
||||
objectName: "home"
|
||||
@@ -15,6 +16,7 @@ HomeForm{
|
||||
signal peloton_abort_workout;
|
||||
signal plus_clicked(string name)
|
||||
signal minus_clicked(string name)
|
||||
signal largeButton_clicked(string name)
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
@@ -79,172 +81,244 @@ HomeForm{
|
||||
|
||||
Component.onCompleted: { console.log("completed"); }
|
||||
|
||||
GridView {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.fill: parent
|
||||
cellWidth: 175 * settings.ui_zoom / 100
|
||||
cellHeight: 130 * settings.ui_zoom / 100
|
||||
focus: true
|
||||
model: appModel
|
||||
leftMargin: { if(OS_VERSION === "Android") (Screen.width % cellWidth) / 2; else (parent.width % cellWidth) / 2; }
|
||||
anchors.topMargin: (!window.lockTiles ? rootItem.topBarHeight + 30 : 0)
|
||||
id: gridView
|
||||
objectName: "gridview"
|
||||
onMovementEnded: { headerToolbar.visible = (contentY == 0) || window.lockTiles; }
|
||||
Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.PortraitOrientation
|
||||
Screen.onPrimaryOrientationChanged:{
|
||||
if(OS_VERSION === "Android")
|
||||
gridView.leftMargin = (Screen.width % cellWidth) / 2;
|
||||
else
|
||||
gridView.leftMargin = (parent.width % cellWidth) / 2;
|
||||
GridView {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.fill: parent
|
||||
cellWidth: 175 * settings.ui_zoom / 100
|
||||
cellHeight: 130 * settings.ui_zoom / 100
|
||||
focus: true
|
||||
model: appModel
|
||||
leftMargin: { if(OS_VERSION === "Android") (Screen.width % cellWidth) / 2; else (parent.width % cellWidth) / 2; }
|
||||
anchors.topMargin: (!window.lockTiles ? rootItem.topBarHeight + 30 : 0)
|
||||
id: gridView
|
||||
objectName: "gridview"
|
||||
onMovementEnded: { headerToolbar.visible = (contentY == 0) || window.lockTiles; }
|
||||
Screen.orientationUpdateMask: Qt.LandscapeOrientation | Qt.PortraitOrientation
|
||||
Screen.onPrimaryOrientationChanged:{
|
||||
if(OS_VERSION === "Android")
|
||||
gridView.leftMargin = (Screen.width % cellWidth) / 2;
|
||||
else
|
||||
gridView.leftMargin = (parent.width % cellWidth) / 2;
|
||||
}
|
||||
|
||||
// highlight: Rectangle {
|
||||
// width: 150
|
||||
// height: 150
|
||||
// color: "lightsteelblue"
|
||||
// }
|
||||
delegate: Item {
|
||||
id: id1
|
||||
width: 170 * settings.ui_zoom / 100
|
||||
height: 125 * settings.ui_zoom / 100
|
||||
|
||||
visible: visibleItem
|
||||
Component.onCompleted: console.log("completed " + objectName)
|
||||
|
||||
Behavior on x {
|
||||
enabled: id1.state != "active"
|
||||
NumberAnimation { duration: 400; easing.type: Easing.OutBack }
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
enabled: id1.state != "active"
|
||||
NumberAnimation { duration: 400; easing.type: Easing.OutBack }
|
||||
}
|
||||
|
||||
SequentialAnimation on rotation {
|
||||
NumberAnimation { to: 2; duration: 60 }
|
||||
NumberAnimation { to: -2; duration: 120 }
|
||||
NumberAnimation { to: 0; duration: 60 }
|
||||
running: loc.currentId !== -1 && id1.state !== "active" && window.lockTiles
|
||||
loops: Animation.Infinite; alwaysRunToEnd: true
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "active"; when: loc.currentId === gridId && window.lockTiles
|
||||
PropertyChanges { target: id1; x: loc.mouseX - gridView.x - width/2; y: loc.mouseY - gridView.y - height/2; scale: 0.5; z: 10 }
|
||||
}
|
||||
|
||||
transitions: Transition { NumberAnimation { property: "scale"; duration: 200} }
|
||||
|
||||
Rectangle {
|
||||
width: 168 * settings.ui_zoom / 100
|
||||
height: 123 * settings.ui_zoom / 100
|
||||
radius: 3
|
||||
border.width: 1
|
||||
border.color: "purple"
|
||||
color: Material.backgroundColor
|
||||
id: rect
|
||||
}
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: rect
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: Material.color(Material.Purple)
|
||||
source: rect
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: toggleIconTimer
|
||||
interval: 500; running: true; repeat: true
|
||||
onTriggered: { if(identificator === "inclination" && rootItem.autoInclinationEnabled()) myIcon.visible = !myIcon.visible; else myIcon.visible = true; }
|
||||
}
|
||||
|
||||
Image {
|
||||
id: myIcon
|
||||
x: 5
|
||||
anchors {
|
||||
bottom: id1.bottom
|
||||
}
|
||||
width: 48 * settings.ui_zoom / 100
|
||||
height: 48 * settings.ui_zoom / 100
|
||||
source: icon
|
||||
visible: !largeButton
|
||||
}
|
||||
Text {
|
||||
objectName: "value"
|
||||
id: myValue
|
||||
color: valueFontColor
|
||||
y: 0
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
text: value
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: valueFontSize * settings.ui_zoom / 100
|
||||
font.bold: true
|
||||
visible: !largeButton
|
||||
}
|
||||
Text {
|
||||
objectName: "secondLine"
|
||||
id: secondLineText
|
||||
color: "white"
|
||||
y: myValue.bottom
|
||||
anchors {
|
||||
top: myValue.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
text: secondLine
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: 12 * settings.ui_zoom / 100
|
||||
font.bold: false
|
||||
visible: !largeButton
|
||||
}
|
||||
Text {
|
||||
id: myText
|
||||
anchors {
|
||||
top: myIcon.top
|
||||
}
|
||||
font.bold: true
|
||||
font.pointSize: labelFontSize
|
||||
color: "white"
|
||||
text: name
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 55 * settings.ui_zoom / 100
|
||||
anchors.topMargin: 20 * settings.ui_zoom / 100
|
||||
visible: !largeButton
|
||||
}
|
||||
RoundButton {
|
||||
objectName: minusName
|
||||
autoRepeat: true
|
||||
text: "-"
|
||||
onClicked: minus_clicked(objectName)
|
||||
visible: writable && !largeButton
|
||||
anchors.top: myValue.top
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 2
|
||||
width: 48 * settings.ui_zoom / 100
|
||||
height: 48 * settings.ui_zoom / 100
|
||||
}
|
||||
RoundButton {
|
||||
autoRepeat: true
|
||||
objectName: plusName
|
||||
text: "+"
|
||||
onClicked: plus_clicked(objectName)
|
||||
visible: writable && !largeButton
|
||||
anchors.top: myValue.top
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 2
|
||||
width: 48 * settings.ui_zoom / 100
|
||||
height: 48 * settings.ui_zoom / 100
|
||||
}
|
||||
RoundButton {
|
||||
autoRepeat: true
|
||||
objectName: identificator
|
||||
text: largeButtonLabel
|
||||
onClicked: largeButton_clicked(objectName)
|
||||
visible: largeButton
|
||||
anchors.fill: rect
|
||||
background: Rectangle {
|
||||
color: largeButtonColor
|
||||
radius: 20
|
||||
}
|
||||
font.pointSize: 16 * settings.ui_zoom / 100
|
||||
//width: 48 * settings.ui_zoom / 100
|
||||
//height: 48 * settings.ui_zoom / 100
|
||||
}
|
||||
|
||||
/*MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: parent.GridView.view.currentIndex = index
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
// highlight: Rectangle {
|
||||
// width: 150
|
||||
// height: 150
|
||||
// color: "lightsteelblue"
|
||||
// }
|
||||
delegate: Item {
|
||||
id: id1
|
||||
width: 170 * settings.ui_zoom / 100
|
||||
height: 125 * settings.ui_zoom / 100
|
||||
|
||||
visible: visibleItem
|
||||
Component.onCompleted: console.log("completed " + objectName)
|
||||
|
||||
Behavior on x {
|
||||
enabled: id1.state != "active"
|
||||
NumberAnimation { duration: 400; easing.type: Easing.OutBack }
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
enabled: id1.state != "active"
|
||||
NumberAnimation { duration: 400; easing.type: Easing.OutBack }
|
||||
}
|
||||
|
||||
SequentialAnimation on rotation {
|
||||
NumberAnimation { to: 2; duration: 60 }
|
||||
NumberAnimation { to: -2; duration: 120 }
|
||||
NumberAnimation { to: 0; duration: 60 }
|
||||
running: loc.currentId !== -1 && id1.state !== "active" && window.lockTiles
|
||||
loops: Animation.Infinite; alwaysRunToEnd: true
|
||||
}
|
||||
|
||||
states: State {
|
||||
name: "active"; when: loc.currentId === gridId && window.lockTiles
|
||||
PropertyChanges { target: id1; x: loc.mouseX - gridView.x - width/2; y: loc.mouseY - gridView.y - height/2; scale: 0.5; z: 10 }
|
||||
}
|
||||
|
||||
transitions: Transition { NumberAnimation { property: "scale"; duration: 200} }
|
||||
|
||||
footer:
|
||||
Rectangle {
|
||||
width: 168 * settings.ui_zoom / 100
|
||||
height: 123 * settings.ui_zoom / 100
|
||||
radius: 3
|
||||
border.width: 1
|
||||
border.color: "purple"
|
||||
color: Material.backgroundColor
|
||||
id: rect
|
||||
}
|
||||
objectName: "footerrectangle"
|
||||
visible: rootItem.videoVisible
|
||||
anchors.top: gridView.bottom
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
|
||||
DropShadow {
|
||||
anchors.fill: rect
|
||||
cached: true
|
||||
horizontalOffset: 3
|
||||
verticalOffset: 3
|
||||
radius: 8.0
|
||||
samples: 16
|
||||
color: Material.color(Material.Purple)
|
||||
source: rect
|
||||
}
|
||||
Timer {
|
||||
id: pauseTimer
|
||||
interval: 1000; running: true; repeat: true
|
||||
onTriggered: { if(visible == true) { (rootItem.currentSpeed > 0 ?
|
||||
videoPlaybackHalf.play() :
|
||||
videoPlaybackHalf.pause()) } }
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: toggleIconTimer
|
||||
interval: 500; running: true; repeat: true
|
||||
onTriggered: { if(identificator === "inclination" && rootItem.autoInclinationEnabled()) myIcon.visible = !myIcon.visible; else myIcon.visible = true; }
|
||||
}
|
||||
onVisibleChanged: {
|
||||
if(visible === true) {
|
||||
console.log("mediaPlayer onCompleted: " + rootItem.videoPath)
|
||||
console.log("videoRate: " + rootItem.videoRate)
|
||||
videoPlaybackHalf.source = rootItem.videoPath
|
||||
//videoPlaybackHalf.playbackRate = rootItem.videoRate
|
||||
|
||||
Image {
|
||||
id: myIcon
|
||||
x: 5
|
||||
anchors {
|
||||
bottom: id1.bottom
|
||||
}
|
||||
width: 48 * settings.ui_zoom / 100
|
||||
height: 48 * settings.ui_zoom / 100
|
||||
source: icon
|
||||
}
|
||||
Text {
|
||||
objectName: "value"
|
||||
id: myValue
|
||||
color: valueFontColor
|
||||
y: 0
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
text: value
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: valueFontSize * settings.ui_zoom / 100
|
||||
font.bold: true
|
||||
}
|
||||
Text {
|
||||
objectName: "secondLine"
|
||||
id: secondLineText
|
||||
color: "white"
|
||||
y: myValue.bottom
|
||||
anchors {
|
||||
top: myValue.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
text: secondLine
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pointSize: 12 * settings.ui_zoom / 100
|
||||
font.bold: false
|
||||
}
|
||||
Text {
|
||||
id: myText
|
||||
anchors {
|
||||
top: myIcon.top
|
||||
}
|
||||
font.bold: true
|
||||
font.pointSize: labelFontSize
|
||||
color: "white"
|
||||
text: name
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 55 * settings.ui_zoom / 100
|
||||
anchors.topMargin: 20 * settings.ui_zoom / 100
|
||||
}
|
||||
RoundButton {
|
||||
objectName: minusName
|
||||
autoRepeat: true
|
||||
text: "-"
|
||||
onClicked: minus_clicked(objectName)
|
||||
visible: writable
|
||||
anchors.top: myValue.top
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 2
|
||||
width: 48 * settings.ui_zoom / 100
|
||||
height: 48 * settings.ui_zoom / 100
|
||||
}
|
||||
RoundButton {
|
||||
autoRepeat: true
|
||||
objectName: plusName
|
||||
text: "+"
|
||||
onClicked: plus_clicked(objectName)
|
||||
visible: writable
|
||||
anchors.top: myValue.top
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 2
|
||||
width: 48 * settings.ui_zoom / 100
|
||||
height: 48 * settings.ui_zoom / 100
|
||||
}
|
||||
videoPlaybackHalf.seek(rootItem.videoPosition)
|
||||
videoPlaybackHalf.play()
|
||||
videoPlaybackHalf.muted = true
|
||||
} else {
|
||||
videoPlaybackHalf.stop()
|
||||
}
|
||||
|
||||
/*MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: parent.GridView.view.currentIndex = index
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MediaPlayer {
|
||||
id: videoPlaybackHalf
|
||||
objectName: "videoplaybackhalf"
|
||||
autoPlay: false
|
||||
playbackRate: rootItem.videoRate
|
||||
|
||||
onError: {
|
||||
if (videoPlaybackHalf.NoError !== error) {
|
||||
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
id:videoPlayer
|
||||
anchors.fill: parent
|
||||
source: videoPlaybackHalf
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
property int currentId: -1 // Original position in model
|
||||
|
||||
@@ -63,21 +63,35 @@ Item {
|
||||
color: "white"
|
||||
font.pointSize: 22
|
||||
wrapMode: TextArea.Wrap
|
||||
text: qsTr("Hi! Do you know that QZ is just an Open Souce Indie App?<br><br>No Big Companies are running this!<br>The \"Swag Bag\" is a way to support the ongoing development, maintenance and support of QZ Fitness!<br><br>Thanks to Rungap App to give me the idea of the name!")
|
||||
text: qsTr("Hi! Do you know that QZ is just an Open Source Indie App?<br><br>No Big Companies are running this!<br>The \"Swag Bag\" is a way to support the ongoing development, maintenance and support of QZ Fitness!")
|
||||
}
|
||||
|
||||
Column {
|
||||
//anchors.top: description.bottom + 10
|
||||
anchors.top: description.bottom
|
||||
//anchors.bottom: restoreButton.top
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
id: itemSwagBag
|
||||
|
||||
SwagBagItem {
|
||||
product: productUnlockVowels
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
Text {
|
||||
anchors {
|
||||
top: itemSwagBag.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
padding: 5
|
||||
id: appleDescription
|
||||
width: parent.width
|
||||
color: "white"
|
||||
font.pointSize: 8
|
||||
wrapMode: TextArea.Wrap
|
||||
text: qsTr("<html><style type='text/css'></style>Swag bag feature:<br>• an auto-renewable subscription<br>• 1 month ($1.99)<br>• Your subscription will be charged to your iTunes account at confirmation of purchase and will automatically renew (at the duration selected) unless auto-renew is turned off at least 24 hours before the end of the current period.<br>• Current subscription may not be cancelled during the active subscription period; however, you can manage your subscription and/or turn off auto-renewal by visiting your iTunes Account Settings after purchase.<br>• Privacy policy: <a href='https://robertoviola.cloud/privacy-policy-qdomyos-zwift/'>https://robertoviola.cloud/privacy-policy-qdomyos-zwift/</a><br>• Licensed Application end user license agreement: <a href='https://www.apple.com/legal/internet-services/itunes/dev/stdeula/'>https://www.apple.com/legal/internet-services/itunes/dev/stdeula/</a><br></html>")
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
/*Button {
|
||||
id: restoreButton
|
||||
|
||||
@@ -59,6 +59,12 @@ ColumnLayout {
|
||||
id: filterField
|
||||
onTextChanged: updateFilter()
|
||||
}
|
||||
Button {
|
||||
anchors.left: mainRect.right
|
||||
anchors.leftMargin: 5
|
||||
text: "←"
|
||||
onClicked: folderModel.folder = folderModel.parentFolder
|
||||
}
|
||||
}
|
||||
|
||||
ListView {
|
||||
@@ -74,8 +80,10 @@ ColumnLayout {
|
||||
id: folderModel
|
||||
nameFilters: ["*.xml", "*.zwo"]
|
||||
folder: "file://" + rootItem.getWritableAppDir() + 'training'
|
||||
showDotAndDotDot: false
|
||||
showDotAndDotDot: false
|
||||
showDirs: true
|
||||
sortField: "Name"
|
||||
showDirsFirst: true
|
||||
}
|
||||
model: folderModel
|
||||
delegate: Component {
|
||||
@@ -83,7 +91,7 @@ ColumnLayout {
|
||||
property alias textColor: fileTextBox.color
|
||||
width: parent.width
|
||||
height: 40
|
||||
color: Material.backgroundColor
|
||||
color: Material.backgroundColor
|
||||
z: 1
|
||||
Item {
|
||||
id: root
|
||||
@@ -94,7 +102,7 @@ ColumnLayout {
|
||||
clip: true
|
||||
Text {
|
||||
id: fileTextBox
|
||||
color: Material.color(Material.Grey)
|
||||
color: (!folderModel.isFolder(index)?Material.color(Material.Grey):Material.color(Material.Orange))
|
||||
font.pixelSize: Qt.application.font.pixelSize * 1.6
|
||||
text: fileName.substring(0, fileName.length-4)
|
||||
NumberAnimation on x {
|
||||
@@ -122,10 +130,12 @@ ColumnLayout {
|
||||
console.log('onclicked ' + index+ " count "+list.count);
|
||||
if (index == list.currentIndex) {
|
||||
let fileUrl = folderModel.get(list.currentIndex, 'fileUrl') || folderModel.get(list.currentIndex, 'fileURL');
|
||||
if (fileUrl) {
|
||||
if (fileUrl && !folderModel.isFolder(list.currentIndex)) {
|
||||
trainprogram_open_clicked(fileUrl);
|
||||
popup.open()
|
||||
}
|
||||
} else {
|
||||
folderModel.folder = fileURL
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (list.currentItem)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "activiotreadmill.h"
|
||||
|
||||
#include "activiotreadmill.h"
|
||||
#include "ios/lockscreen.h"
|
||||
#include "keepawakehelper.h"
|
||||
#include "virtualtreadmill.h"
|
||||
@@ -34,7 +33,7 @@ activiotreadmill::activiotreadmill(uint32_t pollDeviceTime, bool noConsole, bool
|
||||
refresh->start(pollDeviceTime);
|
||||
}
|
||||
|
||||
void activiotreadmill::writeCharacteristic(const QLowEnergyCharacteristic characteristc, uint8_t *data,
|
||||
void activiotreadmill::writeCharacteristic(const QLowEnergyCharacteristic characteristic, uint8_t *data,
|
||||
uint8_t data_len, const QString &info, bool disable_log,
|
||||
bool wait_for_response) {
|
||||
QEventLoop loop;
|
||||
@@ -55,7 +54,7 @@ void activiotreadmill::writeCharacteristic(const QLowEnergyCharacteristic charac
|
||||
return;
|
||||
}
|
||||
|
||||
gattCommunicationChannelService->writeCharacteristic(characteristc, QByteArray((const char *)data, data_len));
|
||||
gattCommunicationChannelService->writeCharacteristic(characteristic, QByteArray((const char *)data, data_len));
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + QByteArray((const char *)data, data_len).toHex(' ') +
|
||||
@@ -75,7 +74,7 @@ void activiotreadmill::forceSpeed(double requestSpeed) {
|
||||
|
||||
writeSpeed[1] = (requestSpeed * 10);
|
||||
writeSpeed[5] += writeSpeed[1];
|
||||
if(!settings.value(QStringLiteral("fitfiu_mc_v460"), false).toBool())
|
||||
if(!settings.value(QZSettings::fitfiu_mc_v460, QZSettings::default_fitfiu_mc_v460).toBool())
|
||||
writeSpeed[6] = writeSpeed[1] + 1;
|
||||
else {
|
||||
switch(writeSpeed[1] & 0x0F) {
|
||||
@@ -169,8 +168,8 @@ void activiotreadmill::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && !virtualTreadMill && !virtualBike) {
|
||||
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
|
||||
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
@@ -191,7 +190,7 @@ void activiotreadmill::update() {
|
||||
|
||||
// debug("Domyos Treadmill RSSI " + QString::number(bluetoothDevice.rssi()));
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
{
|
||||
if (requestSpeed != -1) {
|
||||
@@ -283,7 +282,7 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
@@ -298,13 +297,13 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
|
||||
double speed = GetSpeedFromPacket(value);
|
||||
double incline = 1.0; // "fitfiu_mc_v460" has 1.0 fixed inclination
|
||||
if(!settings.value(QStringLiteral("fitfiu_mc_v460"), false).toBool())
|
||||
if(!settings.value(QZSettings::fitfiu_mc_v460, QZSettings::default_fitfiu_mc_v460).toBool())
|
||||
incline = GetInclinationFromPacket(value);
|
||||
// double kcal = GetKcalFromPacket(value);
|
||||
// double distance = GetDistanceFromPacket(value);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -331,10 +330,10 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
}
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
|
||||
@@ -53,7 +53,7 @@ class activiotreadmill : public treadmill {
|
||||
void forceSpeed(double requestSpeed);
|
||||
void forceIncline(double requestIncline);
|
||||
void btinit(bool startTape);
|
||||
void writeCharacteristic(const QLowEnergyCharacteristic characteristc, uint8_t *data, uint8_t data_len,
|
||||
void writeCharacteristic(const QLowEnergyCharacteristic characteristic, uint8_t *data, uint8_t data_len,
|
||||
const QString &info, bool disable_log = false, bool wait_for_response = false);
|
||||
void startDiscover();
|
||||
bool noConsole = false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.11.40" android:versionCode="381" android:installLocation="auto">
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="2.12.10" android:versionCode="440" android:installLocation="auto">
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
|
||||
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||
<application android:hardwareAccelerated="true" android:debuggable="false" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="qdomyos-zwift" android:extractNativeLibs="true" android:icon="@drawable/icon" android:usesCleartextTraffic="true">
|
||||
<activity android:exported="true" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="qdomyos-zwift" android:launchMode="singleTop">
|
||||
<activity android:exported="true" android:resizeableActivity="true" android:supportsPictureInPicture="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="qdomyos-zwift" android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
@@ -69,6 +69,10 @@
|
||||
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||
<!-- extract android style -->
|
||||
</activity>
|
||||
<service
|
||||
android:name=".ForegroundService"
|
||||
android:enabled="true"
|
||||
android:exported="true"></service>
|
||||
<service android:name=".ChannelService"></service>
|
||||
<activity android:name="org.cagnulen.qdomyoszwift.MyActivity" />
|
||||
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||
@@ -76,10 +80,14 @@
|
||||
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="com.android.vending.BILLING"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
</manifest>
|
||||
|
||||
@@ -19,6 +19,8 @@ apply plugin: 'com.android.application'
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation "com.android.billingclient:billing:4.0.0"
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
androidTestImplementation "com.android.support:support-annotations:28.0.0"
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class ChannelService extends Service {
|
||||
private AntChannelProvider mAntChannelProvider = null;
|
||||
private boolean mAllowAddChannel = false;
|
||||
|
||||
HeartChannelController heartChannelController = null;
|
||||
HeartChannelController heartChannelController = null;
|
||||
PowerChannelController powerChannelController = null;
|
||||
SpeedChannelController speedChannelController = null;
|
||||
|
||||
@@ -116,17 +116,14 @@ public class ChannelService extends Service {
|
||||
if (null != powerChannelController) {
|
||||
powerChannelController.cadence = cadence;
|
||||
}
|
||||
if (null != speedChannelController) {
|
||||
speedChannelController.cadence = cadence;
|
||||
}
|
||||
}
|
||||
|
||||
int getHeart() {
|
||||
if (null != heartChannelController) {
|
||||
return heartChannelController.heart;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int getHeart() {
|
||||
if (null != heartChannelController) {
|
||||
return heartChannelController.heart;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all channels currently added.
|
||||
@@ -134,28 +131,28 @@ public class ChannelService extends Service {
|
||||
void clearAllChannels() {
|
||||
closeAllChannels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void openAllChannels() throws ChannelNotAvailableException {
|
||||
if(Ant.heartRequest)
|
||||
heartChannelController = new HeartChannelController(acquireChannel());
|
||||
if (Ant.heartRequest)
|
||||
heartChannelController = new HeartChannelController(acquireChannel());
|
||||
|
||||
if(Ant.speedRequest) {
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
}
|
||||
if (Ant.speedRequest) {
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
}
|
||||
}
|
||||
|
||||
private void closeAllChannels() {
|
||||
if(heartChannelController != null)
|
||||
heartChannelController.close();
|
||||
if(powerChannelController != null)
|
||||
powerChannelController.close();
|
||||
if(speedChannelController != null)
|
||||
speedChannelController.close();
|
||||
heartChannelController = null;
|
||||
powerChannelController = null;
|
||||
speedChannelController = null;
|
||||
if (heartChannelController != null)
|
||||
heartChannelController.close();
|
||||
if (powerChannelController != null)
|
||||
powerChannelController.close();
|
||||
if (speedChannelController != null)
|
||||
speedChannelController.close();
|
||||
heartChannelController = null;
|
||||
powerChannelController = null;
|
||||
speedChannelController = null;
|
||||
}
|
||||
|
||||
AntChannel acquireChannel() throws ChannelNotAvailableException {
|
||||
@@ -171,19 +168,18 @@ public class ChannelService extends Service {
|
||||
* acquireChannel(context, PredefinedNetwork,
|
||||
* requiredCapabilities, desiredCapabilities).
|
||||
*/
|
||||
if(Ant.garminKey == false)
|
||||
mAntChannel = mAntChannelProvider.acquireChannel(this, PredefinedNetwork.ANT_PLUS_1);
|
||||
else
|
||||
{
|
||||
NetworkKey mNK = new NetworkKey(new byte[] { (byte)0xb9, (byte)0xa5, (byte)0x21, (byte)0xfb,
|
||||
(byte)0xbd, (byte)0x72, (byte)0xc3, (byte)0x45 });
|
||||
Log.v(TAG, mNK.toString());
|
||||
mAntChannel = mAntChannelProvider.acquireChannelOnPrivateNetwork(this, mNK);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.v(TAG, "ACP Remote Ex");
|
||||
} catch (UnsupportedFeatureException e) {
|
||||
Log.v(TAG, "ACP UnsupportedFeature Ex");
|
||||
if (Ant.garminKey == false)
|
||||
mAntChannel = mAntChannelProvider.acquireChannel(this, PredefinedNetwork.ANT_PLUS_1);
|
||||
else {
|
||||
NetworkKey mNK = new NetworkKey(new byte[]{(byte) 0xb9, (byte) 0xa5, (byte) 0x21, (byte) 0xfb,
|
||||
(byte) 0xbd, (byte) 0x72, (byte) 0xc3, (byte) 0x45});
|
||||
Log.v(TAG, mNK.toString());
|
||||
mAntChannel = mAntChannelProvider.acquireChannelOnPrivateNetwork(this, mNK);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.v(TAG, "ACP Remote Ex");
|
||||
} catch (UnsupportedFeatureException e) {
|
||||
Log.v(TAG, "ACP UnsupportedFeature Ex");
|
||||
}
|
||||
}
|
||||
return mAntChannel;
|
||||
|
||||
57
src/android/src/ForegroundService.java
Normal file
57
src/android/src/ForegroundService.java
Normal file
@@ -0,0 +1,57 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
public class ForegroundService extends Service {
|
||||
public static final String CHANNEL_ID = "ForegroundServiceChannel";
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
}
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
String input = intent.getStringExtra("inputExtra");
|
||||
createNotificationChannel();
|
||||
Intent notificationIntent = new Intent();
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(this,
|
||||
0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);
|
||||
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
|
||||
.setContentTitle("QZ is Running")
|
||||
.setContentText(input)
|
||||
.setSmallIcon(R.drawable.icon)
|
||||
.setContentIntent(pendingIntent)
|
||||
.build();
|
||||
startForeground(1, notification);
|
||||
//do heavy work on a background thread
|
||||
//stopSelf();
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
private void createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel serviceChannel = new NotificationChannel(
|
||||
CHANNEL_ID,
|
||||
"Foreground Service Channel",
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
);
|
||||
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||
manager.createNotificationChannel(serviceChannel);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/android/src/NotificationClient.java
Normal file
28
src/android/src/NotificationClient.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.app.PendingIntent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.app.NotificationChannel;
|
||||
|
||||
public class NotificationClient
|
||||
{
|
||||
private static NotificationManager m_notificationManager;
|
||||
private static Notification.Builder m_builder;
|
||||
|
||||
public NotificationClient() {}
|
||||
|
||||
public static void notify(Context context, String message) {
|
||||
Intent serviceIntent = new Intent(context, ForegroundService.class);
|
||||
serviceIntent.putExtra("inputExtra", "QZ is Running");
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
|
||||
context.startForegroundService(serviceIntent);
|
||||
} else {
|
||||
context.startService(serviceIntent);
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/android/src/PiP.java
Normal file
54
src/android/src/PiP.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
import android.util.Log;
|
||||
import android.content.Intent;
|
||||
import android.app.PictureInPictureParams;
|
||||
import android.util.Rational;
|
||||
import android.provider.Settings;
|
||||
import android.view.Display;
|
||||
import android.graphics.Point;
|
||||
|
||||
public class PiP {
|
||||
|
||||
public static void enterPiP(Activity a) {
|
||||
Display d = a.getWindowManager()
|
||||
.getDefaultDisplay();
|
||||
Point p = new Point();
|
||||
d.getSize(p);
|
||||
int width = p.x;
|
||||
int height = p.y;
|
||||
|
||||
Rational ratio
|
||||
= new Rational(width, height);
|
||||
PictureInPictureParams.Builder
|
||||
pip_Builder
|
||||
= new PictureInPictureParams
|
||||
.Builder();
|
||||
pip_Builder.setAspectRatio(ratio).build();
|
||||
Log.v("QZ", "Pip");
|
||||
a.enterPictureInPictureMode(pip_Builder.build());
|
||||
}
|
||||
}
|
||||
@@ -42,16 +42,12 @@ public class SpeedChannelController {
|
||||
private static final String TAG = SpeedChannelController.class.getSimpleName();
|
||||
public static final int SPEED_SENSOR_ID = 0x9e3d4b65;
|
||||
|
||||
private static Random randGen = new Random();
|
||||
|
||||
private AntChannel mAntChannel;
|
||||
|
||||
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
|
||||
|
||||
|
||||
private boolean mIsOpen;
|
||||
double speed = 0.0;
|
||||
double cadence = 0.0;
|
||||
|
||||
public SpeedChannelController(AntChannel antChannel) {
|
||||
mAntChannel = antChannel;
|
||||
@@ -111,7 +107,7 @@ public class SpeedChannelController {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
}
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
@@ -174,7 +170,6 @@ public class SpeedChannelController {
|
||||
int rev;
|
||||
double remWay;
|
||||
double wheel = 0.1;
|
||||
long unixTime = 0;
|
||||
|
||||
@Override
|
||||
public void onChannelDeath() {
|
||||
@@ -207,11 +202,15 @@ public class SpeedChannelController {
|
||||
// Switching on event code to handle the different types of channel events
|
||||
switch (code) {
|
||||
case TX:
|
||||
if(speed > 0)
|
||||
{
|
||||
revCounts++;
|
||||
unixTime += (long)(1024.0 / (((double)(speed)) / 60.0));
|
||||
}
|
||||
long unixTime = System.currentTimeMillis() / 1000L;
|
||||
|
||||
if (lastTime != 0) {
|
||||
way = speed * (unixTime - lastTime) / 3.6 + remWay;
|
||||
rev = (int) (way / wheel + 0.5);
|
||||
remWay = way - rev * wheel;
|
||||
revCounts += rev;
|
||||
}
|
||||
lastTime = unixTime;
|
||||
|
||||
ucPageChange += 0x20;
|
||||
ucPageChange &= 0xF0;
|
||||
@@ -228,14 +227,12 @@ public class SpeedChannelController {
|
||||
payload[1] = (byte) (halfunixTime & 0xFF);
|
||||
payload[2] = (byte) ((halfunixTime >> 8) & 0xFF);
|
||||
payload[3] = (byte) ((halfunixTime >> 16) & 0xFF);
|
||||
}
|
||||
else if (ucExtMesgType == 2) {
|
||||
} else if (ucExtMesgType == 2) {
|
||||
payload[0] = (byte) ((byte) 0x02 | (byte) (ucPageChange & (byte) 0x80));
|
||||
payload[1] = (byte) 0xFF;
|
||||
payload[2] = (byte) ((SPEED_SENSOR_ID >> 16) & 0xFF);
|
||||
payload[3] = (byte) ((SPEED_SENSOR_ID >> 24) & 0xFF);
|
||||
}
|
||||
else if (ucExtMesgType == 3) {
|
||||
} else if (ucExtMesgType == 3) {
|
||||
payload[0] = (byte) ((byte) 0x03 | (byte) (ucPageChange & (byte) 0x80));
|
||||
payload[1] = (byte) 0x01;
|
||||
payload[2] = (byte) 0x01;
|
||||
|
||||
@@ -181,6 +181,20 @@ public class InAppPurchase implements PurchasesUpdatedListener
|
||||
purchaseFailed(purchaseRequestCode, FAILUREREASON_ERROR, e.getMessage());
|
||||
}
|
||||
purchaseSucceeded(purchaseRequestCode, purchase.getSignature(), purchase.getOriginalJson(), purchase.getPurchaseToken(), purchase.getOrderId(), purchase.getPurchaseTime());
|
||||
AcknowledgePurchaseParams acknowledgePurchaseParams =
|
||||
AcknowledgePurchaseParams.newBuilder()
|
||||
.setPurchaseToken(purchase.getPurchaseToken())
|
||||
.build();
|
||||
billingClient.acknowledgePurchase(acknowledgePurchaseParams,
|
||||
new AcknowledgePurchaseResponseListener()
|
||||
{
|
||||
@Override
|
||||
public void onAcknowledgePurchaseResponse(BillingResult billingResult)
|
||||
{
|
||||
Log.d(TAG, "Purchase acknowledged ");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@ bhfitnesselliptical::bhfitnesselliptical(bool noWriteResistance, bool noHeartSer
|
||||
initDone = false;
|
||||
connect(refresh, &QTimer::timeout, this, &bhfitnesselliptical::update);
|
||||
refresh->start(200ms);
|
||||
|
||||
// this bike doesn't send resistance, so I have to use the default value
|
||||
Resistance = default_resistance;
|
||||
}
|
||||
|
||||
void bhfitnesselliptical::writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log,
|
||||
@@ -55,11 +58,15 @@ void bhfitnesselliptical::writeCharacteristic(uint8_t *data, uint8_t data_len, c
|
||||
|
||||
void bhfitnesselliptical::forceResistance(resistance_t requestResistance) {
|
||||
|
||||
uint8_t write[] = {FTMS_SET_TARGET_RESISTANCE_LEVEL, 0x00};
|
||||
uint8_t write[] = {FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS, 0x00, 0x00, 0x00, 0x00, 0x21, 0x22};
|
||||
|
||||
write[1] = ((uint16_t)requestResistance) & 0xFF;
|
||||
write[3] = ((int16_t)(requestResistance - default_resistance) * 33) & 0xFF;
|
||||
write[4] = ((int16_t)(requestResistance - default_resistance) * 33) >> 8;
|
||||
|
||||
writeCharacteristic(write, sizeof(write), QStringLiteral("forceResistance ") + QString::number(requestResistance));
|
||||
|
||||
// this bike doesn't send resistance, so I have to use the value forced
|
||||
Resistance = requestResistance;
|
||||
}
|
||||
|
||||
void bhfitnesselliptical::update() {
|
||||
@@ -69,6 +76,7 @@ void bhfitnesselliptical::update() {
|
||||
}
|
||||
|
||||
if (initRequest) {
|
||||
|
||||
initRequest = false;
|
||||
} else if (bluetoothDevice.isValid() &&
|
||||
m_control->state() == QLowEnergyController::DiscoveredState //&&
|
||||
@@ -85,16 +93,15 @@ void bhfitnesselliptical::update() {
|
||||
}
|
||||
|
||||
if (requestResistance != -1) {
|
||||
if (requestResistance > 100) {
|
||||
requestResistance = 100;
|
||||
} // TODO, use the bluetooth value
|
||||
else if (requestResistance == 0) {
|
||||
requestResistance = 1;
|
||||
if (requestResistance > max_resistance) {
|
||||
requestResistance = max_resistance;
|
||||
}
|
||||
|
||||
if (requestResistance != currentResistance().value()) {
|
||||
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
|
||||
forceResistance(requestResistance);
|
||||
if (((virtualBike && !virtualBike->ftmsDeviceConnected()) || !virtualBike)) {
|
||||
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
|
||||
forceResistance(requestResistance);
|
||||
}
|
||||
}
|
||||
requestResistance = -1;
|
||||
}
|
||||
@@ -124,8 +131,9 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
bool disable_hr_frommachinery = settings.value(QStringLiteral("heart_ignore_builtin"), false).toBool();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
bool disable_hr_frommachinery =
|
||||
settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
@@ -168,14 +176,17 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
index += 2;
|
||||
|
||||
if (!Flags.moreData) {
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
// this elliptical doesn't send speed so i have to calculate this based on cadence
|
||||
/*
|
||||
Speed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;*/
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0),
|
||||
0 /* not useful for elliptical*/);
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
@@ -191,7 +202,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
}
|
||||
|
||||
if (Flags.instantCadence) {
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
@@ -199,7 +210,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
2.0;
|
||||
|
||||
// this elliptical doesn't send speed so i have to calculate this based on cadence
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = Cadence.value() / 10.0;
|
||||
}
|
||||
}
|
||||
@@ -238,7 +249,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
}
|
||||
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QStringLiteral("power_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
@@ -267,8 +278,8 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
} else {
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() *
|
||||
3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
@@ -278,7 +289,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -328,10 +339,10 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
/*
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualTreadmill_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround,
|
||||
QZSettings::default_ios_peloton_workaround).toBool(); if (ios_peloton_workaround && cadence && h &&
|
||||
firstStateChanged) { h->virtualTreadmill_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualTreadmill_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
}
|
||||
*/
|
||||
@@ -427,7 +438,7 @@ void bhfitnesselliptical::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
}
|
||||
|
||||
// ******************************************* virtual bike init *************************************
|
||||
if (!firstStateChanged && !virtualTreadmill
|
||||
if (!firstStateChanged
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
&& !h
|
||||
@@ -435,25 +446,53 @@ void bhfitnesselliptical::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
emit debug(QStringLiteral("creating virtual treadmill interface..."));
|
||||
virtualTreadmill = new virtualtreadmill(this, noHeartService);
|
||||
// connect(virtualTreadmill,&virtualTreadmill::debug ,this,&bhfitnesselliptical::debug);
|
||||
connect(virtualTreadmill, &virtualtreadmill::changeInclination, this,
|
||||
&bhfitnesselliptical::changeInclination);
|
||||
if (!virtualTreadmill && !virtualBike) {
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike =
|
||||
settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike)
|
||||
.toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
virtualTreadmill = new virtualtreadmill(this, noHeartService);
|
||||
connect(virtualTreadmill, &virtualtreadmill::debug, this, &bhfitnesselliptical::debug);
|
||||
connect(virtualTreadmill, &virtualtreadmill::changeInclination, this,
|
||||
&bhfitnesselliptical::changeInclinationRequested);
|
||||
} else {
|
||||
debug("creating virtual bike interface...");
|
||||
virtualBike = new virtualbike(this);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this,
|
||||
&bhfitnesselliptical::changeInclinationRequested);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this,
|
||||
&bhfitnesselliptical::changeInclination);
|
||||
connect(virtualBike, &virtualbike::ftmsCharacteristicChanged, this,
|
||||
&bhfitnesselliptical::ftmsCharacteristicChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
firstStateChanged = 1;
|
||||
// ********************************************************************************************************
|
||||
}
|
||||
|
||||
void bhfitnesselliptical::changeInclinationRequested(double grade, double percentage) {
|
||||
if (percentage < 0)
|
||||
percentage = 0;
|
||||
changeInclination(grade, percentage);
|
||||
}
|
||||
|
||||
void bhfitnesselliptical::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic,
|
||||
const QByteArray &newValue) {
|
||||
QByteArray b = newValue;
|
||||
if (gattWriteCharControlPointId.isValid()) {
|
||||
qDebug() << "routing FTMS packet to the bike from virtualTreadmill" << characteristic.uuid()
|
||||
<< newValue.toHex(' ');
|
||||
qDebug() << "routing FTMS packet to the bike from virtualBike" << characteristic.uuid() << newValue.toHex(' ');
|
||||
|
||||
// handling reading current resistance
|
||||
if (b.at(0) == 0x11) {
|
||||
int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8));
|
||||
Resistance = (slope / 33) + default_resistance;
|
||||
}
|
||||
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, b);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <QString>
|
||||
|
||||
#include "elliptical.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualtreadmill.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
@@ -52,6 +53,7 @@ class bhfitnesselliptical : public elliptical {
|
||||
|
||||
QTimer *refresh;
|
||||
virtualtreadmill *virtualTreadmill = nullptr;
|
||||
virtualbike *virtualBike = nullptr;
|
||||
|
||||
QList<QLowEnergyService *> gattCommunicationChannelService;
|
||||
QLowEnergyCharacteristic gattWriteCharControlPointId;
|
||||
@@ -63,6 +65,8 @@ class bhfitnesselliptical : public elliptical {
|
||||
uint8_t firstStateChanged = 0;
|
||||
uint8_t bikeResistanceOffset = 4;
|
||||
double bikeResistanceGain = 1.0;
|
||||
const uint8_t max_resistance = 72; // 24;
|
||||
const uint8_t default_resistance = 6;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
@@ -96,6 +100,7 @@ class bhfitnesselliptical : public elliptical {
|
||||
void update();
|
||||
void error(QLowEnergyController::Error err);
|
||||
void errorService(QLowEnergyService::ServiceError);
|
||||
void changeInclinationRequested(double grade, double percentage);
|
||||
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
};
|
||||
|
||||
|
||||
14
src/bike.cpp
14
src/bike.cpp
@@ -39,12 +39,12 @@ void bike::changePower(int32_t power) {
|
||||
RequestedPower = power;
|
||||
requestPower = power; // used by some bikes that have ERG mode builtin
|
||||
QSettings settings;
|
||||
bool force_resistance = settings.value(QStringLiteral("virtualbike_forceresistance"), true).toBool();
|
||||
// bool erg_mode = settings.value(QStringLiteral("zwift_erg"), false).toBool(); //Not used anywhere in code
|
||||
double erg_filter_upper = settings.value(QStringLiteral("zwift_erg_filter"), 0.0).toDouble();
|
||||
double erg_filter_lower = settings.value(QStringLiteral("zwift_erg_filter_down"), 0.0).toDouble();
|
||||
double zwift_erg_resistance_up = settings.value(QStringLiteral("zwift_erg_resistance_up"), 999.0).toDouble();
|
||||
double zwift_erg_resistance_down = settings.value(QStringLiteral("zwift_erg_resistance_down"), 0.0).toDouble();
|
||||
bool force_resistance = settings.value(QZSettings::virtualbike_forceresistance, QZSettings::default_virtualbike_forceresistance).toBool();
|
||||
// bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool(); //Not used anywhere in code
|
||||
double erg_filter_upper = settings.value(QZSettings::zwift_erg_filter, QZSettings::default_zwift_erg_filter).toDouble();
|
||||
double erg_filter_lower = settings.value(QZSettings::zwift_erg_filter_down, QZSettings::default_zwift_erg_filter_down).toDouble();
|
||||
double zwift_erg_resistance_up = settings.value(QZSettings::zwift_erg_resistance_up, QZSettings::default_zwift_erg_resistance_up).toDouble();
|
||||
double zwift_erg_resistance_down = settings.value(QZSettings::zwift_erg_resistance_down, QZSettings::default_zwift_erg_resistance_down).toDouble();
|
||||
|
||||
double deltaDown = wattsMetric().value() - ((double)power);
|
||||
double deltaUp = ((double)power) - wattsMetric().value();
|
||||
@@ -162,7 +162,7 @@ uint8_t bike::metrics_override_heartrate() {
|
||||
|
||||
QSettings settings;
|
||||
QString setting =
|
||||
settings.value(QStringLiteral("peloton_heartrate_metric"), QStringLiteral("Heart Rate")).toString();
|
||||
settings.value(QZSettings::peloton_heartrate_metric, QZSettings::default_peloton_heartrate_metric).toString();
|
||||
if (!setting.compare(QStringLiteral("Heart Rate"))) {
|
||||
return qRound(currentHeart().value());
|
||||
} else if (!setting.compare(QStringLiteral("Speed"))) {
|
||||
|
||||
@@ -32,6 +32,8 @@ class bike : public bluetoothdevice {
|
||||
uint8_t metrics_override_heartrate();
|
||||
void setGears(int8_t d);
|
||||
int8_t gears();
|
||||
void setSpeedLimit(double speed) {m_speedLimit = speed;}
|
||||
double speedLimit() {return m_speedLimit;}
|
||||
|
||||
|
||||
/**
|
||||
@@ -80,6 +82,8 @@ class bike : public bluetoothdevice {
|
||||
metric m_pelotonResistance;
|
||||
|
||||
metric m_steeringAngle;
|
||||
|
||||
double m_speedLimit = 0;
|
||||
};
|
||||
|
||||
#endif // BIKE_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,8 @@
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
#include "qzsettings.h"
|
||||
|
||||
#include "activiotreadmill.h"
|
||||
#include "bhfitnesselliptical.h"
|
||||
#include "bluetoothdevice.h"
|
||||
@@ -37,6 +39,7 @@
|
||||
#include "eslinkertreadmill.h"
|
||||
#include "fakebike.h"
|
||||
#include "fakeelliptical.h"
|
||||
#include "faketreadmill.h"
|
||||
#include "fitmetria_fanfit.h"
|
||||
#include "fitplusbike.h"
|
||||
|
||||
@@ -52,15 +55,18 @@
|
||||
#include "keepbike.h"
|
||||
#include "kingsmithr1protreadmill.h"
|
||||
#include "kingsmithr2treadmill.h"
|
||||
#include "lifefitnesstreadmill.h"
|
||||
#include "m3ibike.h"
|
||||
#include "mcfbike.h"
|
||||
#include "mepanelbike.h"
|
||||
#include "nautilusbike.h"
|
||||
#include "nautiluselliptical.h"
|
||||
#include "nautilustreadmill.h"
|
||||
#include "nordictrackelliptical.h"
|
||||
#include "nordictrackifitadbtreadmill.h"
|
||||
#include "nordictrackifitadbbike.h"
|
||||
#include "nordictrackifitadbtreadmill.h"
|
||||
#include "npecablebike.h"
|
||||
#include "octaneelliptical.h"
|
||||
#include "octanetreadmill.h"
|
||||
#include "pafersbike.h"
|
||||
#include "paferstreadmill.h"
|
||||
@@ -151,6 +157,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
nordictrackelliptical *nordictrackElliptical = nullptr;
|
||||
nordictrackifitadbtreadmill *nordictrackifitadbTreadmill = nullptr;
|
||||
nordictrackifitadbbike *nordictrackifitadbBike = nullptr;
|
||||
octaneelliptical *octaneElliptical = nullptr;
|
||||
octanetreadmill *octaneTreadmill = nullptr;
|
||||
proformrower *proformRower = nullptr;
|
||||
proformbike *proformBike = nullptr;
|
||||
@@ -173,6 +180,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
snodebike *snodeBike = nullptr;
|
||||
eslinkertreadmill *eslinkerTreadmill = nullptr;
|
||||
m3ibike *m3iBike = nullptr;
|
||||
mepanelbike *mepanelBike = nullptr;
|
||||
skandikawiribike *skandikaWiriBike = nullptr;
|
||||
cscbike *cscBike = nullptr;
|
||||
mcfbike *mcfBike = nullptr;
|
||||
@@ -187,6 +195,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
ftmsrower *ftmsRower = nullptr;
|
||||
smartrowrower *smartrowRower = nullptr;
|
||||
echelonstride *echelonStride = nullptr;
|
||||
lifefitnesstreadmill *lifefitnessTreadmill = nullptr;
|
||||
keepbike *keepBike = nullptr;
|
||||
kingsmithr1protreadmill *kingsmithR1ProTreadmill = nullptr;
|
||||
kingsmithr2treadmill *kingsmithR2Treadmill = nullptr;
|
||||
@@ -209,6 +218,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
elitesterzosmart *eliteSterzoSmart = nullptr;
|
||||
fakebike *fakeBike = nullptr;
|
||||
fakeelliptical *fakeElliptical = nullptr;
|
||||
faketreadmill *fakeTreadmill = nullptr;
|
||||
QList<fitmetria_fanfit *> fitmetriaFanfit;
|
||||
QString filterDevice = QLatin1String("");
|
||||
|
||||
@@ -222,6 +232,16 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
double bikeResistanceGain = 1.0;
|
||||
bool forceHeartBeltOffForTimeout = false;
|
||||
|
||||
/**
|
||||
* @brief Start the Bluetooth discovery agent.
|
||||
*/
|
||||
void startDiscovery();
|
||||
|
||||
/**
|
||||
* @brief Stop the Bluetooth discovery agent.
|
||||
*/
|
||||
void stopDiscovery();
|
||||
|
||||
bool handleSignal(int signal) override;
|
||||
void stateFileUpdate();
|
||||
void stateFileRead();
|
||||
@@ -231,12 +251,18 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
bool powerSensorAvaiable();
|
||||
bool eliteRizerAvaiable();
|
||||
bool eliteSterzoSmartAvaiable();
|
||||
bool fitmetriaFanfitAvaiable();
|
||||
bool fitmetria_fanfit_isconnected(QString name);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QTimer discoveryTimeout;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Store the name and other info in the settings.
|
||||
* @param b The bluetooth device info.
|
||||
*/
|
||||
void setLastBluetoothDevice(const QBluetoothDeviceInfo &b);
|
||||
signals:
|
||||
void deviceConnected(QBluetoothDeviceInfo b);
|
||||
void deviceFound(QString name);
|
||||
|
||||
@@ -8,7 +8,11 @@ bluetoothdevice::bluetoothdevice() {}
|
||||
|
||||
bluetoothdevice::BLUETOOTH_TYPE bluetoothdevice::deviceType() { return bluetoothdevice::UNKNOWN; }
|
||||
void bluetoothdevice::start() { requestStart = 1; }
|
||||
void bluetoothdevice::stop() { requestStop = 1; }
|
||||
void bluetoothdevice::stop(bool pause) {
|
||||
requestStop = 1;
|
||||
if (pause)
|
||||
requestPause = 1;
|
||||
}
|
||||
metric bluetoothdevice::currentHeart() { return Heart; }
|
||||
metric bluetoothdevice::currentSpeed() { return Speed; }
|
||||
metric bluetoothdevice::currentInclination() { return Inclination; }
|
||||
@@ -38,7 +42,7 @@ void bluetoothdevice::offsetElapsedTime(int offset) { elapsed += offset; }
|
||||
|
||||
QTime bluetoothdevice::currentPace() {
|
||||
QSettings settings;
|
||||
bool miles = settings.value(QStringLiteral("miles_unit"), false).toBool();
|
||||
bool miles = settings.value(QZSettings::miles_unit, QZSettings::default_miles_unit).toBool();
|
||||
double unit_conversion = 1.0;
|
||||
if (miles) {
|
||||
unit_conversion = 0.621371;
|
||||
@@ -55,7 +59,7 @@ QTime bluetoothdevice::currentPace() {
|
||||
QTime bluetoothdevice::averagePace() {
|
||||
|
||||
QSettings settings;
|
||||
bool miles = settings.value(QStringLiteral("miles_unit"), false).toBool();
|
||||
bool miles = settings.value(QZSettings::miles_unit, QZSettings::default_miles_unit).toBool();
|
||||
double unit_conversion = 1.0;
|
||||
if (miles) {
|
||||
unit_conversion = 0.621371;
|
||||
@@ -72,7 +76,7 @@ QTime bluetoothdevice::averagePace() {
|
||||
QTime bluetoothdevice::maxPace() {
|
||||
|
||||
QSettings settings;
|
||||
bool miles = settings.value(QStringLiteral("miles_unit"), false).toBool();
|
||||
bool miles = settings.value(QZSettings::miles_unit, QZSettings::default_miles_unit).toBool();
|
||||
double unit_conversion = 1.0;
|
||||
if (miles) {
|
||||
unit_conversion = 0.621371;
|
||||
@@ -135,17 +139,19 @@ void bluetoothdevice::update_metrics(bool watt_calc, const double watts) {
|
||||
QDateTime current = QDateTime::currentDateTime();
|
||||
double deltaTime = (((double)_lastTimeUpdate.msecsTo(current)) / ((double)1000.0));
|
||||
QSettings settings;
|
||||
bool power_as_bike = settings.value(QStringLiteral("power_sensor_as_bike"), false).toBool();
|
||||
bool power_as_treadmill = settings.value(QStringLiteral("power_sensor_as_treadmill"), false).toBool();
|
||||
bool power_as_bike =
|
||||
settings.value(QZSettings::power_sensor_as_bike, QZSettings::default_power_sensor_as_bike).toBool();
|
||||
bool power_as_treadmill =
|
||||
settings.value(QZSettings::power_sensor_as_treadmill, QZSettings::default_power_sensor_as_treadmill).toBool();
|
||||
|
||||
if (settings.value(QStringLiteral("power_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")) == false &&
|
||||
!power_as_bike && !power_as_treadmill)
|
||||
watt_calc = false;
|
||||
|
||||
if (!_firstUpdate && !paused) {
|
||||
if (currentSpeed().value() > 0.0 || settings.value(QStringLiteral("continuous_moving"), true).toBool()) {
|
||||
if (currentSpeed().value() > 0.0 || settings.value(QZSettings::continuous_moving, true).toBool()) {
|
||||
|
||||
elapsed += deltaTime;
|
||||
}
|
||||
@@ -157,18 +163,21 @@ void bluetoothdevice::update_metrics(bool watt_calc, const double watts) {
|
||||
if (watt_calc) {
|
||||
m_watt = watts;
|
||||
}
|
||||
WattKg = m_watt.value() / settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
WattKg = m_watt.value() / settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
} else if (m_watt.value() > 0) {
|
||||
|
||||
m_watt = 0;
|
||||
if (watt_calc) {
|
||||
m_watt = 0;
|
||||
}
|
||||
WattKg = 0;
|
||||
}
|
||||
} else if (paused && settings.value(QStringLiteral("instant_power_on_pause"), false).toBool()) {
|
||||
} else if (paused && settings.value(QZSettings::instant_power_on_pause, QZSettings::default_instant_power_on_pause)
|
||||
.toBool()) {
|
||||
// useful for FTP test
|
||||
if (watt_calc) {
|
||||
m_watt = watts;
|
||||
}
|
||||
WattKg = m_watt.value() / settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
WattKg = m_watt.value() / settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
} else if (m_watt.value() > 0) {
|
||||
|
||||
m_watt = 0;
|
||||
@@ -267,7 +276,7 @@ uint8_t bluetoothdevice::metrics_override_heartrate() {
|
||||
|
||||
QSettings settings;
|
||||
QString setting =
|
||||
settings.value(QStringLiteral("peloton_heartrate_metric"), QStringLiteral("Heart Rate")).toString();
|
||||
settings.value(QZSettings::peloton_heartrate_metric, QZSettings::default_peloton_heartrate_metric).toString();
|
||||
if (!setting.compare(QStringLiteral("Heart Rate"))) {
|
||||
return currentHeart().value();
|
||||
} else if (!setting.compare(QStringLiteral("Speed"))) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "definitions.h"
|
||||
#include "metric.h"
|
||||
#include "qzsettings.h"
|
||||
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QBluetoothDeviceInfo>
|
||||
@@ -21,16 +22,12 @@
|
||||
#include <QtBluetooth/qlowenergyservice.h>
|
||||
#include <QtBluetooth/qlowenergyservicedata.h>
|
||||
|
||||
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
#define SAME_BLUETOOTH_DEVICE(d1, d2) (d1.deviceUuid() == d2.deviceUuid())
|
||||
#else
|
||||
#define SAME_BLUETOOTH_DEVICE(d1, d2) (d1.address() == d2.address())
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief The MetersByInclination class represents a section of track at a specific inclination.
|
||||
*/
|
||||
@@ -164,7 +161,6 @@ class bluetoothdevice : public QObject {
|
||||
*/
|
||||
virtual QGeoCoordinate currentCordinate();
|
||||
|
||||
|
||||
/**
|
||||
* @brief nextInclination300Meters The next 300m of track sections: length and inclination
|
||||
* @return A list of MetersByInclination objects
|
||||
@@ -293,12 +289,14 @@ class bluetoothdevice : public QObject {
|
||||
metric currentMETS() { return METS; }
|
||||
|
||||
/**
|
||||
* @brief currentHeartZone Gets a metric object to get or set the current heart zone. Units: depends on implementation.
|
||||
* @brief currentHeartZone Gets a metric object to get or set the current heart zone. Units: depends on
|
||||
* implementation.
|
||||
*/
|
||||
metric currentHeartZone() { return HeartZone; }
|
||||
|
||||
/**
|
||||
* @brief currentPowerZone Gets a metric object to get or set the current power zome. Units: depends on implementation.
|
||||
* @brief currentPowerZone Gets a metric object to get or set the current power zome. Units: depends on
|
||||
* implementation.
|
||||
* @return
|
||||
*/
|
||||
metric currentPowerZone() { return PowerZone; }
|
||||
@@ -357,7 +355,7 @@ class bluetoothdevice : public QObject {
|
||||
|
||||
public Q_SLOTS:
|
||||
virtual void start();
|
||||
virtual void stop();
|
||||
virtual void stop(bool pause);
|
||||
virtual void heartRate(uint8_t heart);
|
||||
virtual void cadenceSensor(uint8_t cadence);
|
||||
virtual void powerSensor(uint16_t power);
|
||||
@@ -392,7 +390,7 @@ class bluetoothdevice : public QObject {
|
||||
metric elapsed;
|
||||
|
||||
/**
|
||||
* @brief moving The time spent moving int he current session. Units: seconds
|
||||
* @brief moving The time spent moving in the current session. Units: seconds
|
||||
*/
|
||||
metric moving; // moving time
|
||||
|
||||
@@ -406,7 +404,7 @@ class bluetoothdevice : public QObject {
|
||||
* e.g. the product of bike flywheel speed and simulated wheel size, or
|
||||
* the belt speed of a treadmill.
|
||||
*/
|
||||
metric Speed;
|
||||
metric Speed;
|
||||
|
||||
/**
|
||||
* @brief Distance The simulated distance travelled. Units: km
|
||||
@@ -416,19 +414,19 @@ class bluetoothdevice : public QObject {
|
||||
*/
|
||||
metric Distance;
|
||||
|
||||
|
||||
/**
|
||||
* @brief FanSpeed The currently requested fan speed. Units: revolutions per second
|
||||
*/
|
||||
uint8_t FanSpeed = 0;
|
||||
|
||||
/**
|
||||
* @brief Heart rate. Unit: beats per minute
|
||||
* @brief Heart rate. Unit: beats per minute
|
||||
*/
|
||||
metric Heart;
|
||||
|
||||
int8_t requestStart = -1;
|
||||
int8_t requestStop = -1;
|
||||
int8_t requestPause = -1;
|
||||
int8_t requestIncreaseFan = -1;
|
||||
int8_t requestDecreaseFan = -1;
|
||||
double requestFanSpeed = -1;
|
||||
|
||||
@@ -93,7 +93,8 @@ void bowflext216treadmill::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && !virtualTreadMill) {
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
emit debug(QStringLiteral("creating virtual treadmill interface..."));
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
@@ -103,7 +104,7 @@ void bowflext216treadmill::update() {
|
||||
}
|
||||
// ********************************************************************************************************
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
// updating the treadmill console every second
|
||||
// it seems that stops the communication
|
||||
@@ -124,7 +125,7 @@ void bowflext216treadmill::update() {
|
||||
requestSpeed = -1;
|
||||
}
|
||||
if (requestInclination != -100) {
|
||||
if(requestInclination < 0)
|
||||
if (requestInclination < 0)
|
||||
requestInclination = 0;
|
||||
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
|
||||
requestInclination <= 15) {
|
||||
@@ -167,7 +168,7 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
@@ -188,13 +189,16 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
if ((newValue.length() != 20))
|
||||
return;
|
||||
|
||||
if (bowflex_t6 == true && newValue.at(1) != 0x00)
|
||||
return;
|
||||
|
||||
double speed = GetSpeedFromPacket(value);
|
||||
double incline = GetInclinationFromPacket(value);
|
||||
// double kcal = GetKcalFromPacket(value);
|
||||
// double distance = GetDistanceFromPacket(value);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -225,10 +229,11 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
}
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) +
|
||||
1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
@@ -249,9 +254,15 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
}
|
||||
|
||||
double bowflext216treadmill::GetSpeedFromPacket(const QByteArray &packet) {
|
||||
uint16_t convertedData = (packet.at(7) << 8) | packet.at(6);
|
||||
double data = (double)convertedData / 100.0f;
|
||||
return data * 1.60934;
|
||||
if(bowflex_t6 == false) {
|
||||
uint16_t convertedData = (packet.at(7) << 8) | packet.at(6);
|
||||
double data = (double)convertedData / 100.0f;
|
||||
return data * 1.60934;
|
||||
} else {
|
||||
uint16_t convertedData = (packet.at(13) << 8) | packet.at(12);
|
||||
double data = (double)convertedData / 100.0f;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
double bowflext216treadmill::GetKcalFromPacket(const QByteArray &packet) {
|
||||
@@ -360,6 +371,16 @@ void bowflext216treadmill::serviceScanDone(void) {
|
||||
|
||||
QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("edff9e80-cad7-11e5-ab63-0002a5d5c51b"));
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
if (gattCommunicationChannelService == nullptr) {
|
||||
qDebug() << "trying with the BOWFLEX T6 treadmill";
|
||||
bowflex_t6 = true;
|
||||
QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("15B7BF49-1693-481E-B877-69D33CE6BAFA"));
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
if (gattCommunicationChannelService == nullptr) {
|
||||
qDebug() << "WRONG SERVICE";
|
||||
return;
|
||||
}
|
||||
}
|
||||
connect(gattCommunicationChannelService, &QLowEnergyService::stateChanged, this,
|
||||
&bowflext216treadmill::stateChanged);
|
||||
gattCommunicationChannelService->discoverDetails();
|
||||
|
||||
@@ -79,6 +79,8 @@ class bowflext216treadmill : public treadmill {
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
|
||||
bool bowflex_t6 = false;
|
||||
|
||||
Q_SIGNALS:
|
||||
void disconnected();
|
||||
void debug(QString string);
|
||||
|
||||
@@ -95,7 +95,7 @@ void bowflextreadmill::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && !virtualTreadMill) {
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
emit debug(QStringLiteral("creating virtual treadmill interface..."));
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
@@ -105,7 +105,7 @@ void bowflextreadmill::update() {
|
||||
}
|
||||
// ********************************************************************************************************
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
// updating the treadmill console every second
|
||||
// it seems that stops the communication
|
||||
@@ -166,7 +166,7 @@ void bowflextreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
@@ -183,7 +183,7 @@ void bowflextreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
// double distance = GetDistanceFromPacket(value);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -214,10 +214,10 @@ void bowflextreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
}
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
CharacteristicNotifier2A5B::CharacteristicNotifier2A5B(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a5b, parent), Bike(Bike) {
|
||||
QSettings settings;
|
||||
bike_wheel_revs = settings.value(QStringLiteral("bike_wheel_revs"), false).toBool();
|
||||
bike_wheel_revs = settings.value(QZSettings::bike_wheel_revs, QZSettings::default_bike_wheel_revs).toBool();
|
||||
}
|
||||
|
||||
int CharacteristicNotifier2A5B::notify(QByteArray &value) {
|
||||
|
||||
@@ -8,8 +8,8 @@ CharacteristicNotifier2ACD::CharacteristicNotifier2ACD(bluetoothdevice *Bike, QO
|
||||
int CharacteristicNotifier2ACD::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
value.append(0x08); // Inclination avaiable
|
||||
value.append((char)0x01); // heart rate avaiable
|
||||
value.append(0x08); // Inclination available
|
||||
value.append((char)0x01); // heart rate available
|
||||
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
char a = (normalizeSpeed >> 8) & 0XFF;
|
||||
|
||||
@@ -34,7 +34,7 @@ int CharacteristicNotifier2AD2::notify(QByteArray &value) {
|
||||
return CN_OK;
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
QSettings settings;
|
||||
bool double_cadence = settings.value(QStringLiteral("powr_sensor_running_cadence_double"), false).toBool();
|
||||
bool double_cadence = settings.value(QZSettings::powr_sensor_running_cadence_double, QZSettings::default_powr_sensor_running_cadence_double).toBool();
|
||||
double cadence_multiplier = 2.0;
|
||||
if (double_cadence)
|
||||
cadence_multiplier = 1.0;
|
||||
|
||||
87
src/characteristicwriteprocessor.cpp
Normal file
87
src/characteristicwriteprocessor.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#include "characteristicwriteprocessor.h"
|
||||
#include <QSettings>
|
||||
|
||||
CharacteristicWriteProcessor::CharacteristicWriteProcessor(double bikeResistanceGain, uint8_t bikeResistanceOffset,
|
||||
bluetoothdevice *bike, QObject *parent)
|
||||
: QObject(parent), bikeResistanceOffset(bikeResistanceOffset), bikeResistanceGain(bikeResistanceGain), Bike(bike) {}
|
||||
|
||||
void CharacteristicWriteProcessor::changePower(uint16_t power) { Bike->changePower(power); }
|
||||
|
||||
void CharacteristicWriteProcessor::changeSlope(int16_t iresistance, uint8_t crr, uint8_t cw) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
QSettings settings;
|
||||
bool force_resistance =
|
||||
settings.value(QZSettings::virtualbike_forceresistance, QZSettings::default_virtualbike_forceresistance)
|
||||
.toBool();
|
||||
bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool();
|
||||
bool zwift_negative_inclination_x2 =
|
||||
settings.value(QZSettings::zwift_negative_inclination_x2, QZSettings::default_zwift_negative_inclination_x2)
|
||||
.toBool();
|
||||
double offset =
|
||||
settings.value(QZSettings::zwift_inclination_offset, QZSettings::default_zwift_inclination_offset).toDouble();
|
||||
double gain =
|
||||
settings.value(QZSettings::zwift_inclination_gain, QZSettings::default_zwift_inclination_gain).toDouble();
|
||||
double CRRGain = settings.value(QZSettings::CRRGain, QZSettings::default_CRRGain).toDouble();
|
||||
double CWGain = settings.value(QZSettings::CWGain, QZSettings::default_CWGain).toDouble();
|
||||
|
||||
qDebug() << QStringLiteral("new requested resistance zwift erg grade ") + QString::number(iresistance) +
|
||||
QStringLiteral(" enabled ") + force_resistance;
|
||||
double resistance = ((double)iresistance * 1.5) / 100.0;
|
||||
qDebug() << QStringLiteral("calculated erg grade ") + QString::number(resistance);
|
||||
|
||||
double grade = ((iresistance / 100.0) * gain) + offset;
|
||||
|
||||
/*
|
||||
Surface Road Crr MTB Crr Gravel Crr (Namebrand) Zwift Gravel Crr
|
||||
Pavement .004 .01 .008 .008
|
||||
Sand .004 .01 .008 .008
|
||||
Brick .0055 .01 .008 .008
|
||||
Wood .0065 .01 .008 .008
|
||||
Cobbles .0065 .01 .008 .008
|
||||
Ice/Snow .0075 .014 .018 .018
|
||||
Dirt .025 .014 .016 .018
|
||||
Grass .042
|
||||
*/
|
||||
const double fCRR = crr / 10000.0;
|
||||
const double CRR_offset = ((crr - 40) * 0.05) * CRRGain;
|
||||
|
||||
const double fCW = cw / 100.0;
|
||||
const double CW_offset = ((crr - 40) * 0.05) * CWGain;
|
||||
|
||||
qDebug() << "changeSlope CRR = " << fCRR << CRR_offset << "CW = " << fCW;
|
||||
|
||||
if (dt == bluetoothdevice::BIKE) {
|
||||
|
||||
// if the bike doesn't have the inclination by hardware, i'm simulating inclination with the value received
|
||||
// form Zwift
|
||||
if (!((bike *)Bike)->inclinationAvailableByHardware())
|
||||
Bike->setInclination(grade + CRR_offset + CW_offset);
|
||||
|
||||
if (iresistance >= 0 || !zwift_negative_inclination_x2)
|
||||
emit changeInclination(grade, ((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * gain) + offset);
|
||||
else
|
||||
emit changeInclination((((iresistance / 100.0) * 2.0) * gain) + offset,
|
||||
(((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * 2.0) * gain) + offset);
|
||||
|
||||
if (force_resistance && !erg_mode) {
|
||||
// same on the training program
|
||||
Bike->changeResistance((resistance_t)(round(resistance * bikeResistanceGain)) + bikeResistanceOffset + 1 +
|
||||
CRR_offset + CW_offset); // resistance start from 1
|
||||
}
|
||||
} else if (dt == bluetoothdevice::TREADMILL) {
|
||||
emit changeInclination(((iresistance / 100.0) * gain) + offset,
|
||||
((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * gain) + offset);
|
||||
} else if (dt == bluetoothdevice::ELLIPTICAL) {
|
||||
emit changeInclination(((iresistance / 100.0) * gain) + offset,
|
||||
((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * gain) + offset);
|
||||
|
||||
if (!((elliptical *)Bike)->inclinationAvailableByHardware()) {
|
||||
if (force_resistance && !erg_mode) {
|
||||
// same on the training program
|
||||
Bike->changeResistance((resistance_t)(round(resistance * bikeResistanceGain)) + bikeResistanceOffset +
|
||||
1 + CRR_offset + CW_offset); // resistance start from 1
|
||||
}
|
||||
}
|
||||
}
|
||||
emit slopeChanged();
|
||||
}
|
||||
@@ -1,7 +1,13 @@
|
||||
#ifndef CHARACTERISTICWRITEPROCESSOR_H
|
||||
#define CHARACTERISTICWRITEPROCESSOR_H
|
||||
|
||||
#include "bike.h"
|
||||
#include "bluetoothdevice.h"
|
||||
#include "elliptical.h"
|
||||
#include "treadmill.h"
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
|
||||
#define CP_INVALID -1
|
||||
#define CP_OK 0
|
||||
@@ -9,9 +15,18 @@
|
||||
class CharacteristicWriteProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CharacteristicWriteProcessor(QObject *parent = nullptr) : QObject(parent) {}
|
||||
uint8_t bikeResistanceOffset = 4;
|
||||
double bikeResistanceGain = 1.0;
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
explicit CharacteristicWriteProcessor(double bikeResistanceGain, uint8_t bikeResistanceOffset,
|
||||
bluetoothdevice *bike, QObject *parent = nullptr);
|
||||
virtual int writeProcess(quint16 uuid, const QByteArray &data, QByteArray &out) = 0;
|
||||
virtual void changePower(uint16_t power);
|
||||
virtual void changeSlope(int16_t iresistance, uint8_t crr, uint8_t cw);
|
||||
signals:
|
||||
void changeInclination(double grade, double percentage);
|
||||
void slopeChanged();
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICWRITEPROCESSOR_H
|
||||
|
||||
@@ -9,16 +9,17 @@ CharacteristicWriteProcessor2AD9::CharacteristicWriteProcessor2AD9(double bikeRe
|
||||
uint8_t bikeResistanceOffset, bluetoothdevice *bike,
|
||||
CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent)
|
||||
: CharacteristicWriteProcessor(parent), bikeResistanceOffset(bikeResistanceOffset),
|
||||
bikeResistanceGain(bikeResistanceGain), Bike(bike), notifier(notifier) {}
|
||||
: CharacteristicWriteProcessor(bikeResistanceGain, bikeResistanceOffset, bike, parent), notifier(notifier) {}
|
||||
|
||||
int CharacteristicWriteProcessor2AD9::writeProcess(quint16 uuid, const QByteArray &data, QByteArray &reply) {
|
||||
if (data.size()) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::BIKE) {
|
||||
QSettings settings;
|
||||
bool force_resistance = settings.value(QStringLiteral("virtualbike_forceresistance"), true).toBool();
|
||||
bool erg_mode = settings.value(QStringLiteral("zwift_erg"), false).toBool();
|
||||
bool force_resistance =
|
||||
settings.value(QZSettings::virtualbike_forceresistance, QZSettings::default_virtualbike_forceresistance)
|
||||
.toBool();
|
||||
bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool();
|
||||
char cmd = data.at(0);
|
||||
emit ftmsCharacteristicChanged(QLowEnergyCharacteristic(), data);
|
||||
if (cmd == FTMS_SET_TARGET_RESISTANCE_LEVEL) {
|
||||
@@ -43,7 +44,9 @@ int CharacteristicWriteProcessor2AD9::writeProcess(quint16 uuid, const QByteArra
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
|
||||
int16_t iresistance = (((uint8_t)data.at(3)) + (data.at(4) << 8));
|
||||
changeSlope(iresistance);
|
||||
uint8_t crr = data.at(5);
|
||||
uint8_t cw = data.at(6);
|
||||
changeSlope(iresistance, crr, cw);
|
||||
} else if (cmd == FTMS_SET_TARGET_POWER) // erg mode
|
||||
|
||||
{
|
||||
@@ -114,66 +117,18 @@ int CharacteristicWriteProcessor2AD9::writeProcess(quint16 uuid, const QByteArra
|
||||
{
|
||||
qDebug() << QStringLiteral("indoor bike simulation parameters");
|
||||
int16_t iresistance = (((uint8_t)data.at(3)) + (data.at(4) << 8));
|
||||
changeSlope(iresistance);
|
||||
uint8_t crr = data.at(5);
|
||||
uint8_t cw = data.at(6);
|
||||
changeSlope(iresistance, crr, cw);
|
||||
}
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)data.at(0));
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
}
|
||||
if(notifier) {
|
||||
if (notifier) {
|
||||
notifier->answer = reply;
|
||||
}
|
||||
return CP_OK;
|
||||
} else
|
||||
return CP_INVALID;
|
||||
}
|
||||
|
||||
void CharacteristicWriteProcessor2AD9::changePower(uint16_t power) { Bike->changePower(power); }
|
||||
|
||||
void CharacteristicWriteProcessor2AD9::changeSlope(int16_t iresistance) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::BIKE) {
|
||||
QSettings settings;
|
||||
bool force_resistance = settings.value(QStringLiteral("virtualbike_forceresistance"), true).toBool();
|
||||
bool erg_mode = settings.value(QStringLiteral("zwift_erg"), false).toBool();
|
||||
bool zwift_negative_inclination_x2 =
|
||||
settings.value(QStringLiteral("zwift_negative_inclination_x2"), false).toBool();
|
||||
double offset = settings.value(QStringLiteral("zwift_inclination_offset"), 0.0).toDouble();
|
||||
double gain = settings.value(QStringLiteral("zwift_inclination_gain"), 1.0).toDouble();
|
||||
|
||||
qDebug() << QStringLiteral("new requested resistance zwift erg grade ") + QString::number(iresistance) +
|
||||
QStringLiteral(" enabled ") + force_resistance;
|
||||
double resistance = ((double)iresistance * 1.5) / 100.0;
|
||||
qDebug() << QStringLiteral("calculated erg grade ") + QString::number(resistance);
|
||||
|
||||
double grade = ((iresistance / 100.0) * gain) + offset;
|
||||
// if the bike doesn't have the inclination by hardware, i'm simulating inclination with the value received form Zwift
|
||||
if(!((bike*)Bike)->inclinationAvailableByHardware())
|
||||
Bike->setInclination(grade);
|
||||
|
||||
if (iresistance >= 0 || !zwift_negative_inclination_x2)
|
||||
emit changeInclination(grade,
|
||||
((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * gain) + offset);
|
||||
else
|
||||
emit changeInclination((((iresistance / 100.0) * 2.0) * gain) + offset,
|
||||
(((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * 2.0) * gain) + offset);
|
||||
|
||||
if (force_resistance && !erg_mode) {
|
||||
// same on the training program
|
||||
Bike->changeResistance((resistance_t)(round(resistance * bikeResistanceGain)) + bikeResistanceOffset +
|
||||
1); // resistance start from 1
|
||||
}
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
QSettings settings;
|
||||
double offset = settings.value(QStringLiteral("zwift_inclination_offset"), 0.0).toDouble();
|
||||
double gain = settings.value(QStringLiteral("zwift_inclination_gain"), 1.0).toDouble();
|
||||
|
||||
qDebug() << QStringLiteral("new requested resistance zwift erg grade ") + QString::number(iresistance);
|
||||
double resistance = ((double)iresistance * 1.5) / 100.0;
|
||||
qDebug() << QStringLiteral("calculated erg grade ") + QString::number(resistance);
|
||||
|
||||
emit changeInclination(((iresistance / 100.0) * gain) + offset,
|
||||
((qTan(qDegreesToRadians(iresistance / 100.0)) * 100.0) * gain) + offset);
|
||||
}
|
||||
emit slopeChanged();
|
||||
}
|
||||
|
||||
@@ -1,26 +1,19 @@
|
||||
#ifndef CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
#define CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
#include "characteristicnotifier2ad9.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
|
||||
class CharacteristicWriteProcessor2AD9 : public CharacteristicWriteProcessor {
|
||||
Q_OBJECT
|
||||
uint8_t bikeResistanceOffset = 4;
|
||||
double bikeResistanceGain = 1.0;
|
||||
bluetoothdevice *Bike;
|
||||
CharacteristicNotifier2AD9 *notifier = nullptr;
|
||||
|
||||
public:
|
||||
explicit CharacteristicWriteProcessor2AD9(double bikeResistanceGain, uint8_t bikeResistanceOffset,
|
||||
bluetoothdevice *bike, CharacteristicNotifier2AD9 *notifier, QObject *parent = nullptr);
|
||||
bluetoothdevice *bike, CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent = nullptr);
|
||||
virtual int writeProcess(quint16 uuid, const QByteArray &data, QByteArray &out);
|
||||
void changeSlope(int16_t slope);
|
||||
void changePower(uint16_t power);
|
||||
signals:
|
||||
void changeInclination(double grade, double percentage);
|
||||
void slopeChanged();
|
||||
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
};
|
||||
|
||||
|
||||
49
src/characteristicwriteprocessore005.cpp
Normal file
49
src/characteristicwriteprocessore005.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "characteristicwriteprocessore005.h"
|
||||
#include "elliptical.h"
|
||||
#include "ftmsbike.h"
|
||||
#include "treadmill.h"
|
||||
#include "wahookickrsnapbike.h"
|
||||
#include <QtMath>
|
||||
|
||||
CharacteristicWriteProcessorE005::CharacteristicWriteProcessorE005(double bikeResistanceGain,
|
||||
uint8_t bikeResistanceOffset, bluetoothdevice *bike,
|
||||
// CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent)
|
||||
: CharacteristicWriteProcessor(bikeResistanceGain, bikeResistanceOffset, bike, parent) {}
|
||||
|
||||
int CharacteristicWriteProcessorE005::writeProcess(quint16 uuid, const QByteArray &data, QByteArray &reply) {
|
||||
if (data.size()) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::BIKE) {
|
||||
char cmd = data.at(0);
|
||||
emit ftmsCharacteristicChanged(QLowEnergyCharacteristic(), data);
|
||||
if (cmd == wahookickrsnapbike::_setSimMode && data.count() >= 7) {
|
||||
weight = ((double)((uint16_t)data.at(1)) + (((uint16_t)data.at(2)) >> 8)) / 100.0;
|
||||
rrc = ((double)((uint16_t)data.at(3)) + (((uint16_t)data.at(4)) >> 8)) / 1000.0;
|
||||
wrc = ((double)((uint16_t)data.at(5)) + (((uint16_t)data.at(6)) >> 8)) / 1000.0;
|
||||
qDebug() << "weigth" << weight << "rrc" << rrc << "wrc" << wrc;
|
||||
} else if (cmd == wahookickrsnapbike::_setSimGrade && data.count() >= 3) {
|
||||
uint16_t grade;
|
||||
double fgrade;
|
||||
grade = (uint16_t)((uint8_t)data.at(1)) + (((uint16_t)((uint8_t)data.at(2))) << 8);
|
||||
fgrade = (((((double)grade) / 65535.0) * 2) - 1.0) * 100.0;
|
||||
qDebug() << "grade" << grade << "fgrade" << fgrade;
|
||||
changeSlope(fgrade * 100.0, rrc, wrc);
|
||||
} else if (cmd == wahookickrsnapbike::_setErgMode && data.count() >= 3) {
|
||||
uint16_t watts;
|
||||
watts = (uint16_t)((uint8_t)data.at(1)) + (((uint16_t)((uint8_t)data.at(2))) << 8);
|
||||
qDebug() << "erg mode" << watts;
|
||||
changePower(watts);
|
||||
}
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
}
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)data.at(0));
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
/*if (notifier) {
|
||||
notifier->answer = reply;
|
||||
}*/
|
||||
return CP_OK;
|
||||
} else
|
||||
return CP_INVALID;
|
||||
}
|
||||
24
src/characteristicwriteprocessore005.h
Normal file
24
src/characteristicwriteprocessore005.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef CHARACTERISTICWRITEPROCESSORE005_H
|
||||
#define CHARACTERISTICWRITEPROCESSORE005_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier2ad9.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
|
||||
class CharacteristicWriteProcessorE005 : public CharacteristicWriteProcessor {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CharacteristicWriteProcessorE005(double bikeResistanceGain, uint8_t bikeResistanceOffset,
|
||||
bluetoothdevice *bike, // CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent = nullptr);
|
||||
virtual int writeProcess(quint16 uuid, const QByteArray &data, QByteArray &out);
|
||||
|
||||
private:
|
||||
double weight, rrc, wrc;
|
||||
|
||||
signals:
|
||||
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICWRITEPROCESSORE005_H
|
||||
@@ -129,7 +129,7 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
@@ -138,23 +138,26 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
if (newValue.length() != 19)
|
||||
return;
|
||||
|
||||
if (settings.value(QStringLiteral("power_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = (uint16_t)((uint8_t)newValue.at(17)) + ((uint16_t)((uint8_t)newValue.at(18)) << 8);
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((uint8_t)newValue.at(8)) / 2;
|
||||
}
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = ((double)((uint16_t)((uint8_t)newValue.at(6)) + ((uint16_t)((uint8_t)newValue.at(7)) << 8))) / 100.0;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
@@ -176,8 +179,8 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
(cr - (m_watt.value() * 132.0 / (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) -
|
||||
br) /
|
||||
(2.0 * ar)) *
|
||||
settings.value(QStringLiteral("peloton_gain"), 1.0).toDouble()) +
|
||||
settings.value(QStringLiteral("peloton_offset"), 0.0).toDouble();
|
||||
settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
Resistance = m_pelotonResistance;
|
||||
emit resistanceRead(Resistance.value());
|
||||
|
||||
@@ -189,7 +192,7 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -210,8 +213,9 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", false).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -268,11 +272,14 @@ void chronobike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", false).toBool();
|
||||
bool cadence =
|
||||
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
|
||||
@@ -131,7 +131,7 @@ void concept2skierg::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
qDebug() << QStringLiteral(" << ") << characteristic.uuid() << " " << newValue.toHex(' ');
|
||||
|
||||
@@ -180,7 +180,7 @@ void concept2skierg::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
uint8_t heart_rate = newValue.at(7);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -248,8 +248,8 @@ void concept2skierg::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
@@ -365,11 +365,11 @@ void concept2skierg::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
) {
|
||||
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
|
||||
103
src/cscbike.cpp
103
src/cscbike.cpp
@@ -58,11 +58,11 @@ data_len));
|
||||
void cscbike::update() {
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
if (!noVirtualDevice) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool()) {
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
debug("Current Heart: " + QString::number(Heart.value()));
|
||||
}
|
||||
@@ -82,16 +82,16 @@ void cscbike::update() {
|
||||
}
|
||||
|
||||
if (Heart.value() > 0) {
|
||||
int avgP = ((settings.value(QStringLiteral("power_hr_pwr1"), 200).toDouble() *
|
||||
settings.value(QStringLiteral("power_hr_hr2"), 170).toDouble()) -
|
||||
(settings.value(QStringLiteral("power_hr_pwr2"), 230).toDouble() *
|
||||
settings.value(QStringLiteral("power_hr_hr1"), 150).toDouble())) /
|
||||
(settings.value(QStringLiteral("power_hr_hr2"), 170).toDouble() -
|
||||
settings.value(QStringLiteral("power_hr_hr1"), 150).toDouble()) +
|
||||
(Heart.value() * ((settings.value(QStringLiteral("power_hr_pwr1"), 200).toDouble() -
|
||||
settings.value(QStringLiteral("power_hr_pwr2"), 230).toDouble()) /
|
||||
(settings.value(QStringLiteral("power_hr_hr1"), 150).toDouble() -
|
||||
settings.value(QStringLiteral("power_hr_hr2"), 170).toDouble())));
|
||||
int avgP = ((settings.value(QZSettings::power_hr_pwr1, QZSettings::default_power_hr_pwr1).toDouble() *
|
||||
settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble()) -
|
||||
(settings.value(QZSettings::power_hr_pwr2, QZSettings::default_power_hr_pwr2).toDouble() *
|
||||
settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble())) /
|
||||
(settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble() -
|
||||
settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble()) +
|
||||
(Heart.value() * ((settings.value(QZSettings::power_hr_pwr1, QZSettings::default_power_hr_pwr1).toDouble() -
|
||||
settings.value(QZSettings::power_hr_pwr2, QZSettings::default_power_hr_pwr2).toDouble()) /
|
||||
(settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble() -
|
||||
settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble())));
|
||||
if (avgP < 50) {
|
||||
avgP = 50;
|
||||
}
|
||||
@@ -158,38 +158,67 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
// QString heartRateBeltName = //unused QString
|
||||
// settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
// settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
uint16_t _LastCrankEventTime = 0;
|
||||
double _CrankRevs = 0;
|
||||
uint16_t _LastWheelEventTime = 0;
|
||||
double _WheelRevs = 0;
|
||||
uint8_t battery = 0;
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
if (characteristic.uuid() == QBluetoothUuid((quint16)0x2A19)) {
|
||||
battery = newValue.at(0);
|
||||
qDebug() << QStringLiteral("battery: ") << battery;
|
||||
return;
|
||||
}
|
||||
|
||||
if (characteristic.uuid() != QBluetoothUuid((quint16)0x2A5B)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastPacket = newValue;
|
||||
|
||||
bool CrankPresent = (newValue.at(0) & 0x02) == 0x02;
|
||||
bool WheelPresent = (newValue.at(0) & 0x01) == 0x01;
|
||||
qDebug() << QStringLiteral("CrankPresent: ") << CrankPresent;
|
||||
qDebug() << QStringLiteral("WheelPresent: ") << WheelPresent;
|
||||
|
||||
uint8_t index = 1;
|
||||
if (newValue.at(0) == 0x02) {
|
||||
CrankRevs = (((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)));
|
||||
} else {
|
||||
CrankRevs =
|
||||
|
||||
if (WheelPresent) {
|
||||
_WheelRevs =
|
||||
(((uint32_t)((uint8_t)newValue.at(index + 3)) << 24) | ((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
((uint32_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint32_t)((uint8_t)newValue.at(index)));
|
||||
}
|
||||
if (newValue.at(0) == 0x01) {
|
||||
emit debug(QStringLiteral("Current Wheel Revs: ") + QString::number(_WheelRevs));
|
||||
index += 4;
|
||||
} else {
|
||||
|
||||
_LastWheelEventTime =
|
||||
(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)));
|
||||
emit debug(QStringLiteral("Current Wheel Event Time: ") + QString::number(_LastWheelEventTime));
|
||||
index += 2;
|
||||
}
|
||||
LastCrankEventTime = (((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)));
|
||||
if (CrankPresent) {
|
||||
_CrankRevs = (((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)));
|
||||
emit debug(QStringLiteral("Current Crank Revs: ") + QString::number(_CrankRevs));
|
||||
index += 2;
|
||||
_LastCrankEventTime =
|
||||
(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)));
|
||||
emit debug(QStringLiteral("Current Crank Event Time: ") + QString::number(_LastCrankEventTime));
|
||||
}
|
||||
|
||||
if ((!CrankPresent || _CrankRevs == 0) && WheelPresent) {
|
||||
CrankRevs = _WheelRevs;
|
||||
LastCrankEventTime = _LastWheelEventTime;
|
||||
} else {
|
||||
CrankRevs = _CrankRevs;
|
||||
LastCrankEventTime = _LastCrankEventTime;
|
||||
}
|
||||
|
||||
int16_t deltaT = LastCrankEventTime - oldLastCrankEventTime;
|
||||
if (deltaT < 0) {
|
||||
if (newValue.at(0) == 0x01) {
|
||||
deltaT = LastCrankEventTime + 1024 - oldLastCrankEventTime;
|
||||
} else {
|
||||
deltaT = LastCrankEventTime + 65535 - oldLastCrankEventTime;
|
||||
}
|
||||
deltaT = LastCrankEventTime + 65535 - oldLastCrankEventTime;
|
||||
}
|
||||
|
||||
if (CrankRevs != oldCrankRevs && deltaT) {
|
||||
@@ -206,10 +235,10 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
oldLastCrankEventTime = LastCrankEventTime;
|
||||
oldCrankRevs = CrankRevs;
|
||||
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
Speed = Cadence.value() * settings.value(QStringLiteral("cadence_sensor_speed_ratio"), 0.33).toDouble();
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = Cadence.value() * settings.value(QZSettings::cadence_sensor_speed_ratio, QZSettings::default_cadence_sensor_speed_ratio).toDouble();
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
|
||||
@@ -232,8 +261,8 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
(ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) -
|
||||
br) /
|
||||
(2.0 * ar)) *
|
||||
settings.value(QStringLiteral("peloton_gain"), 1.0).toDouble()) +
|
||||
settings.value(QStringLiteral("peloton_offset"), 0.0).toDouble();
|
||||
settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
Resistance = m_pelotonResistance;
|
||||
} else {
|
||||
m_pelotonResistance = 0;
|
||||
@@ -243,7 +272,7 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
@@ -260,8 +289,8 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
if (!noVirtualDevice) {
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -360,11 +389,11 @@ void cscbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
|
||||
@@ -14,13 +14,15 @@
|
||||
OP(HEART_RATE, 0x180D, WAHOO_BLUEHR, P1, P2, P3)
|
||||
|
||||
#define DM_MACHINE_OP(OP, P1, P2, P3) \
|
||||
OP(WAHOO_KICKR, "Wahoo KICKR $uuid_hex$", DM_MACHINE_TYPE_BIKE, P1, P2, P3) \
|
||||
OP(WAHOO_KICKR, "Wahoo KICKR $uuid_hex$", DM_MACHINE_TYPE_TREADMILL | DM_MACHINE_TYPE_BIKE, P1, P2, P3) \
|
||||
OP(WAHOO_BLUEHR, "Wahoo HRM", DM_MACHINE_TYPE_BIKE | DM_MACHINE_TYPE_TREADMILL, P1, P2, P3) \
|
||||
OP(WAHOO_RPM_SPEED, "Wahoo SPEED $uuid_hex$", DM_MACHINE_TYPE_BIKE, P1, P2, P3) \
|
||||
OP(WAHOO_TREADMILL, "Wahoo TREAD $uuid_hex$", DM_MACHINE_TYPE_TREADMILL, P1, P2, P3)
|
||||
|
||||
#define DP_PROCESS_WRITE_2AD9() writeP2AD9
|
||||
#define DP_PROCESS_WRITE_2AD9T() writeP2AD9
|
||||
#define DP_PROCESS_WRITE_E005() writePE005
|
||||
#define DP_PROCESS_WRITE_E005T() writePE005
|
||||
#define DP_PROCESS_WRITE_2A55() 0
|
||||
#define DP_PROCESS_WRITE_2A55T() 0
|
||||
#define DP_PROCESS_WRITE_NULL() 0
|
||||
@@ -33,6 +35,7 @@
|
||||
OP(FITNESS_MACHINE_CYCLE, 0x2AD6, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x0A\x00\x96\x00\x0A\x00"), \
|
||||
DP_PROCESS_WRITE_NULL, P1, P2, P3) \
|
||||
OP(FITNESS_MACHINE_CYCLE, 0x2AD9, DPKT_CHAR_PROP_FLAG_WRITE, DM_BT("\x00"), DP_PROCESS_WRITE_2AD9, P1, P2, P3) \
|
||||
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(FITNESS_MACHINE_TREADMILL, 0x2ACC, DPKT_CHAR_PROP_FLAG_READ, DM_BT("\x08\x14\x00\x00\x00\x00\x00\x00"), \
|
||||
@@ -101,9 +104,10 @@ enum { DM_SERV_OP(DM_SERV_ENUMI_OP, 0, 0, 0) DM_SERV_I_NUM };
|
||||
} \
|
||||
if (P2.size()) { \
|
||||
DirconProcessor *processor = new DirconProcessor( \
|
||||
P2, QString(QStringLiteral(NAME)) \
|
||||
.replace(QStringLiteral("$uuid_hex$"), \
|
||||
QString(QStringLiteral("%1")).arg(DM_MACHINE_##DESC, 4, 10, QLatin1Char('0'))), \
|
||||
P2, \
|
||||
QString(QStringLiteral(NAME)) \
|
||||
.replace(QStringLiteral("$uuid_hex$"), \
|
||||
QString(QStringLiteral("%1")).arg(DM_MACHINE_##DESC, 4, 10, QLatin1Char('0'))), \
|
||||
server_base_port + DM_MACHINE_##DESC, QString(QStringLiteral("%1")).arg(DM_MACHINE_##DESC), mac, \
|
||||
this); \
|
||||
QString servdesc; \
|
||||
@@ -146,14 +150,19 @@ DirconManager::DirconManager(bluetoothdevice *Bike, uint8_t bikeResistanceOffset
|
||||
uint8_t type = dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL ? DM_MACHINE_TYPE_TREADMILL
|
||||
: DM_MACHINE_TYPE_BIKE;
|
||||
qDebug() << "Building Dircom Manager";
|
||||
uint16_t server_base_port = settings.value(QStringLiteral("dircon_server_base_port"), 4810).toUInt();
|
||||
bool bike_wheel_revs = settings.value(QStringLiteral("bike_wheel_revs"), false).toBool();
|
||||
uint16_t server_base_port =
|
||||
settings.value(QZSettings::dircon_server_base_port, QZSettings::default_dircon_server_base_port).toUInt();
|
||||
bool bike_wheel_revs = settings.value(QZSettings::bike_wheel_revs, QZSettings::default_bike_wheel_revs).toBool();
|
||||
DM_CHAR_NOTIF_OP(DM_CHAR_NOTIF_BUILD_OP, Bike, 0, 0)
|
||||
writeP2AD9 = new CharacteristicWriteProcessor2AD9(bikeResistanceGain, bikeResistanceOffset, Bike, notif2AD9, this);
|
||||
writePE005 = new CharacteristicWriteProcessorE005(bikeResistanceGain, bikeResistanceOffset, Bike, this);
|
||||
DM_CHAR_OP(DM_CHAR_INIT_OP, services, service, 0)
|
||||
connect(writeP2AD9, SIGNAL(changeInclination(double, double)), this, SIGNAL(changeInclination(double, double)));
|
||||
connect(writeP2AD9, SIGNAL(ftmsCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)), this,
|
||||
SIGNAL(ftmsCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)));
|
||||
connect(writePE005, SIGNAL(changeInclination(double, double)), this, SIGNAL(changeInclination(double, double)));
|
||||
connect(writePE005, SIGNAL(ftmsCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)), this,
|
||||
SIGNAL(ftmsCharacteristicChanged(QLowEnergyCharacteristic, QByteArray)));
|
||||
QObject::connect(&bikeTimer, &QTimer::timeout, this, &DirconManager::bikeProvider);
|
||||
QString mac = getMacAddress();
|
||||
DM_MACHINE_OP(DM_MACHINE_INIT_OP, services, proc_services, type)
|
||||
|
||||
@@ -6,18 +6,21 @@
|
||||
#include "characteristicnotifier2a53.h"
|
||||
#include "characteristicnotifier2a5b.h"
|
||||
#include "characteristicnotifier2a63.h"
|
||||
#include "characteristicnotifier2acd.h"
|
||||
#include "characteristicnotifier2acc.h"
|
||||
#include "characteristicnotifier2acd.h"
|
||||
#include "characteristicnotifier2ad2.h"
|
||||
#include "characteristicnotifier2ad9.h"
|
||||
#include "characteristicwriteprocessor2ad9.h"
|
||||
#include "characteristicwriteprocessore005.h"
|
||||
#include "dirconpacket.h"
|
||||
#include "dirconprocessor.h"
|
||||
#include <QObject>
|
||||
|
||||
#define DM_CHAR_NOTIF_OP(OP, P1, P2, P3) \
|
||||
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(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)
|
||||
|
||||
#define DM_CHAR_NOTIF_DEFINE_OP(UUID, P1, P2, P3) CharacteristicNotifier##UUID *notif##UUID = 0;
|
||||
|
||||
@@ -25,6 +28,7 @@ class DirconManager : public QObject {
|
||||
Q_OBJECT
|
||||
QTimer bikeTimer;
|
||||
CharacteristicWriteProcessor2AD9 *writeP2AD9 = 0;
|
||||
CharacteristicWriteProcessorE005 *writePE005 = 0;
|
||||
DM_CHAR_NOTIF_OP(DM_CHAR_NOTIF_DEFINE_OP, 0, 0, 0)
|
||||
QList<DirconProcessor *> processors;
|
||||
static QString getMacAddress();
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "dirconprocessor.h"
|
||||
#include "dirconpacket.h"
|
||||
#include "qzsettings.h"
|
||||
#include <QSettings>
|
||||
#include <QHostInfo>
|
||||
|
||||
DirconProcessor::DirconProcessor(const QList<DirconProcessorService *> &my_services, const QString &serv_name,
|
||||
quint16 serv_port, const QString &serv_sn, const QString &my_mac, QObject *parent)
|
||||
@@ -198,6 +201,7 @@ bool DirconProcessor::sendCharacteristicNotification(quint16 uuid, const QByteAr
|
||||
DirconPacket pkt;
|
||||
QTcpSocket *socket;
|
||||
DirconProcessorClient *client;
|
||||
QSettings settings;
|
||||
bool rv = true, rvs;
|
||||
pkt.additional_data = data;
|
||||
pkt.Identifier = DPKT_MSGID_UNSOLICITED_CHARACTERISTIC_NOTIFICATION;
|
||||
@@ -205,7 +209,7 @@ bool DirconProcessor::sendCharacteristicNotification(quint16 uuid, const QByteAr
|
||||
pkt.uuid = uuid;
|
||||
for (QHash<QTcpSocket *, DirconProcessorClient *>::iterator i = clientsMap.begin(); i != clientsMap.end(); ++i) {
|
||||
client = i.value();
|
||||
/*if (client->char_notify.indexOf(uuid) >= 0)*/ {
|
||||
if (client->char_notify.indexOf(uuid) >= 0 || !settings.value(QZSettings::wahoo_rgt_dircon, QZSettings::default_wahoo_rgt_dircon).toBool()) {
|
||||
socket = i.key();
|
||||
rvs = socket->write(pkt.encode(0)) < 0;
|
||||
if (rvs)
|
||||
|
||||
@@ -18,7 +18,6 @@ class DirconProcessorCharacteristic : public QObject {
|
||||
DirconProcessorCharacteristic(quint16 my_uuid, quint8 my_type, const QByteArray &data,
|
||||
CharacteristicWriteProcessor *w, QObject *parent = nullptr)
|
||||
: QObject(parent), read_values(data), uuid(my_uuid), type(my_type), writeP(w) {}
|
||||
DirconProcessorCharacteristic(const DirconProcessorCharacteristic &cp) { this->operator=(cp); }
|
||||
~DirconProcessorCharacteristic() {}
|
||||
DirconProcessorCharacteristic &operator=(const DirconProcessorCharacteristic &cp) {
|
||||
read_values = cp.read_values;
|
||||
|
||||
@@ -74,8 +74,8 @@ void domyosbike::updateDisplay(uint16_t elapsed) {
|
||||
uint16_t multiplier = 1;
|
||||
|
||||
QSettings settings;
|
||||
bool distance = settings.value(QStringLiteral("domyos_treadmill_distance_display"), true).toBool();
|
||||
bool domyos_bike_display_calories = settings.value(QStringLiteral("domyos_bike_display_calories"), true).toBool();
|
||||
bool distance = settings.value(QZSettings::domyos_treadmill_distance_display, QZSettings::default_domyos_treadmill_distance_display).toBool();
|
||||
bool domyos_bike_display_calories = settings.value(QZSettings::domyos_bike_display_calories, QZSettings::default_domyos_bike_display_calories).toBool();
|
||||
|
||||
if (domyos_bike_display_calories) {
|
||||
multiplier = 10;
|
||||
@@ -101,7 +101,7 @@ void domyosbike::updateDisplay(uint16_t elapsed) {
|
||||
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00};
|
||||
|
||||
display[3] = (elapsed / 60) & 0xFF; // high byte for elapsed time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elasped time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elapsed time (in seconds)
|
||||
|
||||
if (currentSpeed().value() < 10.0) {
|
||||
|
||||
@@ -190,11 +190,11 @@ void domyosbike::update() {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
@@ -278,15 +278,15 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
QByteArray value = newValue;
|
||||
|
||||
qDebug() << QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' ');
|
||||
|
||||
// for the init packets, the lenght is always less than 20
|
||||
// for the display and status packets, the lenght is always grater then 20 and there are 2 cases:
|
||||
// - intense run: it always send more than 20 bytes in one packets, so the lenght will be always != 20
|
||||
// - t900: it splits packets with lenght grater than 20 in two distinct packets, so the first one it has lenght of
|
||||
// for the init packets, the length is always less than 20
|
||||
// for the display and status packets, the length is always grater then 20 and there are 2 cases:
|
||||
// - intense run: it always send more than 20 bytes in one packets, so the length will be always != 20
|
||||
// - t900: it splits packets with length grater than 20 in two distinct packets, so the first one it has length of
|
||||
// 20,
|
||||
// and the second one with the remained byte
|
||||
// so this simply condition will match all the cases, excluding the 20byte packet of the T900.
|
||||
@@ -307,7 +307,7 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
startBytes3.append(0xf0);
|
||||
startBytes3.append(0xdd);
|
||||
|
||||
// on some treadmills, the 26bytes has splitted in 2 packets
|
||||
// on some treadmills, the 26bytes has split in 2 packets
|
||||
if ((lastPacket.length() == 20 && lastPacket.startsWith(startBytes) && value.length() == 6) ||
|
||||
(lastPacket.length() == 20 && lastPacket.startsWith(startBytes2) && value.length() == 7) ||
|
||||
(lastPacket.length() == 20 && lastPacket.startsWith(startBytes3) && value.length() == 7)) {
|
||||
@@ -347,8 +347,8 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
double distance = GetDistanceFromPacket(value);
|
||||
|
||||
double ucadence = ((uint8_t)value.at(9));
|
||||
double cadenceFilter = settings.value(QStringLiteral("domyos_bike_cadence_filter"), 0).toDouble();
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
double cadenceFilter = settings.value(QZSettings::domyos_bike_cadence_filter, QZSettings::default_domyos_bike_cadence_filter).toDouble();
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
if (cadenceFilter == 0 || cadenceFilter > ucadence) {
|
||||
@@ -367,10 +367,10 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
emit resistanceRead(Resistance.value());
|
||||
m_pelotonResistance = (Resistance.value() * 100) / max_resistance;
|
||||
|
||||
bool disable_hr_frommachinery = settings.value(QStringLiteral("heart_ignore_builtin"), false).toBool();
|
||||
bool disable_hr_frommachinery = settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -401,8 +401,8 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -424,10 +424,10 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
qDebug() << "QLowEnergyController ERROR!!" << m_control->errorString();
|
||||
}
|
||||
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = speed;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
KCal = kcal;
|
||||
Distance = distance;
|
||||
|
||||
@@ -87,7 +87,7 @@ void domyoselliptical::updateDisplay(uint16_t elapsed) {
|
||||
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00};
|
||||
|
||||
display[3] = (elapsed / 60) & 0xFF; // high byte for elapsed time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elasped time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elapsed time (in seconds)
|
||||
|
||||
display[7] = ((uint8_t)((uint16_t)(currentSpeed().value()) >> 8)) & 0xFF;
|
||||
display[8] = (uint8_t)(currentSpeed().value()) & 0xFF;
|
||||
@@ -171,8 +171,8 @@ void domyoselliptical::update() {
|
||||
// ******************************************* virtual bike init *************************************
|
||||
QSettings settings;
|
||||
if (!firstVirtual && searchStopped && !virtualTreadmill && !virtualBike) {
|
||||
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
|
||||
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
@@ -204,7 +204,7 @@ void domyoselliptical::update() {
|
||||
if (requestResistance != -1) {
|
||||
if (requestResistance > 15) {
|
||||
requestResistance = 15;
|
||||
} else if (requestResistance == 0) {
|
||||
} else if (requestResistance <= 0) {
|
||||
requestResistance = 1;
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ void domyoselliptical::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
@@ -287,12 +287,12 @@ void domyoselliptical::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
inclination and speed status return;*/
|
||||
|
||||
double speed =
|
||||
GetSpeedFromPacket(newValue) * settings.value(QStringLiteral("domyos_elliptical_speed_ratio"), 1.0).toDouble();
|
||||
GetSpeedFromPacket(newValue) * settings.value(QZSettings::domyos_elliptical_speed_ratio, QZSettings::default_domyos_elliptical_speed_ratio).toDouble();
|
||||
double kcal = GetKcalFromPacket(newValue);
|
||||
double distance = GetDistanceFromPacket(newValue) *
|
||||
settings.value(QStringLiteral("domyos_elliptical_speed_ratio"), 1.0).toDouble();
|
||||
settings.value(QZSettings::domyos_elliptical_speed_ratio, QZSettings::default_domyos_elliptical_speed_ratio).toDouble();
|
||||
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((uint8_t)newValue.at(9));
|
||||
@@ -311,7 +311,7 @@ void domyoselliptical::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -582,19 +582,29 @@ uint16_t domyoselliptical::watts() {
|
||||
// calc Watts ref. https://alancouzens.com/blog/Run_Power.html
|
||||
|
||||
uint16_t watts = 0;
|
||||
double weight = settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
double weight = settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
if (currentSpeed().value() > 0) {
|
||||
|
||||
double pace = 60 / currentSpeed().value();
|
||||
double VO2R = 210.0 / pace;
|
||||
double VO2A = (VO2R * weight) / 1000.0;
|
||||
double hwatts = 75 * VO2A;
|
||||
double vwatts = ((9.8 * weight) * (currentInclination().value() / 100.0));
|
||||
double inc_res_ratio;
|
||||
if(settings.value(QZSettings::domyos_elliptical_inclination, QZSettings::default_domyos_elliptical_inclination).toBool())
|
||||
inc_res_ratio = currentInclination().value() / 100.0;
|
||||
else
|
||||
inc_res_ratio = currentResistance().value() / 100.0;
|
||||
double vwatts = ((9.8 * weight) * (inc_res_ratio));
|
||||
watts = hwatts + vwatts;
|
||||
}
|
||||
return watts;
|
||||
}
|
||||
|
||||
bool domyoselliptical::inclinationAvailableByHardware() {
|
||||
QSettings settings;
|
||||
return settings.value(QZSettings::domyos_elliptical_inclination, QZSettings::default_domyos_elliptical_inclination).toBool();
|
||||
}
|
||||
|
||||
void domyoselliptical::controllerStateChanged(QLowEnergyController::ControllerState state) {
|
||||
qDebug() << QStringLiteral("controllerStateChanged") << state;
|
||||
if (state == QLowEnergyController::UnconnectedState && m_control) {
|
||||
|
||||
@@ -37,6 +37,7 @@ class domyoselliptical : public elliptical {
|
||||
uint8_t bikeResistanceOffset = 4, double bikeResistanceGain = 1.0);
|
||||
~domyoselliptical();
|
||||
bool connected();
|
||||
bool inclinationAvailableByHardware();
|
||||
|
||||
void *VirtualTreadmill();
|
||||
void *VirtualDevice();
|
||||
|
||||
@@ -87,7 +87,7 @@ void domyosrower::updateDisplay(uint16_t elapsed) {
|
||||
0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x00};
|
||||
|
||||
display[3] = (elapsed / 60) & 0xFF; // high byte for elapsed time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elasped time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elapsed time (in seconds)
|
||||
|
||||
display[7] = ((uint8_t)((uint16_t)(currentSpeed().value()) >> 8)) & 0xFF;
|
||||
display[8] = (uint8_t)(currentSpeed().value()) & 0xFF;
|
||||
@@ -171,8 +171,8 @@ void domyosrower::update() {
|
||||
// ******************************************* virtual bike init *************************************
|
||||
QSettings settings;
|
||||
if (!firstVirtual && searchStopped && !virtualTreadmill && !virtualBike) {
|
||||
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
|
||||
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
@@ -263,7 +263,7 @@ void domyosrower::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
@@ -286,12 +286,12 @@ void domyosrower::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
inclination and speed status return;*/
|
||||
|
||||
double speed =
|
||||
GetSpeedFromPacket(newValue) * settings.value(QStringLiteral("domyos_elliptical_speed_ratio"), 1.0).toDouble();
|
||||
GetSpeedFromPacket(newValue) * settings.value(QZSettings::domyos_elliptical_speed_ratio, QZSettings::default_domyos_elliptical_speed_ratio).toDouble();
|
||||
double kcal = GetKcalFromPacket(newValue);
|
||||
double distance = GetDistanceFromPacket(newValue) *
|
||||
settings.value(QStringLiteral("domyos_elliptical_speed_ratio"), 1.0).toDouble();
|
||||
settings.value(QZSettings::domyos_elliptical_speed_ratio, QZSettings::default_domyos_elliptical_speed_ratio).toDouble();
|
||||
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((uint8_t)newValue.at(9));
|
||||
@@ -310,7 +310,7 @@ void domyosrower::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -579,7 +579,7 @@ uint16_t domyosrower::watts() {
|
||||
// calc Watts ref. https://alancouzens.com/blog/Run_Power.html
|
||||
|
||||
uint16_t watts = 0;
|
||||
double weight = settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
double weight = settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
if (currentSpeed().value() > 0) {
|
||||
|
||||
double pace = 60 / currentSpeed().value();
|
||||
|
||||
@@ -47,8 +47,15 @@ QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("49535343-fe7d-
|
||||
QBluetoothUuid _gattWriteCharacteristicId(QStringLiteral("49535343-8841-43f4-a8d4-ecbe34729bb3"));
|
||||
QBluetoothUuid _gattNotifyCharacteristicId(QStringLiteral("49535343-1e4d-4bd9-ba61-23c647249616"));
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
extern quint8 QZ_EnableDiscoveryCharsAndDescripttors;
|
||||
#endif
|
||||
|
||||
domyostreadmill::domyostreadmill(uint32_t pollDeviceTime, bool noConsole, bool noHeartService, double forceInitSpeed,
|
||||
double forceInitInclination) {
|
||||
#ifdef Q_OS_IOS
|
||||
QZ_EnableDiscoveryCharsAndDescripttors = true;
|
||||
#endif
|
||||
m_watt.setType(metric::METRIC_WATT);
|
||||
Speed.setType(metric::METRIC_SPEED);
|
||||
this->noConsole = noConsole;
|
||||
@@ -83,23 +90,28 @@ void domyostreadmill::writeCharacteristic(uint8_t *data, uint8_t data_len, const
|
||||
|
||||
if (gattCommunicationChannelService->state() != QLowEnergyService::ServiceState::ServiceDiscovered ||
|
||||
m_control->state() == QLowEnergyController::UnconnectedState) {
|
||||
emit debug(QStringLiteral("writeCharacteristic error because the connection is closed"));
|
||||
qDebug() << QStringLiteral("writeCharacteristic error because the connection is closed");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gattWriteCharacteristic.isValid()) {
|
||||
qDebug() << QStringLiteral("gattWriteCharacteristic is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic,
|
||||
QByteArray((const char *)data, data_len));
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + QByteArray((const char *)data, data_len).toHex(' ') +
|
||||
QStringLiteral(" // ") + info);
|
||||
qDebug() << QStringLiteral(" >> ") + QByteArray((const char *)data, data_len).toHex(' ') <<
|
||||
QStringLiteral(" // ") + info;
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
|
||||
if (timeout.isActive() == false) {
|
||||
emit debug(QStringLiteral(" exit for timeout"));
|
||||
qDebug() << QStringLiteral(" exit for timeout");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,17 +120,17 @@ void domyostreadmill::updateDisplay(uint16_t elapsed) {
|
||||
0x01, 0x00, 0x05, 0x01, 0x01, 0x00, 0x0c, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00};
|
||||
|
||||
QSettings settings;
|
||||
bool distance = settings.value(QStringLiteral("domyos_treadmill_distance_display"), true).toBool();
|
||||
bool domyos_treadmill_display_invert = settings.value(QStringLiteral("domyos_treadmill_display_invert"), false).toBool();
|
||||
bool distance = settings.value(QZSettings::domyos_treadmill_distance_display, QZSettings::default_domyos_treadmill_distance_display).toBool();
|
||||
bool domyos_treadmill_display_invert = settings.value(QZSettings::domyos_treadmill_display_invert, QZSettings::default_domyos_treadmill_display_invert).toBool();
|
||||
|
||||
if (elapsed > 5999) // 99:59
|
||||
{
|
||||
display[3] = ((elapsed / 60) / 60) & 0xFF; // high byte for elapsed time (in seconds)
|
||||
display[4] = ((elapsed / 60) % 60) & 0xFF; // low byte for elasped time (in seconds)
|
||||
display[4] = ((elapsed / 60) % 60) & 0xFF; // low byte for elapsed time (in seconds)
|
||||
} else {
|
||||
|
||||
display[3] = (elapsed / 60) & 0xFF; // high byte for elapsed time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elasped time (in seconds)
|
||||
display[4] = (elapsed % 60 & 0xFF); // low byte for elapsed time (in seconds)
|
||||
}
|
||||
|
||||
if (distance) {
|
||||
@@ -255,8 +267,8 @@ void domyostreadmill::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && searchStopped && !virtualTreadMill && !virtualBike) {
|
||||
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
|
||||
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
@@ -277,7 +289,7 @@ void domyostreadmill::update() {
|
||||
|
||||
// debug("Domyos Treadmill RSSI " + QString::number(bluetoothDevice.rssi()));
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
// updating the treadmill console every second
|
||||
if (sec1Update++ >= (1000 / refresh->interval())) {
|
||||
@@ -302,7 +314,7 @@ void domyostreadmill::update() {
|
||||
double inc = Inclination.value();
|
||||
if (requestInclination != -100) {
|
||||
|
||||
// only 0.5 steps ara avaiable
|
||||
// only 0.5 steps ara available
|
||||
requestInclination = qRound(requestInclination * 2.0) / 2.0;
|
||||
inc = requestInclination;
|
||||
requestInclination = -100;
|
||||
@@ -314,7 +326,7 @@ void domyostreadmill::update() {
|
||||
if (requestInclination != -100) {
|
||||
if(requestInclination < 0)
|
||||
requestInclination = 0;
|
||||
// only 0.5 steps ara avaiable
|
||||
// only 0.5 steps ara available
|
||||
requestInclination = qRound(requestInclination * 2.0) / 2.0;
|
||||
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
|
||||
requestInclination <= 15) {
|
||||
@@ -376,17 +388,17 @@ void domyostreadmill::characteristicChanged(const QLowEnergyCharacteristic &char
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
bool domyos_treadmill_buttons = settings.value(QStringLiteral("domyos_treadmill_buttons"), false).toBool();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
bool domyos_treadmill_buttons = settings.value(QZSettings::domyos_treadmill_buttons, QZSettings::default_domyos_treadmill_buttons).toBool();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
emit debug(QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' '));
|
||||
|
||||
// for the init packets, the lenght is always less than 20
|
||||
// for the display and status packets, the lenght is always grater then 20 and there are 2 cases:
|
||||
// - intense run: it always send more than 20 bytes in one packets, so the lenght will be always != 20
|
||||
// - t900: it splits packets with lenght grater than 20 in two distinct packets, so the first one it has lenght of
|
||||
// for the init packets, the length is always less than 20
|
||||
// for the display and status packets, the length is always grater then 20 and there are 2 cases:
|
||||
// - intense run: it always send more than 20 bytes in one packets, so the length will be always != 20
|
||||
// - t900: it splits packets with length grater than 20 in two distinct packets, so the first one it has length of
|
||||
// 20,
|
||||
// and the second one with the remained byte
|
||||
// so this simply condition will match all the cases, excluding the 20byte packet of the T900.
|
||||
@@ -404,7 +416,7 @@ void domyostreadmill::characteristicChanged(const QLowEnergyCharacteristic &char
|
||||
startBytes2.append(0xf0);
|
||||
startBytes2.append(0xdb);
|
||||
|
||||
// on some treadmills, the 26bytes has splitted in 2 packets
|
||||
// on some treadmills, the 26bytes has split in 2 packets
|
||||
if ((lastPacket.length() == 20 && lastPacket.startsWith(startBytes) && value.length() == 6) ||
|
||||
(lastPacket.length() == 20 && lastPacket.startsWith(startBytes2) && value.length() == 7)) {
|
||||
|
||||
@@ -526,10 +538,10 @@ void domyostreadmill::characteristicChanged(const QLowEnergyCharacteristic &char
|
||||
double incline = GetInclinationFromPacket(value);
|
||||
double kcal = GetKcalFromPacket(value);
|
||||
double distance = GetDistanceFromPacket(value);
|
||||
bool disable_hr_frommachinery = settings.value(QStringLiteral("heart_ignore_builtin"), false).toBool();
|
||||
bool disable_hr_frommachinery = settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -557,7 +569,7 @@ void domyostreadmill::characteristicChanged(const QLowEnergyCharacteristic &char
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
if (settings.value(QStringLiteral("power_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
{
|
||||
@@ -571,10 +583,10 @@ void domyostreadmill::characteristicChanged(const QLowEnergyCharacteristic &char
|
||||
FanSpeed = value.at(23);
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
|
||||
@@ -189,7 +189,8 @@ double echelonconnectsport::bikeResistanceToPeloton(double resistance) {
|
||||
if (p < 0) {
|
||||
p = 0;
|
||||
}
|
||||
return (p * settings.value(QStringLiteral("peloton_gain"), 1.0).toDouble()) + settings.value(QStringLiteral("peloton_offset"), 0.0).toDouble();
|
||||
return (p * settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
}
|
||||
|
||||
void echelonconnectsport::characteristicChanged(const QLowEnergyCharacteristic &characteristic,
|
||||
@@ -198,7 +199,7 @@ void echelonconnectsport::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
qDebug() << " << " + newValue.toHex(' ');
|
||||
|
||||
@@ -223,19 +224,22 @@ void echelonconnectsport::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
|
||||
double distance = GetDistanceFromPacket(newValue);
|
||||
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((uint8_t)newValue.at(10));
|
||||
}
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = 0.37497622 * ((double)Cadence.value());
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
@@ -251,7 +255,7 @@ void echelonconnectsport::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QStringLiteral("ant_heart"), false).toBool()) {
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
} else
|
||||
#endif
|
||||
@@ -272,8 +276,9 @@ void echelonconnectsport::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -380,11 +385,14 @@ void echelonconnectsport::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence =
|
||||
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
@@ -595,7 +603,9 @@ uint16_t echelonconnectsport::wattsFromResistance(double resistance) {
|
||||
}
|
||||
double *watts_of_level;
|
||||
QSettings settings;
|
||||
if (!settings.value("echelon_watttable", "Echelon").toString().compare("mgarcea"))
|
||||
if (!settings.value(QZSettings::echelon_watttable, QZSettings::default_echelon_watttable)
|
||||
.toString()
|
||||
.compare("mgarcea"))
|
||||
watts_of_level = wattTable_mgarcea[level];
|
||||
else
|
||||
watts_of_level = wattTable[level];
|
||||
|
||||
@@ -191,7 +191,7 @@ void echelonrower::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
qDebug() << QStringLiteral(" << ") + newvalue.toHex(' ');
|
||||
|
||||
@@ -221,7 +221,7 @@ void echelonrower::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
|
||||
// double distance = GetDistanceFromPacket(newValue);
|
||||
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((uint8_t)lastPacket.at(11));
|
||||
@@ -234,7 +234,7 @@ void echelonrower::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
Cadence.value(); // this is just to fill the tile, but it's quite useless since the machinery doesn't report it
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
@@ -250,7 +250,7 @@ void echelonrower::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QStringLiteral("ant_heart"), false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -271,9 +271,9 @@ void echelonrower::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool virtual_device_rower = settings.value("virtual_device_rower", false).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
bool virtual_device_rower = settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
|
||||
if (ios_peloton_workaround && cadence && !virtual_device_rower && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -375,12 +375,12 @@ void echelonrower::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_rower = settings.value("virtual_device_rower", false).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_rower = settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && !virtual_device_rower) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
|
||||
@@ -132,8 +132,8 @@ void echelonstride::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && !virtualTreadMill && !virtualBike) {
|
||||
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
|
||||
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
@@ -152,7 +152,7 @@ void echelonstride::update() {
|
||||
}
|
||||
// ********************************************************************************************************
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
// updating the treadmill console every second
|
||||
if (sec1Update++ >= (2000 / refresh->interval())) {
|
||||
@@ -184,6 +184,13 @@ void echelonstride::update() {
|
||||
}
|
||||
uint8_t initData3[] = {0xf0, 0xb0, 0x01, 0x01, 0xa2};
|
||||
writeCharacteristic(initData3, sizeof(initData3), QStringLiteral("start"), false, true);
|
||||
|
||||
uint8_t initData4[] = {0xf0, 0xd0, 0x01, 0x00, 0xc1};
|
||||
writeCharacteristic(initData4, sizeof(initData4), QStringLiteral("start"), false, false);
|
||||
|
||||
uint8_t initData5[] = {0xf0, 0xd0, 0x01, 0x11, 0xd2};
|
||||
writeCharacteristic(initData5, sizeof(initData5), QStringLiteral("start"), false, false);
|
||||
|
||||
lastStart = QDateTime::currentMSecsSinceEpoch();
|
||||
requestStart = -1;
|
||||
emit tapeStarted();
|
||||
@@ -222,7 +229,7 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
@@ -232,6 +239,8 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
|
||||
if (((unsigned char)newValue.at(0)) == 0xf0 && ((unsigned char)newValue.at(1)) == 0xd3) {
|
||||
|
||||
writeCharacteristic((uint8_t*)newValue.constData(), newValue.length(), "reply to d3", false, false);
|
||||
|
||||
double miles = 1.60934;
|
||||
|
||||
// this line on iOS sometimes gives strange overflow values
|
||||
@@ -255,9 +264,13 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
qDebug() << QStringLiteral("Current Speed: ") + QString::number(Speed.value());
|
||||
return;
|
||||
} else if (((unsigned char)newValue.at(0)) == 0xf0 && ((unsigned char)newValue.at(1)) == 0xd2) {
|
||||
writeCharacteristic((uint8_t*)newValue.constData(), newValue.length(), "reply to d2", false, false);
|
||||
Inclination = (uint8_t)newValue.at(3);
|
||||
qDebug() << QStringLiteral("Current Inclination: ") + QString::number(Inclination.value());
|
||||
return;
|
||||
} else if (((unsigned char)newValue.at(0)) == 0xf0 && ((unsigned char)newValue.at(1)) == 0xd0) {
|
||||
writeCharacteristic((uint8_t*)newValue.constData(), newValue.length(), "reply to d0", false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
/*if (newValue.length() != 21)
|
||||
@@ -267,10 +280,10 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
return;*/
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
@@ -281,7 +294,7 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
|
||||
if((uint8_t)newValue.at(1) == 0xD1 && newValue.length() > 11)
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -309,7 +322,7 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
qDebug() << QStringLiteral("Current Heart: ") + QString::number(Heart.value());
|
||||
qDebug() << QStringLiteral("Current Calculate Distance: ") + QString::number(Distance.value());
|
||||
qDebug() << QStringLiteral("Current Watt: ") +
|
||||
QString::number(watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
QString::number(watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
if (m_control->error() != QLowEnergyController::NoError)
|
||||
qDebug() << QStringLiteral("QLowEnergyController ERROR!!") << m_control->errorString();
|
||||
@@ -319,15 +332,12 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
}
|
||||
|
||||
void echelonstride::btinit() {
|
||||
uint8_t initData0[] = {0xf0, 0xa4, 0x00, 0x94};
|
||||
uint8_t initData1[] = {0xf0, 0xa1, 0x00, 0x91};
|
||||
uint8_t initData2[] = {0xf0, 0xa3, 0x00, 0x93};
|
||||
// uint8_t initData4[] = { 0xf0, 0x60, 0x00, 0x50 }; // get sleep command
|
||||
|
||||
// useless i guess
|
||||
// writeCharacteristic(initData4, sizeof(initData4), "get sleep", false, true);
|
||||
writeCharacteristic(initData0, sizeof(initData0), QStringLiteral("init"), false, true);
|
||||
|
||||
// in the snoof log it repeats this frame 4 times, i will have to analyze the response to understand if 4 times are
|
||||
// enough
|
||||
writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true);
|
||||
|
||||
@@ -34,7 +34,7 @@ void eliterizer::changeInclinationRequested(double grade, double percentage) {
|
||||
Q_UNUSED(grade);
|
||||
uint8_t incline[] = {0x0a, 0x00, 0x00};
|
||||
QSettings settings;
|
||||
double gain = settings.value(QStringLiteral("elite_rizer_gain"), 1.0).toDouble();
|
||||
double gain = settings.value(QZSettings::elite_rizer_gain, QZSettings::default_elite_rizer_gain).toDouble();
|
||||
percentage = percentage * gain;
|
||||
|
||||
incline[1] = ((int16_t)(percentage * 10.0)) & 0xff;
|
||||
|
||||
@@ -10,7 +10,7 @@ void elliptical::update_metrics(bool watt_calc, const double watts) {
|
||||
double deltaTime = (((double)_lastTimeUpdate.msecsTo(current)) / ((double)1000.0));
|
||||
QSettings settings;
|
||||
if (!_firstUpdate && !paused) {
|
||||
if (currentSpeed().value() > 0.0 || settings.value(QStringLiteral("continuous_moving"), true).toBool()) {
|
||||
if (currentSpeed().value() > 0.0 || settings.value(QZSettings::continuous_moving, true).toBool()) {
|
||||
elapsed += deltaTime;
|
||||
}
|
||||
if (currentSpeed().value() > 0.0) {
|
||||
@@ -20,7 +20,7 @@ void elliptical::update_metrics(bool watt_calc, const double watts) {
|
||||
}
|
||||
m_jouls += (m_watt.value() * deltaTime);
|
||||
WeightLoss = metric::calculateWeightLoss(KCal.value());
|
||||
WattKg = m_watt.value() / settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
WattKg = m_watt.value() / settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
} else if (m_watt.value() > 0) {
|
||||
m_watt = 0;
|
||||
WattKg = 0;
|
||||
@@ -40,7 +40,7 @@ void elliptical::update_metrics(bool watt_calc, const double watts) {
|
||||
uint16_t elliptical::watts() {
|
||||
|
||||
QSettings settings;
|
||||
double weight = settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
double weight = settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
// calc Watts ref. https://alancouzens.com/blog/Run_Power.html
|
||||
|
||||
uint16_t watts = 0;
|
||||
@@ -133,3 +133,4 @@ metric elliptical::lastRequestedCadence() { return RequestedCadence; }
|
||||
metric elliptical::pelotonResistance() { return m_pelotonResistance; }
|
||||
metric elliptical::lastRequestedPelotonResistance() { return RequestedPelotonResistance; }
|
||||
metric elliptical::lastRequestedResistance() { return RequestedResistance; }
|
||||
bool elliptical::inclinationAvailableByHardware() { return true; }
|
||||
|
||||
@@ -22,6 +22,7 @@ class elliptical : public bluetoothdevice {
|
||||
virtual bool connected();
|
||||
metric pelotonResistance();
|
||||
virtual int pelotonToEllipticalResistance(int pelotonResistance);
|
||||
virtual bool inclinationAvailableByHardware();
|
||||
bluetoothdevice::BLUETOOTH_TYPE deviceType();
|
||||
void clearStats();
|
||||
void setPaused(bool p);
|
||||
|
||||
@@ -60,7 +60,7 @@ void eslinkertreadmill::writeCharacteristic(uint8_t *data, uint8_t data_len, con
|
||||
}
|
||||
|
||||
void eslinkertreadmill::updateDisplay(uint16_t elapsed) {
|
||||
if (treadmill_type == RHYTHM_FUN) {
|
||||
if (treadmill_type == RHYTHM_FUN || treadmill_type == YPOO_MINI_CHANGE) {
|
||||
// trying to force a fixed value to keep the connection on
|
||||
uint8_t display[] = {0xa9, 0xa0, 0x03, 0x02, 0x23, 0x00, 0x2b};
|
||||
|
||||
@@ -111,7 +111,7 @@ void eslinkertreadmill::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && !virtualTreadMill) {
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
emit debug(QStringLiteral("creating virtual treadmill interface..."));
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
@@ -121,7 +121,7 @@ void eslinkertreadmill::update() {
|
||||
}
|
||||
// ********************************************************************************************************
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
// updating the treadmill console every second
|
||||
// it seems that stops the communication
|
||||
@@ -129,7 +129,7 @@ void eslinkertreadmill::update() {
|
||||
updateDisplay(elapsed.value());
|
||||
}
|
||||
|
||||
if (treadmill_type == TYPE::RHYTHM_FUN) {
|
||||
if (treadmill_type == TYPE::RHYTHM_FUN || treadmill_type == TYPE::YPOO_MINI_CHANGE) { //
|
||||
if (requestSpeed != -1) {
|
||||
if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) {
|
||||
emit debug(QStringLiteral("writing speed ") + QString::number(requestSpeed));
|
||||
@@ -202,7 +202,7 @@ void eslinkertreadmill::update() {
|
||||
if (lastSpeed == 0.0) {
|
||||
lastSpeed = 0.5;
|
||||
}
|
||||
if (treadmill_type == TYPE::RHYTHM_FUN)
|
||||
if (treadmill_type == TYPE::RHYTHM_FUN || treadmill_type == TYPE::YPOO_MINI_CHANGE)
|
||||
btinit(true);
|
||||
requestSpeed = 1.0;
|
||||
requestStart = -1;
|
||||
@@ -226,7 +226,7 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
@@ -299,7 +299,7 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch
|
||||
} else if (newValue.length() == 3 && newValue.at(0) == 2 && newValue.at(1) == 1) {
|
||||
uint8_t heart = newValue.at(2);
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -311,17 +311,17 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch
|
||||
}
|
||||
}
|
||||
|
||||
if ((newValue.length() != 17 && treadmill_type == RHYTHM_FUN))
|
||||
if ((newValue.length() != 17 && (treadmill_type == RHYTHM_FUN || treadmill_type == YPOO_MINI_CHANGE)))
|
||||
return;
|
||||
|
||||
if (treadmill_type == RHYTHM_FUN) {
|
||||
if (treadmill_type == RHYTHM_FUN || treadmill_type == YPOO_MINI_CHANGE) {
|
||||
double speed = GetSpeedFromPacket(value);
|
||||
double incline = GetInclinationFromPacket(value);
|
||||
double kcal = GetKcalFromPacket(value);
|
||||
// double distance = GetDistanceFromPacket(value);
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -353,10 +353,10 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch
|
||||
}
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
|
||||
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
@@ -379,12 +379,23 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch
|
||||
double eslinkertreadmill::GetSpeedFromPacket(const QByteArray &packet) {
|
||||
uint8_t convertedData = (uint8_t)packet.at(14);
|
||||
double data = (double)convertedData / 10.0f;
|
||||
if (treadmill_type == YPOO_MINI_CHANGE && data < 1.0) {
|
||||
data = 0.0;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
double eslinkertreadmill::GetKcalFromPacket(const QByteArray &packet) {
|
||||
uint16_t convertedData = (packet.at(7) << 8) | packet.at(8);
|
||||
return (double)convertedData;
|
||||
double data;
|
||||
if (treadmill_type == YPOO_MINI_CHANGE) {
|
||||
uint16_t convertedData = (((uint8_t)packet.at(5)) << 8) | (uint8_t)packet.at(6);;
|
||||
data = (double)convertedData / 100.0f;
|
||||
}
|
||||
else {
|
||||
uint16_t convertedData = (packet.at(7) << 8) | packet.at(8);
|
||||
data = (double)convertedData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
double eslinkertreadmill::GetDistanceFromPacket(const QByteArray &packet) {
|
||||
@@ -394,9 +405,11 @@ double eslinkertreadmill::GetDistanceFromPacket(const QByteArray &packet) {
|
||||
}
|
||||
|
||||
double eslinkertreadmill::GetInclinationFromPacket(const QByteArray &packet) {
|
||||
uint16_t convertedData = packet.at(11);
|
||||
double data = convertedData;
|
||||
|
||||
double data = 0.0;
|
||||
if (treadmill_type != YPOO_MINI_CHANGE) {
|
||||
uint16_t convertedData = packet.at(11);
|
||||
data = convertedData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -418,7 +431,7 @@ void eslinkertreadmill::btinit(bool startTape) {
|
||||
|
||||
uint8_t initData2_CADENZA[] = {0x08, 0x01, 0x01};
|
||||
|
||||
if (treadmill_type == RHYTHM_FUN) {
|
||||
if (treadmill_type == RHYTHM_FUN || treadmill_type == YPOO_MINI_CHANGE) {
|
||||
writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, false);
|
||||
writeCharacteristic(initData2, sizeof(initData2), QStringLiteral("init"), false, true);
|
||||
writeCharacteristic(initData3, sizeof(initData3), QStringLiteral("init"), false, true);
|
||||
@@ -542,9 +555,12 @@ void eslinkertreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
});
|
||||
|
||||
QSettings settings;
|
||||
bool eslinker_cadenza = settings.value(QStringLiteral("eslinker_cadenza"), true).toBool();
|
||||
bool eslinker_cadenza = settings.value(QZSettings::eslinker_cadenza, QZSettings::default_eslinker_cadenza).toBool();
|
||||
bool eslinker_ypoo = settings.value(QZSettings::eslinker_ypoo, QZSettings::default_eslinker_ypoo).toBool();
|
||||
if (eslinker_cadenza) {
|
||||
treadmill_type = CADENZA_FITNESS_T45;
|
||||
} else if (eslinker_ypoo) {
|
||||
treadmill_type = YPOO_MINI_CHANGE;
|
||||
} else
|
||||
treadmill_type = RHYTHM_FUN;
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ class eslinkertreadmill : public treadmill {
|
||||
typedef enum TYPE {
|
||||
RHYTHM_FUN = 0,
|
||||
CADENZA_FITNESS_T45 = 1, // it has the same protocol of RHYTHM_FUN but without the header and the footer
|
||||
YPOO_MINI_CHANGE = 2, // Similar to RHYTHM_FUN but has no ascension
|
||||
} TYPE;
|
||||
volatile TYPE treadmill_type = RHYTHM_FUN;
|
||||
|
||||
|
||||
@@ -31,7 +31,20 @@ fakebike::fakebike(bool noWriteResistance, bool noHeartService, bool noVirtualDe
|
||||
void fakebike::update() {
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
/*
|
||||
static int updcou = 0;
|
||||
updcou++;
|
||||
double w = 250.0;
|
||||
if (updcou > 20000 )
|
||||
updcou = 0;
|
||||
else if (updcou > 12000)
|
||||
w = 300;
|
||||
else if (updcou > 6000)
|
||||
w = 150;
|
||||
|
||||
Speed = metric::calculateSpeedFromPower(w, Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), speedLimit());*/
|
||||
|
||||
update_metrics(true, watts());
|
||||
|
||||
@@ -47,11 +60,11 @@ void fakebike::update() {
|
||||
#endif
|
||||
#endif
|
||||
) {
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
@@ -73,7 +86,7 @@ void fakebike::update() {
|
||||
|
||||
if (!noVirtualDevice) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool()) {
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
debug("Current Heart: " + QString::number(Heart.value()));
|
||||
}
|
||||
@@ -93,8 +106,8 @@ void fakebike::update() {
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -104,39 +117,7 @@ void fakebike::update() {
|
||||
}
|
||||
|
||||
if (Heart.value()) {
|
||||
|
||||
/*
|
||||
* If VO2 max is unknown, the following formulas would apply:
|
||||
|
||||
Women:
|
||||
|
||||
CB = T * (0.4472*H - 0.1263*W + 0.074*A - 20.4022) / 4.184
|
||||
|
||||
Men:
|
||||
|
||||
CB = T * (0.6309*H + 0.1988*W + 0.2017*A - 55.0969) / 4.184
|
||||
|
||||
Where:
|
||||
|
||||
CB is the number of calories burned;
|
||||
T is the duration of exercise in minutes;
|
||||
H is your average heart rate in beats per minute;
|
||||
W is your weight in kilograms; and
|
||||
A is your age in years.
|
||||
*/
|
||||
|
||||
QString sex = settings.value(QStringLiteral("sex"), "Male").toString();
|
||||
double weight = settings.value(QStringLiteral("weight"), 75.0).toFloat();
|
||||
double age = settings.value(QStringLiteral("age"), 35).toDouble();
|
||||
double T = elapsed.value() / 60;
|
||||
double H = Heart.average();
|
||||
double W = weight;
|
||||
double A = age;
|
||||
if (sex.toLower().contains("female")) {
|
||||
KCal = T * ((0.4472 * H) - (0.1263 * W) + (0.074 * A) - 20.4022) / 4.184;
|
||||
} else {
|
||||
KCal = T * ((0.6309 * H) + (0.1988 * W) + (0.2017 * A) - 55.0969) / 4.184;
|
||||
}
|
||||
KCal = metric::calculateKCalfromHR(Heart.average(), elapsed.value());
|
||||
}
|
||||
|
||||
if (requestResistance != -1 && requestResistance != currentResistance().value()) {
|
||||
|
||||
@@ -31,7 +31,7 @@ fakeelliptical::fakeelliptical(bool noWriteResistance, bool noHeartService, bool
|
||||
void fakeelliptical::update() {
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
update_metrics(true, watts());
|
||||
|
||||
@@ -53,11 +53,11 @@ void fakeelliptical::update() {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
@@ -69,7 +69,8 @@ void fakeelliptical::update() {
|
||||
emit debug(QStringLiteral("creating virtual bike interface..."));
|
||||
virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &fakeelliptical::changeInclinationRequested);
|
||||
connect(virtualBike, &virtualbike::ftmsCharacteristicChanged, this, &fakeelliptical::ftmsCharacteristicChanged);
|
||||
connect(virtualBike, &virtualbike::ftmsCharacteristicChanged, this,
|
||||
&fakeelliptical::ftmsCharacteristicChanged);
|
||||
}
|
||||
}
|
||||
if (!firstStateChanged)
|
||||
@@ -79,7 +80,7 @@ void fakeelliptical::update() {
|
||||
|
||||
if (!noVirtualDevice) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool()) {
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
debug("Current Heart: " + QString::number(Heart.value()));
|
||||
}
|
||||
@@ -99,8 +100,8 @@ void fakeelliptical::update() {
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -109,12 +110,17 @@ void fakeelliptical::update() {
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Heart.value()) {
|
||||
KCal = metric::calculateKCalfromHR(Heart.average(), elapsed.value());
|
||||
}
|
||||
|
||||
if (requestResistance != -1 && requestResistance != currentResistance().value()) {
|
||||
Resistance = requestResistance;
|
||||
}
|
||||
}
|
||||
|
||||
void fakeelliptical::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
void fakeelliptical::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic,
|
||||
const QByteArray &newValue) {
|
||||
QByteArray b = newValue;
|
||||
qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' ');
|
||||
}
|
||||
|
||||
137
src/faketreadmill.cpp
Normal file
137
src/faketreadmill.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "faketreadmill.h"
|
||||
#include "ios/lockscreen.h"
|
||||
#include "virtualbike.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
#include <QMetaEnum>
|
||||
#include <QSettings>
|
||||
#include <QThread>
|
||||
#include <math.h>
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include <QLowEnergyConnectionParameters>
|
||||
#endif
|
||||
#include "keepawakehelper.h"
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
faketreadmill::faketreadmill(bool noWriteResistance, bool noHeartService, bool noVirtualDevice) {
|
||||
m_watt.setType(metric::METRIC_WATT);
|
||||
Speed.setType(metric::METRIC_SPEED);
|
||||
refresh = new QTimer(this);
|
||||
this->noWriteResistance = noWriteResistance;
|
||||
this->noHeartService = noHeartService;
|
||||
this->noVirtualDevice = noVirtualDevice;
|
||||
initDone = false;
|
||||
connect(refresh, &QTimer::timeout, this, &faketreadmill::update);
|
||||
refresh->start(200ms);
|
||||
}
|
||||
|
||||
void faketreadmill::update() {
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
if (requestSpeed != -1) {
|
||||
Speed = requestSpeed;
|
||||
emit debug(QStringLiteral("writing speed ") + QString::number(requestSpeed));
|
||||
requestSpeed = -1;
|
||||
}
|
||||
|
||||
if (requestInclination != -100) {
|
||||
Inclination = requestInclination;
|
||||
emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination));
|
||||
requestInclination = -100;
|
||||
}
|
||||
|
||||
Distance += ((Speed.value() / (double)3600.0) /
|
||||
((double)1000.0 / (double)(lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstStateChanged && !virtualTreadmill && !virtualBike) {
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_force_bike =
|
||||
settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike)
|
||||
.toBool();
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_force_bike) {
|
||||
debug("creating virtual treadmill interface...");
|
||||
virtualTreadmill = new virtualtreadmill(this, noHeartService);
|
||||
connect(virtualTreadmill, &virtualtreadmill::debug, this, &faketreadmill::debug);
|
||||
connect(virtualTreadmill, &virtualtreadmill::changeInclination, this,
|
||||
&faketreadmill::changeInclinationRequested);
|
||||
} else {
|
||||
debug("creating virtual bike interface...");
|
||||
virtualBike = new virtualbike(this);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &faketreadmill::changeInclinationRequested);
|
||||
}
|
||||
}
|
||||
if (!firstStateChanged)
|
||||
emit connectedAndDiscovered();
|
||||
firstStateChanged = 1;
|
||||
}
|
||||
// ********************************************************************************************************
|
||||
|
||||
if (!noVirtualDevice) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
debug("Current Heart: " + QString::number(Heart.value()));
|
||||
}
|
||||
#endif
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) {
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
lockscreen h;
|
||||
long appleWatchHeartRate = h.heartRate();
|
||||
h.setKcal(KCal.value());
|
||||
h.setDistance(Distance.value());
|
||||
Heart = appleWatchHeartRate;
|
||||
debug("Current Heart from Apple Watch: " + QString::number(appleWatchHeartRate));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence =
|
||||
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (Heart.value()) {
|
||||
KCal = metric::calculateKCalfromHR(Heart.average(), elapsed.value());
|
||||
}
|
||||
}
|
||||
|
||||
void faketreadmill::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic,
|
||||
const QByteArray &newValue) {
|
||||
QByteArray b = newValue;
|
||||
qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' ');
|
||||
}
|
||||
|
||||
void faketreadmill::changeInclinationRequested(double grade, double percentage) {
|
||||
if (percentage < 0)
|
||||
percentage = 0;
|
||||
changeInclination(grade, percentage);
|
||||
}
|
||||
|
||||
bool faketreadmill::connected() { return true; }
|
||||
|
||||
void *faketreadmill::VirtualBike() { return virtualBike; }
|
||||
|
||||
void *faketreadmill::VirtualTreadmill() { return virtualTreadmill; }
|
||||
|
||||
void *faketreadmill::VirtualDevice() { return VirtualTreadmill(); }
|
||||
80
src/faketreadmill.h
Normal file
80
src/faketreadmill.h
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef FAKETREADMILL_H
|
||||
#define FAKETREADMILL_H
|
||||
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QtBluetooth/qlowenergyadvertisingdata.h>
|
||||
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristic.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristicdata.h>
|
||||
#include <QtBluetooth/qlowenergycontroller.h>
|
||||
#include <QtBluetooth/qlowenergydescriptordata.h>
|
||||
#include <QtBluetooth/qlowenergyservice.h>
|
||||
#include <QtBluetooth/qlowenergyservicedata.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#else
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#endif
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "treadmill.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualtreadmill.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
#endif
|
||||
|
||||
class faketreadmill : public treadmill {
|
||||
Q_OBJECT
|
||||
public:
|
||||
faketreadmill(bool noWriteResistance, bool noHeartService, bool noVirtualDevice);
|
||||
bool connected();
|
||||
|
||||
void *VirtualBike();
|
||||
void *VirtualTreadmill();
|
||||
void *VirtualDevice();
|
||||
|
||||
private:
|
||||
QTimer *refresh;
|
||||
virtualbike *virtualBike = nullptr;
|
||||
virtualtreadmill *virtualTreadmill = nullptr;
|
||||
|
||||
uint8_t sec1Update = 0;
|
||||
QByteArray lastPacket;
|
||||
QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
QDateTime lastGoodCadence = QDateTime::currentDateTime();
|
||||
uint8_t firstStateChanged = 0;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
|
||||
bool noWriteResistance = false;
|
||||
bool noHeartService = false;
|
||||
bool noVirtualDevice = false;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void disconnected();
|
||||
void debug(QString string);
|
||||
|
||||
private slots:
|
||||
void changeInclinationRequested(double grade, double percentage);
|
||||
void update();
|
||||
|
||||
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
};
|
||||
|
||||
#endif // FAKETREADMILL_H
|
||||
@@ -148,7 +148,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the accelerometer sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z
|
||||
// Comment: Each time in the array describes the time at which the accelerometer sample with the corresponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_UINT16 GetSampleTimeOffset(FIT_UINT8 index) const
|
||||
{
|
||||
@@ -158,7 +158,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the accelerometer sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z
|
||||
// Comment: Each time in the array describes the time at which the accelerometer sample with the corresponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in accel_x and accel_y and accel_z
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetSampleTimeOffset(FIT_UINT8 index, FIT_UINT16 sampleTimeOffset)
|
||||
{
|
||||
|
||||
@@ -140,7 +140,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the barometer sample with the corrosponding index was taken. The samples may span across seconds. Array size must match the number of samples in baro_cal
|
||||
// Comment: Each time in the array describes the time at which the barometer sample with the corresponding index was taken. The samples may span across seconds. Array size must match the number of samples in baro_cal
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_UINT16 GetSampleTimeOffset(FIT_UINT8 index) const
|
||||
{
|
||||
@@ -150,7 +150,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the barometer sample with the corrosponding index was taken. The samples may span across seconds. Array size must match the number of samples in baro_cal
|
||||
// Comment: Each time in the array describes the time at which the barometer sample with the corresponding index was taken. The samples may span across seconds. Array size must match the number of samples in baro_cal
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetSampleTimeOffset(FIT_UINT8 index, FIT_UINT16 sampleTimeOffset)
|
||||
{
|
||||
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the gyro sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z
|
||||
// Comment: Each time in the array describes the time at which the gyro sample with the corresponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_UINT16 GetSampleTimeOffset(FIT_UINT8 index) const
|
||||
{
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the gyro sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z
|
||||
// Comment: Each time in the array describes the time at which the gyro sample with the corresponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in gyro_x and gyro_y and gyro_z
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetSampleTimeOffset(FIT_UINT8 index, FIT_UINT16 sampleTimeOffset)
|
||||
{
|
||||
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the compass sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in cmps_x and cmps_y and cmps_z
|
||||
// Comment: Each time in the array describes the time at which the compass sample with the corresponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in cmps_x and cmps_y and cmps_z
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_UINT16 GetSampleTimeOffset(FIT_UINT8 index) const
|
||||
{
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set sample_time_offset field
|
||||
// Units: ms
|
||||
// Comment: Each time in the array describes the time at which the compass sample with the corrosponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in cmps_x and cmps_y and cmps_z
|
||||
// Comment: Each time in the array describes the time at which the compass sample with the corresponding index was taken. Limited to 30 samples in each message. The samples may span across seconds. Array size must match the number of samples in cmps_x and cmps_y and cmps_z
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetSampleTimeOffset(FIT_UINT8 index, FIT_UINT16 sampleTimeOffset)
|
||||
{
|
||||
|
||||
@@ -145,7 +145,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns time_offset field
|
||||
// Units: ms
|
||||
// Comment: Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span accross seconds.
|
||||
// Comment: Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span across seconds.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_UINT16 GetTimeOffset(FIT_UINT8 index) const
|
||||
{
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set time_offset field
|
||||
// Units: ms
|
||||
// Comment: Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span accross seconds.
|
||||
// Comment: Offset of PID reading [i] from start_timestamp+start_timestamp_ms. Readings may span across seconds.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetTimeOffset(FIT_UINT8 index, FIT_UINT16 timeOffset)
|
||||
{
|
||||
|
||||
@@ -1865,7 +1865,7 @@ typedef FIT_UINT32Z FIT_CONNECTIVITY_CAPABILITIES;
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_CONNECT_IQ_WIDGET_DOWNLOAD ((FIT_CONNECTIVITY_CAPABILITIES)0x00020000)
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_CONNECT_IQ_WATCH_FACE_DOWNLOAD ((FIT_CONNECTIVITY_CAPABILITIES)0x00040000)
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_CONNECT_IQ_DATA_FIELD_DOWNLOAD ((FIT_CONNECTIVITY_CAPABILITIES)0x00080000)
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_CONNECT_IQ_APP_MANAGMENT ((FIT_CONNECTIVITY_CAPABILITIES)0x00100000) // Device supports delete and reorder of apps via GCM
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_CONNECT_IQ_APP_MANAGEMENT ((FIT_CONNECTIVITY_CAPABILITIES)0x00100000) // Device supports delete and reorder of apps via GCM
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_SWING_SENSOR ((FIT_CONNECTIVITY_CAPABILITIES)0x00200000)
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_SWING_SENSOR_REMOTE ((FIT_CONNECTIVITY_CAPABILITIES)0x00400000)
|
||||
#define FIT_CONNECTIVITY_CAPABILITIES_INCIDENT_DETECTION ((FIT_CONNECTIVITY_CAPABILITIES)0x00800000) // Device supports incident detection
|
||||
@@ -2297,7 +2297,7 @@ typedef FIT_ENUM FIT_EXD_DATA_UNITS;
|
||||
#define FIT_EXD_DATA_UNITS_FEET_PER_HOUR ((FIT_EXD_DATA_UNITS)4)
|
||||
#define FIT_EXD_DATA_UNITS_METERS_PER_HOUR ((FIT_EXD_DATA_UNITS)5)
|
||||
#define FIT_EXD_DATA_UNITS_DEGREES_CELSIUS ((FIT_EXD_DATA_UNITS)6)
|
||||
#define FIT_EXD_DATA_UNITS_DEGREES_FARENHEIT ((FIT_EXD_DATA_UNITS)7)
|
||||
#define FIT_EXD_DATA_UNITS_DEGREES_FAHRENHEIT ((FIT_EXD_DATA_UNITS)7)
|
||||
#define FIT_EXD_DATA_UNITS_ZONE ((FIT_EXD_DATA_UNITS)8)
|
||||
#define FIT_EXD_DATA_UNITS_GEAR ((FIT_EXD_DATA_UNITS)9)
|
||||
#define FIT_EXD_DATA_UNITS_RPM ((FIT_EXD_DATA_UNITS)10)
|
||||
@@ -2394,7 +2394,7 @@ typedef FIT_ENUM FIT_EXD_DESCRIPTORS;
|
||||
#define FIT_EXD_DESCRIPTORS_INVALID FIT_ENUM_INVALID
|
||||
#define FIT_EXD_DESCRIPTORS_BIKE_LIGHT_BATTERY_STATUS ((FIT_EXD_DESCRIPTORS)0)
|
||||
#define FIT_EXD_DESCRIPTORS_BEAM_ANGLE_STATUS ((FIT_EXD_DESCRIPTORS)1)
|
||||
#define FIT_EXD_DESCRIPTORS_BATERY_LEVEL ((FIT_EXD_DESCRIPTORS)2)
|
||||
#define FIT_EXD_DESCRIPTORS_BATTERY_LEVEL ((FIT_EXD_DESCRIPTORS)2)
|
||||
#define FIT_EXD_DESCRIPTORS_LIGHT_NETWORK_MODE ((FIT_EXD_DESCRIPTORS)3)
|
||||
#define FIT_EXD_DESCRIPTORS_NUMBER_LIGHTS_CONNECTED ((FIT_EXD_DESCRIPTORS)4)
|
||||
#define FIT_EXD_DESCRIPTORS_CADENCE ((FIT_EXD_DESCRIPTORS)5)
|
||||
|
||||
@@ -1361,7 +1361,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns cadence256 field
|
||||
// Units: rpm
|
||||
// Comment: Log cadence and fractional cadence for backwards compatability
|
||||
// Comment: Log cadence and fractional cadence for backwards compatibility
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_FLOAT32 GetCadence256(void) const
|
||||
{
|
||||
@@ -1371,7 +1371,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set cadence256 field
|
||||
// Units: rpm
|
||||
// Comment: Log cadence and fractional cadence for backwards compatability
|
||||
// Comment: Log cadence and fractional cadence for backwards compatibility
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetCadence256(FIT_FLOAT32 cadence256)
|
||||
{
|
||||
|
||||
@@ -223,7 +223,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns timestamp field
|
||||
// Units: s
|
||||
// Comment: Sesson end time.
|
||||
// Comment: Session end time.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_DATE_TIME GetTimestamp(void) const
|
||||
{
|
||||
@@ -233,7 +233,7 @@ public:
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set timestamp field
|
||||
// Units: s
|
||||
// Comment: Sesson end time.
|
||||
// Comment: Session end time.
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetTimestamp(FIT_DATE_TIME timestamp)
|
||||
{
|
||||
|
||||
@@ -134,7 +134,7 @@ public:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Returns repetitions field
|
||||
// Comment: # of repitions of the movement
|
||||
// Comment: # of repetitions of the movement
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
FIT_UINT16 GetRepetitions(void) const
|
||||
{
|
||||
@@ -143,7 +143,7 @@ public:
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Set repetitions field
|
||||
// Comment: # of repitions of the movement
|
||||
// Comment: # of repetitions of the movement
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
void SetRepetitions(FIT_UINT16 repetitions)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,14 @@
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
extern quint8 QZ_EnableDiscoveryCharsAndDescripttors;
|
||||
#endif
|
||||
|
||||
fitmetria_fanfit::fitmetria_fanfit(bluetoothdevice *parentDevice) {
|
||||
#ifdef Q_OS_IOS
|
||||
QZ_EnableDiscoveryCharsAndDescripttors = true;
|
||||
#endif
|
||||
this->parentDevice = parentDevice;
|
||||
}
|
||||
|
||||
@@ -40,14 +47,14 @@ void fitmetria_fanfit::fanSpeedRequest(uint8_t speed) {
|
||||
QSettings settings;
|
||||
if (speed > 102)
|
||||
speed = 102;
|
||||
double max = settings.value(QStringLiteral("fitmetria_fanfit_max"), 100).toDouble();
|
||||
double min = settings.value(QStringLiteral("fitmetria_fanfit_min"), 0).toDouble();
|
||||
double max = settings.value(QZSettings::fitmetria_fanfit_max, QZSettings::default_fitmetria_fanfit_max).toDouble();
|
||||
double min = settings.value(QZSettings::fitmetria_fanfit_min, QZSettings::default_fitmetria_fanfit_min).toDouble();
|
||||
|
||||
uint16_t speed16 = (uint16_t)((double)speed * ((max * 10.0) - (min * 10.0)) / 100.0 + (min * 10.0));
|
||||
const uint8_t brightness = 5;
|
||||
const uint8_t leds_max = 15;
|
||||
|
||||
uint8_t leds[leds_max] = {30,30,30,15,15,15,13,24,24,8,27,27,27,26,26};
|
||||
uint8_t leds[leds_max] = {30, 30, 30, 15, 15, 15, 13, 24, 24, 8, 27, 27, 27, 26, 26};
|
||||
// 0~5~30~30~30~15~15~15~13~24~24~8~27~27~27~26~26
|
||||
// 0 - fans peed
|
||||
// 1 - brightness
|
||||
@@ -88,52 +95,85 @@ void fitmetria_fanfit::fanSpeedRequest(uint8_t speed) {
|
||||
myCollorDict['Yellow'] = 31
|
||||
*/
|
||||
|
||||
QString s = QString::number((speed16)) +
|
||||
"~" + QString::number(brightness);
|
||||
QString s = QString::number((speed16)) + "~" + QString::number(brightness);
|
||||
|
||||
if(!settings.value(QStringLiteral("fitmetria_fanfit_mode"), QStringLiteral("Heart"))
|
||||
.toString()
|
||||
.compare(QStringLiteral("Power")) && parentDevice) {
|
||||
if (!settings.value(QZSettings::fitmetria_fanfit_mode, QZSettings::default_fitmetria_fanfit_mode)
|
||||
.toString()
|
||||
.compare(QStringLiteral("Power")) &&
|
||||
parentDevice) {
|
||||
double ftp = parentDevice->currentPowerZone().value();
|
||||
if(ftp < 1.3) memset(&leds[1], 0, leds_max - 1);
|
||||
else if(ftp < 1.6) memset(&leds[2], 0, leds_max - 2);
|
||||
else if(ftp < 2) memset(&leds[3], 0, leds_max - 3);
|
||||
else if(ftp < 2.4) memset(&leds[4], 0, leds_max - 4);
|
||||
else if(ftp < 3) memset(&leds[5], 0, leds_max - 5);
|
||||
else if(ftp < 3.3) memset(&leds[6], 0, leds_max - 6);
|
||||
else if(ftp < 3.6) memset(&leds[7], 0, leds_max - 7);
|
||||
else if(ftp < 4) memset(&leds[8], 0, leds_max - 8);
|
||||
else if(ftp < 5) memset(&leds[9], 0, leds_max - 9);
|
||||
else if(ftp < 5.6) memset(&leds[10], 0, leds_max - 10);
|
||||
else if(ftp < 6) memset(&leds[11], 0, leds_max - 11);
|
||||
else if(ftp < 6.6) memset(&leds[12], 0, leds_max - 12);
|
||||
else if(ftp < 7) memset(&leds[13], 0, leds_max - 13);
|
||||
else if(ftp < 7.1) memset(&leds[14], 0, leds_max - 14);
|
||||
} else if(!settings.value(QStringLiteral("fitmetria_fanfit_mode"), QStringLiteral("Heart"))
|
||||
.toString()
|
||||
.compare(QStringLiteral("Heart")) && parentDevice) {
|
||||
if (ftp < 1.3)
|
||||
memset(&leds[1], 0, leds_max - 1);
|
||||
else if (ftp < 1.6)
|
||||
memset(&leds[2], 0, leds_max - 2);
|
||||
else if (ftp < 2)
|
||||
memset(&leds[3], 0, leds_max - 3);
|
||||
else if (ftp < 2.4)
|
||||
memset(&leds[4], 0, leds_max - 4);
|
||||
else if (ftp < 3)
|
||||
memset(&leds[5], 0, leds_max - 5);
|
||||
else if (ftp < 3.3)
|
||||
memset(&leds[6], 0, leds_max - 6);
|
||||
else if (ftp < 3.6)
|
||||
memset(&leds[7], 0, leds_max - 7);
|
||||
else if (ftp < 4)
|
||||
memset(&leds[8], 0, leds_max - 8);
|
||||
else if (ftp < 5)
|
||||
memset(&leds[9], 0, leds_max - 9);
|
||||
else if (ftp < 5.6)
|
||||
memset(&leds[10], 0, leds_max - 10);
|
||||
else if (ftp < 6)
|
||||
memset(&leds[11], 0, leds_max - 11);
|
||||
else if (ftp < 6.6)
|
||||
memset(&leds[12], 0, leds_max - 12);
|
||||
else if (ftp < 7)
|
||||
memset(&leds[13], 0, leds_max - 13);
|
||||
else if (ftp < 7.1)
|
||||
memset(&leds[14], 0, leds_max - 14);
|
||||
} else if (!settings.value(QZSettings::fitmetria_fanfit_mode, QZSettings::default_fitmetria_fanfit_mode)
|
||||
.toString()
|
||||
.compare(QStringLiteral("Heart")) &&
|
||||
parentDevice) {
|
||||
double ftp = parentDevice->currentHeartZone().value();
|
||||
if(ftp < 1.3) memset(&leds[1], 0, leds_max - 1);
|
||||
else if(ftp < 1.6) memset(&leds[2], 0, leds_max - 2);
|
||||
else if(ftp < 1.9) memset(&leds[3], 0, leds_max - 3);
|
||||
else if(ftp < 2) memset(&leds[4], 0, leds_max - 4);
|
||||
else if(ftp < 2.3) memset(&leds[5], 0, leds_max - 5);
|
||||
else if(ftp < 2.6) memset(&leds[6], 0, leds_max - 6);
|
||||
else if(ftp < 2.9) memset(&leds[7], 0, leds_max - 7);
|
||||
else if(ftp < 3.3) memset(&leds[8], 0, leds_max - 8);
|
||||
else if(ftp < 3.6) memset(&leds[9], 0, leds_max - 9);
|
||||
else if(ftp < 4) memset(&leds[10], 0, leds_max - 10);
|
||||
else if(ftp < 4.3) memset(&leds[11], 0, leds_max - 11);
|
||||
else if(ftp < 4.9) memset(&leds[12], 0, leds_max - 12);
|
||||
else if(ftp < 5) memset(&leds[13], 0, leds_max - 13);
|
||||
else if(ftp < 5.1) memset(&leds[14], 0, leds_max - 14);
|
||||
if (ftp < 1.3)
|
||||
memset(&leds[1], 0, leds_max - 1);
|
||||
else if (ftp < 1.6)
|
||||
memset(&leds[2], 0, leds_max - 2);
|
||||
else if (ftp < 1.9)
|
||||
memset(&leds[3], 0, leds_max - 3);
|
||||
else if (ftp < 2)
|
||||
memset(&leds[4], 0, leds_max - 4);
|
||||
else if (ftp < 2.3)
|
||||
memset(&leds[5], 0, leds_max - 5);
|
||||
else if (ftp < 2.6)
|
||||
memset(&leds[6], 0, leds_max - 6);
|
||||
else if (ftp < 2.9)
|
||||
memset(&leds[7], 0, leds_max - 7);
|
||||
else if (ftp < 3.3)
|
||||
memset(&leds[8], 0, leds_max - 8);
|
||||
else if (ftp < 3.6)
|
||||
memset(&leds[9], 0, leds_max - 9);
|
||||
else if (ftp < 4)
|
||||
memset(&leds[10], 0, leds_max - 10);
|
||||
else if (ftp < 4.3)
|
||||
memset(&leds[11], 0, leds_max - 11);
|
||||
else if (ftp < 4.9)
|
||||
memset(&leds[12], 0, leds_max - 12);
|
||||
else if (ftp < 5)
|
||||
memset(&leds[13], 0, leds_max - 13);
|
||||
else if (ftp < 5.1)
|
||||
memset(&leds[14], 0, leds_max - 14);
|
||||
} else {
|
||||
memset(&leds, 0, leds_max);
|
||||
}
|
||||
for(int i=0;i<leds_max;i++)
|
||||
for (int i = 0; i < leds_max; i++)
|
||||
s += "~" + QString::number(leds[i]);
|
||||
|
||||
writeCharacteristic((uint8_t *)s.toLocal8Bit().data(), s.length(), QStringLiteral("forcing fan ") + s, false, true);
|
||||
// only if the string differs i update the value over bluetooth
|
||||
if (lastValueSent != s)
|
||||
writeCharacteristic((uint8_t *)s.toLocal8Bit().data(), s.length(), QStringLiteral("forcing fan ") + s, false,
|
||||
true);
|
||||
lastValueSent = s;
|
||||
}
|
||||
|
||||
void fitmetria_fanfit::writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log,
|
||||
@@ -176,7 +216,8 @@ void fitmetria_fanfit::writeCharacteristic(uint8_t *data, uint8_t data_len, cons
|
||||
QStringLiteral(" // ") + info;
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
// not necessary, since the communication is one way only. also it could lead to crashes
|
||||
// loop.exec();
|
||||
}
|
||||
|
||||
void fitmetria_fanfit::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
@@ -236,6 +277,8 @@ void fitmetria_fanfit::serviceScanDone(void) {
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
connect(gattCommunicationChannelService, &QLowEnergyService::stateChanged, this, &fitmetria_fanfit::stateChanged);
|
||||
gattCommunicationChannelService->discoverDetails();
|
||||
|
||||
lastValueSent = "";
|
||||
}
|
||||
|
||||
void fitmetria_fanfit::errorService(QLowEnergyService::ServiceError err) {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#ifndef FITMETRIA_FANFIT_H
|
||||
#define FITMETRIA_FANFIT_H
|
||||
|
||||
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QtBluetooth/qlowenergyadvertisingdata.h>
|
||||
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
|
||||
@@ -36,13 +35,14 @@ class fitmetria_fanfit : public bluetoothdevice {
|
||||
|
||||
private:
|
||||
QLowEnergyService *gattCommunicationChannelService = nullptr;
|
||||
//QLowEnergyCharacteristic gattNotifyCharacteristic;
|
||||
// QLowEnergyCharacteristic gattNotifyCharacteristic;
|
||||
QLowEnergyCharacteristic gattWriteCharacteristic;
|
||||
|
||||
void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false,
|
||||
bool wait_for_response = false);
|
||||
|
||||
bluetoothdevice *parentDevice = nullptr;
|
||||
QString lastValueSent = "";
|
||||
|
||||
signals:
|
||||
void disconnected();
|
||||
|
||||
@@ -71,8 +71,8 @@ void fitplusbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QSt
|
||||
|
||||
void fitplusbike::forceResistance(resistance_t requestResistance) {
|
||||
QSettings settings;
|
||||
bool virtufit_etappe = settings.value(QStringLiteral("virtufit_etappe"), false).toBool();
|
||||
if (virtufit_etappe) {
|
||||
bool virtufit_etappe = settings.value(QZSettings::virtufit_etappe, QZSettings::default_virtufit_etappe).toBool();
|
||||
if (virtufit_etappe || merach_MRK) {
|
||||
if (requestResistance == 1) {
|
||||
uint8_t res[] = {0x02, 0x44, 0x05, 0x01, 0xf9, 0xb9, 0x03};
|
||||
writeCharacteristic(res, sizeof(res), "force resistance", false, true);
|
||||
@@ -163,23 +163,25 @@ void fitplusbike::update() {
|
||||
gattNotify1Characteristic.isValid() && initDone) {
|
||||
QSettings settings;
|
||||
update_metrics(true, watts());
|
||||
bool virtufit_etappe = settings.value(QStringLiteral("virtufit_etappe"), false).toBool();
|
||||
bool virtufit_etappe =
|
||||
settings.value(QZSettings::virtufit_etappe, QZSettings::default_virtufit_etappe).toBool();
|
||||
|
||||
if (virtufit_etappe) {
|
||||
if (virtufit_etappe || merach_MRK) {
|
||||
|
||||
} else {
|
||||
|
||||
if (Heart.value() > 0) {
|
||||
int avgP = ((settings.value(QStringLiteral("power_hr_pwr1"), 200).toDouble() *
|
||||
settings.value(QStringLiteral("power_hr_hr2"), 170).toDouble()) -
|
||||
(settings.value(QStringLiteral("power_hr_pwr2"), 230).toDouble() *
|
||||
settings.value(QStringLiteral("power_hr_hr1"), 150).toDouble())) /
|
||||
(settings.value(QStringLiteral("power_hr_hr2"), 170).toDouble() -
|
||||
settings.value(QStringLiteral("power_hr_hr1"), 150).toDouble()) +
|
||||
(Heart.value() * ((settings.value(QStringLiteral("power_hr_pwr1"), 200).toDouble() -
|
||||
settings.value(QStringLiteral("power_hr_pwr2"), 230).toDouble()) /
|
||||
(settings.value(QStringLiteral("power_hr_hr1"), 150).toDouble() -
|
||||
settings.value(QStringLiteral("power_hr_hr2"), 170).toDouble())));
|
||||
int avgP = ((settings.value(QZSettings::power_hr_pwr1, QZSettings::default_power_hr_pwr1).toDouble() *
|
||||
settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble()) -
|
||||
(settings.value(QZSettings::power_hr_pwr2, QZSettings::default_power_hr_pwr2).toDouble() *
|
||||
settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble())) /
|
||||
(settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble() -
|
||||
settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble()) +
|
||||
(Heart.value() *
|
||||
((settings.value(QZSettings::power_hr_pwr1, QZSettings::default_power_hr_pwr1).toDouble() -
|
||||
settings.value(QZSettings::power_hr_pwr2, QZSettings::default_power_hr_pwr2).toDouble()) /
|
||||
(settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble() -
|
||||
settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble())));
|
||||
if (avgP < 50) {
|
||||
avgP = 50;
|
||||
}
|
||||
@@ -248,31 +250,52 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
qDebug() << QStringLiteral(" << ") + newValue.toHex(' ');
|
||||
|
||||
lastPacket = newValue;
|
||||
|
||||
bool virtufit_etappe = settings.value(QStringLiteral("virtufit_etappe"), false).toBool();
|
||||
if (virtufit_etappe) {
|
||||
bool virtufit_etappe = settings.value(QZSettings::virtufit_etappe, QZSettings::default_virtufit_etappe).toBool();
|
||||
if (virtufit_etappe || merach_MRK) {
|
||||
if (newValue.length() != 15 && newValue.length() != 13)
|
||||
return;
|
||||
|
||||
if (newValue.length() == 15) {
|
||||
Resistance = newValue.at(5);
|
||||
m_pelotonResistance = (100 * Resistance.value()) / max_resistance;
|
||||
if(merach_MRK) {
|
||||
// if we change this, also change the wattsFromResistance function. We can create a standard function in order to
|
||||
// have all the costants in one place (I WANT MORE TIME!!!)
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
double cc = -23.50977444;
|
||||
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
double ar = 0.1469553975;
|
||||
double br = -5.841344538;
|
||||
double cr = 97.62165482;
|
||||
|
||||
m_pelotonResistance =
|
||||
(((sqrt(pow(br, 2.0) -
|
||||
4.0 * ar *
|
||||
(cr - (m_watt.value() * 132.0 / (ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) -
|
||||
br) /
|
||||
(2.0 * ar)) *
|
||||
settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
} else {
|
||||
m_pelotonResistance = (100 * Resistance.value()) / max_resistance;
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
Cadence = ((uint8_t)newValue.at(6));
|
||||
m_watt = (double)((((uint8_t)newValue.at(4)) << 8) | ((uint8_t)newValue.at(3))) / 10.0;
|
||||
|
||||
/*if (!settings.value(QStringLiteral("speed_power_based"), false).toBool())
|
||||
/*if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool())
|
||||
Speed = (double)((((uint8_t)newValue.at(4)) << 10) | ((uint8_t)newValue.at(9))) / 100.0;
|
||||
else*/
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
|
||||
} else if (newValue.length() == 13) {
|
||||
|
||||
@@ -291,19 +314,20 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
Resistance = 1;
|
||||
m_pelotonResistance = 1;
|
||||
emit resistanceRead(Resistance.value());
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
Cadence = ((uint8_t)newValue.at(8));
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool())
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool())
|
||||
Speed = (double)((((uint8_t)newValue.at(7)) << 8) | ((uint8_t)newValue.at(6))) / 10.0;
|
||||
else
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
@@ -319,7 +343,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -340,8 +364,9 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -364,9 +389,12 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
void fitplusbike::btinit() {
|
||||
|
||||
QSettings settings;
|
||||
bool virtufit_etappe = settings.value(QStringLiteral("virtufit_etappe"), false).toBool();
|
||||
bool virtufit_etappe = settings.value(QZSettings::virtufit_etappe, QZSettings::default_virtufit_etappe).toBool();
|
||||
|
||||
if (virtufit_etappe) {
|
||||
if (merach_MRK) {
|
||||
uint8_t initData1[] = {0xaa, 0x01, 0x00, 0x01, 0x55};
|
||||
writeCharacteristic(initData1, sizeof(initData1), QStringLiteral("init"), false, true);
|
||||
} else if (virtufit_etappe) {
|
||||
uint8_t initData1[] = {0x02, 0x42, 0x42, 0x03};
|
||||
uint8_t initData2[] = {0x02, 0x41, 0x02, 0x43, 0x03};
|
||||
uint8_t initData3[] = {0x02, 0x41, 0x03, 0x42, 0x03};
|
||||
@@ -448,11 +476,14 @@ void fitplusbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence =
|
||||
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
@@ -518,6 +549,10 @@ void fitplusbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
{
|
||||
bluetoothDevice = device;
|
||||
|
||||
if (device.name().startsWith(QStringLiteral("MRK-"))) {
|
||||
merach_MRK = true;
|
||||
}
|
||||
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, &QLowEnergyController::serviceDiscovered, this, &fitplusbike::serviceDiscovered);
|
||||
connect(m_control, &QLowEnergyController::discoveryFinished, this, &fitplusbike::serviceScanDone);
|
||||
|
||||
@@ -75,6 +75,8 @@ class fitplusbike : public bike {
|
||||
bool noWriteResistance = false;
|
||||
bool noHeartService = false;
|
||||
|
||||
bool merach_MRK = false;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
#endif
|
||||
|
||||
@@ -33,8 +33,8 @@ fitshowtreadmill::fitshowtreadmill(uint32_t pollDeviceTime, bool noConsole, bool
|
||||
refresh = new QTimer(this);
|
||||
initDone = false;
|
||||
QSettings settings;
|
||||
anyrun = settings.value(QStringLiteral("fitshow_anyrun"), false).toBool();
|
||||
truetimer = settings.value(QStringLiteral("fitshow_truetimer"), false).toBool();
|
||||
anyrun = settings.value(QZSettings::fitshow_anyrun, QZSettings::default_fitshow_anyrun).toBool();
|
||||
truetimer = settings.value(QZSettings::fitshow_truetimer, QZSettings::default_fitshow_truetimer).toBool();
|
||||
connect(refresh, &QTimer::timeout, this, &fitshowtreadmill::update);
|
||||
refresh->start(pollDeviceTime);
|
||||
}
|
||||
@@ -156,7 +156,8 @@ void fitshowtreadmill::update() {
|
||||
QSettings settings;
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstInit && searchStopped && !virtualTreadMill) {
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
emit debug(QStringLiteral("creating virtual treadmill interface..."));
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
@@ -171,7 +172,7 @@ void fitshowtreadmill::update() {
|
||||
|
||||
emit debug(QStringLiteral("fitshow Treadmill RSSI ") + QString::number(bluetoothDevice.rssi()));
|
||||
|
||||
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
if (requestSpeed != -1) {
|
||||
if (requestSpeed != currentSpeed().value()) {
|
||||
@@ -295,7 +296,7 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
@@ -425,9 +426,21 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
}
|
||||
|
||||
if (!firstCharacteristicChanged) {
|
||||
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts(
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) +
|
||||
1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
DistanceCalculated +=
|
||||
((speed / 3600.0) /
|
||||
(1000.0 / (lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current elapsed from treadmill: ") + QString::number(seconds_elapsed));
|
||||
@@ -436,7 +449,8 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
emit debug(QStringLiteral("Current heart: ") + QString::number(heart));
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(distance));
|
||||
emit debug(QStringLiteral("Current Distance Calculated: ") + QString::number(DistanceCalculated));
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(kcal));
|
||||
emit debug(QStringLiteral("Current KCal from the Machine: ") + QString::number(kcal));
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
emit debug(QStringLiteral("Current step countl: ") + QString::number(step_count));
|
||||
|
||||
if (m_control->error() != QLowEnergyController::NoError) {
|
||||
@@ -450,21 +464,20 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
lastStop = 0;
|
||||
}
|
||||
|
||||
Speed = speed;
|
||||
if (Speed.value() != speed) {
|
||||
Speed = speed;
|
||||
emit speedChanged(speed);
|
||||
}
|
||||
Inclination = incline;
|
||||
if (Inclination.value() != incline) {
|
||||
Inclination = incline;
|
||||
emit inclinationChanged(0, incline);
|
||||
}
|
||||
|
||||
KCal = kcal;
|
||||
if (truetimer)
|
||||
elapsed = seconds_elapsed;
|
||||
Distance = distance;
|
||||
Distance = DistanceCalculated;
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
@@ -487,7 +500,6 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
lastInclination = incline;
|
||||
}
|
||||
|
||||
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
|
||||
firstCharacteristicChanged = false;
|
||||
if (par != FITSHOW_STATUS_RUNNING) {
|
||||
sendSportData();
|
||||
@@ -563,12 +575,12 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
|
||||
emit debug(QStringLiteral("Current elapsed from treadmill: ") + QString::number(seconds_elapsed));
|
||||
emit debug(QStringLiteral("Current step countl: ") + QString::number(step_count));
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(kcal));
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(distance));
|
||||
KCal = kcal;
|
||||
emit debug(QStringLiteral("Current KCal from the machine: ") + QString::number(kcal));
|
||||
emit debug(QStringLiteral("Current Distance from the machine: ") + QString::number(distance));
|
||||
// KCal = kcal;
|
||||
if (truetimer)
|
||||
elapsed = seconds_elapsed;
|
||||
Distance = distance;
|
||||
// Distance = distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -601,8 +613,8 @@ void fitshowtreadmill::btinit(bool startTape) {
|
||||
0x00 // mode-dependent value (u16le)
|
||||
}; // to verify
|
||||
QSettings settings;
|
||||
int user_id = settings.value(QStringLiteral("fitshow_user_id"), 0x13AA).toInt();
|
||||
uint8_t weight = (uint8_t)(settings.value(QStringLiteral("weight"), 75.0).toFloat() + 0.5);
|
||||
int user_id = settings.value(QZSettings::fitshow_user_id, QZSettings::default_fitshow_user_id).toInt();
|
||||
uint8_t weight = (uint8_t)(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() + 0.5);
|
||||
uint8_t initUserData[] = {FITSHOW_SYS_CONTROL, FITSHOW_CONTROL_USER, 0, 0, 0, 0, 0, 0};
|
||||
initUserData[2] = (user_id >> 0) & 0xFF;
|
||||
initUserData[3] = (user_id >> 8) & 0xFF;
|
||||
|
||||
@@ -182,12 +182,12 @@ void flywheelbike::decodeReceivedData(QByteArray buffer) {
|
||||
void flywheelbike::updateStats() {
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
// calculate the acculamator every time on the current data, in order to avoid holes in peloton or strava
|
||||
// calculate the accumulator every time on the current data, in order to avoid holes in peloton or strava
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
@@ -217,8 +217,8 @@ void flywheelbike::updateStats() {
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", false).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -245,7 +245,7 @@ void flywheelbike::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
// QString heartRateBeltName = settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled"))
|
||||
// QString heartRateBeltName = settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name)
|
||||
// .toString(); // NOTE: clazy-unused-non-trivial-variable
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
@@ -263,7 +263,7 @@ void flywheelbike::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
// double distance = GetDistanceFromPacket(newValue); //Note: clang-analyzer-deadcode.DeadStores
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
#endif
|
||||
|
||||
@@ -272,7 +272,7 @@ void flywheelbike::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
uint16_t speed = ((parsedData->speed >> 8) & 0xFF);
|
||||
speed += ((parsedData->speed & 0xFF) << 8);
|
||||
|
||||
if (zero_fix_filter < settings.value(QStringLiteral("flywheel_filter"), 2).toUInt() &&
|
||||
if (zero_fix_filter < settings.value(QZSettings::flywheel_filter, QZSettings::default_flywheel_filter).toUInt() &&
|
||||
(parsedData->cadence == 0 || speed == 0 || power == 0)) {
|
||||
qDebug() << QStringLiteral("filtering crappy values");
|
||||
zero_fix_filter++;
|
||||
@@ -281,16 +281,16 @@ void flywheelbike::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
|
||||
Resistance = parsedData->brake_level;
|
||||
emit resistanceRead(Resistance.value());
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = parsedData->cadence;
|
||||
}
|
||||
m_watts = power;
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = ((double)speed) / 10.0;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
|
||||
// https://www.facebook.com/groups/149984563348738/permalink/174268944253633/?comment_id=174366620910532&reply_comment_id=174666314213896
|
||||
@@ -366,11 +366,11 @@ void flywheelbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", false).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
|
||||
565
src/ftmsbike.cpp
565
src/ftmsbike.cpp
@@ -161,192 +161,389 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
bool disable_hr_frommachinery = settings.value(QStringLiteral("heart_ignore_builtin"), false).toBool();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
bool disable_hr_frommachinery =
|
||||
settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
bool heart = false;
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
if (characteristic.uuid() != QBluetoothUuid((quint16)0x2AD2)) {
|
||||
return;
|
||||
}
|
||||
qDebug() << characteristic.uuid() << QStringLiteral(" << ") << newValue.toHex(' ');
|
||||
|
||||
lastPacket = newValue;
|
||||
|
||||
union flags {
|
||||
struct {
|
||||
uint16_t moreData : 1;
|
||||
uint16_t avgSpeed : 1;
|
||||
uint16_t instantCadence : 1;
|
||||
uint16_t avgCadence : 1;
|
||||
uint16_t totDistance : 1;
|
||||
uint16_t resistanceLvl : 1;
|
||||
uint16_t instantPower : 1;
|
||||
uint16_t avgPower : 1;
|
||||
uint16_t expEnergy : 1;
|
||||
uint16_t heartRate : 1;
|
||||
uint16_t metabolic : 1;
|
||||
uint16_t elapsedTime : 1;
|
||||
uint16_t remainingTime : 1;
|
||||
uint16_t spare : 3;
|
||||
if (characteristic.uuid() == QBluetoothUuid((quint16)0x2AD2)) {
|
||||
|
||||
union flags {
|
||||
struct {
|
||||
uint16_t moreData : 1;
|
||||
uint16_t avgSpeed : 1;
|
||||
uint16_t instantCadence : 1;
|
||||
uint16_t avgCadence : 1;
|
||||
uint16_t totDistance : 1;
|
||||
uint16_t resistanceLvl : 1;
|
||||
uint16_t instantPower : 1;
|
||||
uint16_t avgPower : 1;
|
||||
uint16_t expEnergy : 1;
|
||||
uint16_t heartRate : 1;
|
||||
uint16_t metabolic : 1;
|
||||
uint16_t elapsedTime : 1;
|
||||
uint16_t remainingTime : 1;
|
||||
uint16_t spare : 3;
|
||||
};
|
||||
|
||||
uint16_t word_flags;
|
||||
};
|
||||
|
||||
uint16_t word_flags;
|
||||
};
|
||||
flags Flags;
|
||||
int index = 0;
|
||||
Flags.word_flags = (newValue.at(1) << 8) | newValue.at(0);
|
||||
index += 2;
|
||||
|
||||
flags Flags;
|
||||
int index = 0;
|
||||
Flags.word_flags = (newValue.at(1) << 8) | newValue.at(0);
|
||||
index += 2;
|
||||
if (!Flags.moreData) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
}
|
||||
|
||||
if (!Flags.moreData) {
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
Speed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
if (Flags.avgSpeed) {
|
||||
double avgSpeed;
|
||||
avgSpeed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Speed: ") + QString::number(avgSpeed));
|
||||
}
|
||||
|
||||
if (Flags.instantCadence) {
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0;
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Cadence: ") + QString::number(Cadence.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgCadence) {
|
||||
double avgCadence;
|
||||
avgCadence = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Cadence: ") + QString::number(avgCadence));
|
||||
}
|
||||
|
||||
if (Flags.totDistance) {
|
||||
Distance = ((double)((((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
(uint32_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint32_t)((uint8_t)newValue.at(index)))) /
|
||||
1000.0;
|
||||
index += 3;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgSpeed) {
|
||||
double avgSpeed;
|
||||
avgSpeed =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Speed: ") + QString::number(avgSpeed));
|
||||
}
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
if (Flags.instantCadence) {
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0;
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Cadence: ") + QString::number(Cadence.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgCadence) {
|
||||
double avgCadence;
|
||||
avgCadence =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Cadence: ") + QString::number(avgCadence));
|
||||
}
|
||||
|
||||
if (Flags.totDistance) {
|
||||
Distance = ((double)((((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
(uint32_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint32_t)((uint8_t)newValue.at(index)))) /
|
||||
1000.0;
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
if (Flags.resistanceLvl) {
|
||||
Resistance =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit resistanceRead(Resistance.value());
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
} else {
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
double cc = -23.50977444;
|
||||
|
||||
double ar = 0.1469553975;
|
||||
double br = -5.841344538;
|
||||
double cr = 97.62165482;
|
||||
|
||||
if (Cadence.value() && m_watt.value()) {
|
||||
m_pelotonResistance =
|
||||
(((sqrt(pow(br, 2.0) - 4.0 * ar *
|
||||
(cr - (m_watt.value() * 132.0 /
|
||||
(ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) -
|
||||
br) /
|
||||
(2.0 * ar)) *
|
||||
settings.value(QStringLiteral("peloton_gain"), 1.0).toDouble()) +
|
||||
settings.value(QStringLiteral("peloton_offset"), 0.0).toDouble();
|
||||
Resistance = m_pelotonResistance;
|
||||
if (Flags.resistanceLvl) {
|
||||
Resistance = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit resistanceRead(Resistance.value());
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
} else {
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
double cc = -23.50977444;
|
||||
|
||||
double ar = 0.1469553975;
|
||||
double br = -5.841344538;
|
||||
double cr = 97.62165482;
|
||||
|
||||
if (Cadence.value() && m_watt.value()) {
|
||||
m_pelotonResistance =
|
||||
(((sqrt(pow(br, 2.0) - 4.0 * ar *
|
||||
(cr - (m_watt.value() * 132.0 /
|
||||
(ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) -
|
||||
br) /
|
||||
(2.0 * ar)) *
|
||||
settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
Resistance = m_pelotonResistance;
|
||||
emit resistanceRead(Resistance.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QStringLiteral("power_sensor_name"), QStringLiteral("Disabled"))
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
}
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgPower) {
|
||||
double avgPower;
|
||||
avgPower =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Watt: ") + QString::number(avgPower));
|
||||
}
|
||||
if (Flags.avgPower && newValue.length() > index + 1) {
|
||||
double avgPower;
|
||||
avgPower = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Watt: ") + QString::number(avgPower));
|
||||
}
|
||||
|
||||
if (Flags.expEnergy && newValue.length() > index + 1) {
|
||||
KCal = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
if (Flags.expEnergy && newValue.length() > index + 1) {
|
||||
KCal = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
|
||||
// energy per hour
|
||||
index += 2;
|
||||
// energy per hour
|
||||
index += 2;
|
||||
|
||||
// energy per minute
|
||||
index += 1;
|
||||
} else {
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() *
|
||||
3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
// energy per minute
|
||||
index += 1;
|
||||
} else {
|
||||
if (watts())
|
||||
KCal += ((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
Flags.heartRate = false;
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
Flags.heartRate = false;
|
||||
}
|
||||
heart = Flags.heartRate;
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags.metabolic) {
|
||||
// todo
|
||||
}
|
||||
if (Flags.metabolic) {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (Flags.elapsedTime) {
|
||||
// todo
|
||||
}
|
||||
if (Flags.elapsedTime) {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (Flags.remainingTime) {
|
||||
// todo
|
||||
if (Flags.remainingTime) {
|
||||
// todo
|
||||
}
|
||||
} else if (characteristic.uuid() == QBluetoothUuid((quint16)0x2ACE)) {
|
||||
union flags {
|
||||
struct {
|
||||
uint32_t moreData : 1;
|
||||
uint32_t avgSpeed : 1;
|
||||
uint32_t totDistance : 1;
|
||||
uint32_t stepCount : 1;
|
||||
uint32_t strideCount : 1;
|
||||
uint32_t elevationGain : 1;
|
||||
uint32_t rampAngle : 1;
|
||||
uint32_t resistanceLvl : 1;
|
||||
uint32_t instantPower : 1;
|
||||
uint32_t avgPower : 1;
|
||||
uint32_t expEnergy : 1;
|
||||
uint32_t heartRate : 1;
|
||||
uint32_t metabolicEq : 1;
|
||||
uint32_t elapsedTime : 1;
|
||||
uint32_t remainingTime : 1;
|
||||
uint32_t movementDirection : 1;
|
||||
uint32_t spare : 8;
|
||||
};
|
||||
|
||||
uint32_t word_flags;
|
||||
};
|
||||
|
||||
flags Flags;
|
||||
int index = 0;
|
||||
Flags.word_flags = (newValue.at(2) << 16) | (newValue.at(1) << 8) | newValue.at(0);
|
||||
index += 3;
|
||||
|
||||
if (!Flags.moreData) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.avgSpeed) {
|
||||
double avgSpeed;
|
||||
avgSpeed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Speed: ") + QString::number(avgSpeed));
|
||||
}
|
||||
|
||||
if (Flags.totDistance) {
|
||||
Distance = ((double)((((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
(uint32_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint32_t)((uint8_t)newValue.at(index)))) /
|
||||
1000.0;
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
if (Flags.stepCount) {
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
Cadence = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
}
|
||||
emit debug(QStringLiteral("Current Cadence: ") + QString::number(Cadence.value()));
|
||||
|
||||
index += 2;
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.strideCount) {
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.elevationGain) {
|
||||
index += 2;
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.rampAngle) {
|
||||
index += 2;
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.resistanceLvl) {
|
||||
Resistance = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit resistanceRead(Resistance.value());
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
} else {
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
double cc = -23.50977444;
|
||||
|
||||
double ar = 0.1469553975;
|
||||
double br = -5.841344538;
|
||||
double cr = 97.62165482;
|
||||
|
||||
if (Cadence.value() && m_watt.value()) {
|
||||
m_pelotonResistance =
|
||||
(((sqrt(pow(br, 2.0) - 4.0 * ar *
|
||||
(cr - (m_watt.value() * 132.0 /
|
||||
(ac * pow(Cadence.value(), 2.0) + bc * Cadence.value() + cc)))) -
|
||||
br) /
|
||||
(2.0 * ar)) *
|
||||
settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
Resistance = m_pelotonResistance;
|
||||
emit resistanceRead(Resistance.value());
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.avgPower && newValue.length() > index + 1) {
|
||||
double avgPower;
|
||||
avgPower = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit debug(QStringLiteral("Current Average Watt: ") + QString::number(avgPower));
|
||||
index += 2;
|
||||
}
|
||||
|
||||
if (Flags.expEnergy && newValue.length() > index + 1) {
|
||||
KCal = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
|
||||
// energy per hour
|
||||
index += 2;
|
||||
|
||||
// energy per minute
|
||||
index += 1;
|
||||
} else {
|
||||
if (watts())
|
||||
KCal += ((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
Flags.heartRate = false;
|
||||
}
|
||||
heart = Flags.heartRate;
|
||||
}
|
||||
|
||||
if (Flags.metabolicEq) {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (Flags.elapsedTime) {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (Flags.remainingTime) {
|
||||
// todo
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Cadence.value() > 0) {
|
||||
@@ -357,7 +554,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled")) &&
|
||||
(!Flags.heartRate || Heart.value() == 0 || disable_hr_frommachinery)) {
|
||||
(!heart || Heart.value() == 0 || disable_hr_frommachinery)) {
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
lockscreen h;
|
||||
@@ -372,8 +569,9 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -390,6 +588,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
}
|
||||
|
||||
void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
QSettings settings;
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyService::ServiceState>();
|
||||
emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state)));
|
||||
|
||||
@@ -422,6 +621,16 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
|
||||
qDebug() << s->serviceUuid() << QStringLiteral("connected!");
|
||||
|
||||
if (settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool()) {
|
||||
QBluetoothUuid ftmsService((quint16)0x1826);
|
||||
if (s->serviceUuid() != ftmsService) {
|
||||
qDebug() << QStringLiteral("hammer racer bike wants to be subscribed only to FTMS service in order "
|
||||
"to send metrics")
|
||||
<< s->serviceUuid();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto characteristics_list = s->characteristics();
|
||||
for (const QLowEnergyCharacteristic &c : qAsConst(characteristics_list)) {
|
||||
qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle();
|
||||
@@ -474,6 +683,11 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
}
|
||||
}
|
||||
|
||||
if (gattFTMSService && gattWriteCharControlPointId.isValid() &&
|
||||
settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool()) {
|
||||
init();
|
||||
}
|
||||
|
||||
// ******************************************* virtual bike init *************************************
|
||||
if (!firstStateChanged && !virtualBike
|
||||
#ifdef Q_OS_IOS
|
||||
@@ -483,11 +697,14 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence =
|
||||
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround =
|
||||
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
@@ -561,11 +778,15 @@ void ftmsbike::serviceScanDone(void) {
|
||||
|
||||
initRequest = false;
|
||||
auto services_list = m_control->services();
|
||||
QBluetoothUuid ftmsService((quint16)0x1826);
|
||||
bool JK_fitness_577 = bluetoothDevice.name().toUpper().startsWith("DHZ-");
|
||||
for (const QBluetoothUuid &s : qAsConst(services_list)) {
|
||||
gattCommunicationChannelService.append(m_control->createServiceObject(s));
|
||||
connect(gattCommunicationChannelService.constLast(), &QLowEnergyService::stateChanged, this,
|
||||
&ftmsbike::stateChanged);
|
||||
gattCommunicationChannelService.constLast()->discoverDetails();
|
||||
if ((JK_fitness_577 && s == ftmsService) || !JK_fitness_577) {
|
||||
gattCommunicationChannelService.append(m_control->createServiceObject(s));
|
||||
connect(gattCommunicationChannelService.constLast(), &QLowEnergyService::stateChanged, this,
|
||||
&ftmsbike::stateChanged);
|
||||
gattCommunicationChannelService.constLast()->discoverDetails();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,14 +802,16 @@ void ftmsbike::error(QLowEnergyController::Error err) {
|
||||
m_control->errorString());
|
||||
}
|
||||
|
||||
resistance_t ftmsbike::pelotonToBikeResistance(int pelotonResistance) { return (pelotonResistance * max_resistance) / 100; }
|
||||
resistance_t ftmsbike::pelotonToBikeResistance(int pelotonResistance) {
|
||||
return (pelotonResistance * max_resistance) / 100;
|
||||
}
|
||||
|
||||
void ftmsbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit debug(QStringLiteral("Found new device: ") + device.name() + QStringLiteral(" (") +
|
||||
device.address().toString() + ')');
|
||||
{
|
||||
bluetoothDevice = device;
|
||||
if(bluetoothDevice.name().toUpper().startsWith("SUITO")) {
|
||||
if (bluetoothDevice.name().toUpper().startsWith("SUITO")) {
|
||||
qDebug() << QStringLiteral("SUITO found");
|
||||
max_resistance = 16;
|
||||
}
|
||||
|
||||
@@ -137,8 +137,9 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
bool disable_hr_frommachinery = settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
|
||||
qDebug() << QStringLiteral(" << ") << characteristic.uuid() << " " << newValue.toHex(' ');
|
||||
|
||||
@@ -172,19 +173,22 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
|
||||
flags Flags;
|
||||
int index = 0;
|
||||
double cadence_divider = 2.0;
|
||||
if (WHIPR)
|
||||
cadence_divider = 1.0;
|
||||
Flags.word_flags = (newValue.at(1) << 8) | newValue.at(0);
|
||||
index += 2;
|
||||
|
||||
if (!Flags.moreData) {
|
||||
|
||||
Cadence = ((uint8_t)newValue.at(index)) / 2;
|
||||
Cadence = ((uint8_t)newValue.at(index)) / cadence_divider;
|
||||
StrokesCount =
|
||||
(((uint16_t)((uint8_t)newValue.at(index + 2)) << 8) | (uint16_t)((uint8_t)newValue.at(index + 1)));
|
||||
|
||||
index += 3;
|
||||
|
||||
/*
|
||||
* the concept 2 sends the pace in 2 frames, so this condition will create a bugus speed
|
||||
* the concept 2 sends the pace in 2 frames, so this condition will create a bogus speed
|
||||
if (!Flags.instantPace) {
|
||||
// eredited by echelon rower, probably we need to change this
|
||||
Speed = (0.37497622 * ((double)Cadence.value())) / 2.0;
|
||||
@@ -196,7 +200,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
if (Flags.avgStroke) {
|
||||
|
||||
double avgStroke;
|
||||
avgStroke = ((double)(uint16_t)((uint8_t)newValue.at(index))) / 2.0;
|
||||
avgStroke = ((double)(uint16_t)((uint8_t)newValue.at(index))) / cadence_divider;
|
||||
index += 1;
|
||||
emit debug(QStringLiteral("Current Average Stroke: ") + QString::number(avgStroke));
|
||||
}
|
||||
@@ -240,7 +244,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
double watt =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
if(!filterWattNull || watt != 0) {
|
||||
if (!filterWattNull || watt != 0) {
|
||||
m_watt = watt;
|
||||
}
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
@@ -263,8 +267,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
}
|
||||
|
||||
if (Flags.expEnergy) {
|
||||
|
||||
if (Flags.expEnergy && index + 1 < newValue.length()) {
|
||||
KCal = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
|
||||
@@ -276,7 +279,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
} else {
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() *
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() *
|
||||
3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
@@ -287,12 +290,12 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate) {
|
||||
if (Flags.heartRate && !disable_hr_frommachinery) {
|
||||
if (index < newValue.length()) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; //NOTE: clang-analyzer-deadcode.DeadStores
|
||||
@@ -341,8 +344,8 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
@@ -454,11 +457,11 @@ void ftmsrower::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
) {
|
||||
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
@@ -540,8 +543,9 @@ void ftmsrower::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
{
|
||||
bluetoothDevice = device;
|
||||
|
||||
if(device.name().trimmed().toUpper().startsWith("WHIPR")) {
|
||||
if (device.name().trimmed().toUpper().startsWith("WHIPR")) {
|
||||
filterWattNull = true;
|
||||
WHIPR = true;
|
||||
qDebug() << "WHIPR found! filtering null wattage";
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ class ftmsrower : public rower {
|
||||
bool noHeartService = false;
|
||||
|
||||
bool filterWattNull = false;
|
||||
bool WHIPR = false;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
|
||||
70
src/gpx.cpp
70
src/gpx.cpp
@@ -9,27 +9,29 @@ gpx::gpx(QObject *parent) : QObject(parent) {}
|
||||
|
||||
QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx) {
|
||||
QSettings settings;
|
||||
bool treadmill_force_speed = settings.value(QStringLiteral("treadmill_force_speed"), false).toBool();
|
||||
const double meter_limit_for_auto_loop = 300;
|
||||
bool treadmill_force_speed =
|
||||
settings.value(QZSettings::treadmill_force_speed, QZSettings::default_treadmill_force_speed).toBool();
|
||||
bool gpx_loop = settings.value(QZSettings::gpx_loop, QZSettings::default_gpx_loop).toBool();
|
||||
QFile input(gpx);
|
||||
input.open(QIODevice::ReadOnly);
|
||||
QDomDocument doc;
|
||||
doc.setContent(&input);
|
||||
QDomNodeList metadata = doc.elementsByTagName(QStringLiteral("metadata"));
|
||||
if(metadata.size()) {
|
||||
if (metadata.size()) {
|
||||
QDomNodeList list = metadata.at(0).childNodes();
|
||||
for(int i=0; i<list.count(); i++) {
|
||||
if(list.at(i).nodeName().toLower() == "video") {
|
||||
for (int i = 0; i < list.count(); i++) {
|
||||
if (list.at(i).nodeName().toLower() == "video") {
|
||||
QString video = list.at(i).toElement().firstChild().nodeValue();
|
||||
if(!video.isEmpty()) {
|
||||
if (!video.isEmpty()) {
|
||||
videoUrl = video;
|
||||
qDebug() << "gpx::videoUrl " << videoUrl;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QDomNodeList points = doc.elementsByTagName(QStringLiteral("trkpt"));
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
QDomNode point = points.item(i);
|
||||
@@ -41,13 +43,21 @@ QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx) {
|
||||
gpx_point g;
|
||||
// 2020-10-10T10:54:45
|
||||
g.time = QDateTime::fromString(time.text(), Qt::ISODate);
|
||||
g.p.setAltitude(ele.text().toFloat());
|
||||
g.p.setLatitude(lat.toFloat());
|
||||
g.p.setLongitude(lon.toFloat());
|
||||
g.p.setAltitude(ele.text().toDouble());
|
||||
g.p.setLatitude(lat.toDouble());
|
||||
g.p.setLongitude(lon.toDouble());
|
||||
this->points.append(g);
|
||||
}
|
||||
|
||||
const uint8_t secondsInclination = 60;
|
||||
if (gpx_loop && this->points.size() > 2 &&
|
||||
this->points.first().p.distanceTo(this->points.last().p) >= meter_limit_for_auto_loop) {
|
||||
for (int i =
|
||||
this->points.size() - 2 /* -2 because otherwise the first point will be the same as the last point */;
|
||||
i >= 0; i--) {
|
||||
this->points.append(this->points.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
QList<gpx_altitude_point_for_treadmill> inclinationList;
|
||||
|
||||
if (this->points.isEmpty()) {
|
||||
@@ -57,19 +67,31 @@ QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx) {
|
||||
gpx_point pP = this->points.constFirst();
|
||||
|
||||
if (treadmill_force_speed) {
|
||||
|
||||
// starting point
|
||||
gpx_altitude_point_for_treadmill g;
|
||||
g.distance = 0;
|
||||
g.inclination = 0;
|
||||
g.elevation = pP.p.altitude();
|
||||
g.latitude = pP.p.latitude();
|
||||
g.longitude = pP.p.longitude();
|
||||
g.seconds = 0;
|
||||
inclinationList.append(g);
|
||||
|
||||
for (int32_t i = 1; i < this->points.count(); i++) {
|
||||
qint64 dT = qAbs(pP.time.secsTo(this->points.at(i).time));
|
||||
if (dT < secondsInclination) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double distance = this->points.at(i).p.distanceTo(pP.p);
|
||||
double elevation = this->points.at(i).p.altitude() - pP.p.altitude();
|
||||
|
||||
if (distance == 0 || dT == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pP = this->points[i];
|
||||
|
||||
gpx_altitude_point_for_treadmill g;
|
||||
g.seconds = dT;
|
||||
g.seconds = this->points.constFirst().time.secsTo(pP.time);
|
||||
g.distance = distance / 1000.0;
|
||||
g.speed = (distance / 1000.0) * (3600 / dT);
|
||||
g.inclination = (elevation / distance) * 100;
|
||||
@@ -85,11 +107,24 @@ QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx) {
|
||||
if (!isnan(this->points.constFirst().p.latitude()) && !isnan(this->points.constFirst().p.longitude()) &&
|
||||
QGeoCoordinate(this->points.first().p.latitude(), this->points.first().p.longitude())
|
||||
.distanceTo(QGeoCoordinate(this->points.constLast().p.latitude(),
|
||||
this->points.constLast().p.longitude())) < 300) {
|
||||
this->points.constLast().p.longitude())) < meter_limit_for_auto_loop) {
|
||||
// to create the circuit
|
||||
this->points.append(this->points.constFirst());
|
||||
this->points.last().time = this->points.at(this->points.count() - 2).time;
|
||||
}
|
||||
|
||||
// starting point
|
||||
gpx_altitude_point_for_treadmill g;
|
||||
g.distance = 0;
|
||||
g.inclination = 0;
|
||||
g.elevation = pP.p.altitude();
|
||||
g.latitude = pP.p.latitude();
|
||||
g.longitude = pP.p.longitude();
|
||||
g.seconds = 0;
|
||||
/*qDebug() << qSetRealNumberPrecision(10) << i << g.distance << g.inclination << g.elevation << g.latitude
|
||||
<< g.longitude << totDistance << pP.time;*/
|
||||
inclinationList.append(g);
|
||||
|
||||
for (int32_t i = 1; i < this->points.count(); i++) {
|
||||
double distance = this->points.at(i).p.distanceTo(pP.p);
|
||||
double elevation = this->points.at(i).p.altitude() - pP.p.altitude();
|
||||
@@ -108,7 +143,8 @@ QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx) {
|
||||
g.latitude = pP.p.latitude();
|
||||
g.longitude = pP.p.longitude();
|
||||
g.seconds = this->points.constFirst().time.secsTo(pP.time);
|
||||
// qDebug() << i << g.distance << g.inclination << g.elevation << g.latitude << g.longitude << totDistance;
|
||||
/*qDebug() << qSetRealNumberPrecision(10) << i << g.distance << g.inclination << g.elevation << g.latitude
|
||||
<< g.longitude << totDistance << pP.time;*/
|
||||
inclinationList.append(g);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
class gpx_altitude_point_for_treadmill {
|
||||
public:
|
||||
uint32_t seconds = 0;
|
||||
uint64_t seconds = 0;
|
||||
float inclination = 0;
|
||||
float elevation = 0;
|
||||
float speed = 0;
|
||||
|
||||
@@ -50,7 +50,10 @@ void heartratebelt::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
|
||||
gattNotifyCharacteristic =
|
||||
gattCommunicationChannelService->characteristic(QBluetoothUuid(QBluetoothUuid::HeartRateMeasurement));
|
||||
Q_ASSERT(gattNotifyCharacteristic.isValid());
|
||||
if(!gattNotifyCharacteristic.isValid()) {
|
||||
qDebug() << "gattNotifyCharacteristic not valid for HR";
|
||||
return;
|
||||
}
|
||||
|
||||
// establish hook into notifications
|
||||
connect(gattCommunicationChannelService, &QLowEnergyService::characteristicChanged, this,
|
||||
@@ -111,8 +114,8 @@ void heartratebelt::error(QLowEnergyController::Error err) {
|
||||
|
||||
void heartratebelt::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
QSettings settings;
|
||||
// QString heartRateBeltName = settings.value(QStringLiteral("heart_rate_belt_name"),
|
||||
// QStringLiteral("Disabled")).toString();//NOTE: clazy-unsed-non-trivial-variable
|
||||
// QString heartRateBeltName = settings.value(QZSettings::heart_rate_belt_name),
|
||||
// QStringLiteral("Disabled")).toString();//NOTE: clazy-unused-non-trivial-variable
|
||||
emit debug(QStringLiteral("Found new device: ") + device.name() + QStringLiteral(" (") +
|
||||
device.address().toString() + ')');
|
||||
// if(device.name().startsWith(heartRateBeltName))
|
||||
|
||||
@@ -19,7 +19,7 @@ homefitnessbuddy::homefitnessbuddy(bluetooth *bl, QObject *parent) : QObject(par
|
||||
retry.setInterval(10s);
|
||||
connect(&retry, &QTimer::timeout, this, &homefitnessbuddy::startEngine);
|
||||
|
||||
if (!settings.value(QStringLiteral("peloton_username"), QStringLiteral("username"))
|
||||
if (!settings.value(QZSettings::peloton_username, QZSettings::default_peloton_username)
|
||||
.toString()
|
||||
.compare(QStringLiteral("username"))) {
|
||||
qDebug() << QStringLiteral("invalid peloton credentials");
|
||||
@@ -192,7 +192,7 @@ void homefitnessbuddy::search_workout_onfinish(QNetworkReply *reply) {
|
||||
|
||||
QSettings settings;
|
||||
// NOTE: clazy-unused-non-trivial-variable
|
||||
// QString difficulty = settings.value(QStringLiteral("peloton_difficulty"), QStringLiteral("lower")).toString();
|
||||
// QString difficulty = settings.value(QZSettings::peloton_difficulty, QZSettings::default_peloton_difficulty).toString();
|
||||
|
||||
trainrows.clear();
|
||||
trainrows = zwiftworkout::load(payload);
|
||||
|
||||
2154
src/homeform.cpp
2154
src/homeform.cpp
File diff suppressed because it is too large
Load Diff
109
src/homeform.h
109
src/homeform.h
@@ -13,6 +13,7 @@
|
||||
#include <QChart>
|
||||
#include <QColor>
|
||||
#include <QGraphicsScene>
|
||||
#include <QMediaPlayer>
|
||||
#include <QNetworkReply>
|
||||
#include <QOAuth2AuthorizationCodeFlow>
|
||||
#include <QQmlApplicationEngine>
|
||||
@@ -34,14 +35,19 @@ class DataObject : public QObject {
|
||||
Q_PROPERTY(int labelFontSize READ labelFontSize WRITE setLabelFontSize NOTIFY labelFontSizeChanged)
|
||||
Q_PROPERTY(bool writable READ writable NOTIFY writableChanged)
|
||||
Q_PROPERTY(bool visibleItem READ visibleItem NOTIFY visibleChanged)
|
||||
Q_PROPERTY(bool largeButton READ largeButton NOTIFY largeButtonChanged)
|
||||
Q_PROPERTY(QString largeButtonColor READ largeButtonColor NOTIFY largeButtonColorChanged)
|
||||
Q_PROPERTY(QString largeButtonLabel READ largeButtonLabel NOTIFY largeButtonLabelChanged)
|
||||
Q_PROPERTY(QString plusName READ plusName NOTIFY plusNameChanged)
|
||||
Q_PROPERTY(QString minusName READ minusName NOTIFY minusNameChanged)
|
||||
Q_PROPERTY(QString identificator READ identificator)
|
||||
Q_PROPERTY(QString identificator READ identificator NOTIFY identificatorChanged)
|
||||
|
||||
public:
|
||||
DataObject(const QString &name, const QString &icon, const QString &value, bool writable, const QString &id,
|
||||
int valueFontSize, int labelFontSize, const QString &valueFontColor = QStringLiteral("white"),
|
||||
const QString &secondLine = QLatin1String(""), const int gridId = 0);
|
||||
const QString &secondLine = QLatin1String(""), const int gridId = 0, const bool largeButton = false,
|
||||
const QString largeButtonLabel = QLatin1String(""),
|
||||
const QString largeButtonColor = QZSettings::default_tile_preset_resistance_1_color);
|
||||
void setName(const QString &value);
|
||||
void setValue(const QString &value);
|
||||
void setSecondLine(const QString &value);
|
||||
@@ -63,6 +69,9 @@ class DataObject : public QObject {
|
||||
QString plusName() { return m_id + QStringLiteral("_plus"); }
|
||||
QString minusName() { return m_id + QStringLiteral("_minus"); }
|
||||
QString identificator() { return m_id; }
|
||||
bool largeButton() { return m_largeButton; }
|
||||
QString largeButtonLabel() { return m_largeButtonLabel; }
|
||||
QString largeButtonColor() { return m_largeButtonColor; }
|
||||
|
||||
QString m_id;
|
||||
QString m_name;
|
||||
@@ -75,6 +84,9 @@ class DataObject : public QObject {
|
||||
int m_labelFontSize;
|
||||
bool m_writable;
|
||||
bool m_visible = true;
|
||||
bool m_largeButton = false;
|
||||
QString m_largeButtonLabel = QLatin1String("");
|
||||
QString m_largeButtonColor = QZSettings::default_tile_preset_resistance_1_color;
|
||||
|
||||
signals:
|
||||
void valueChanged(QString value);
|
||||
@@ -89,6 +101,10 @@ class DataObject : public QObject {
|
||||
void visibleChanged(bool value);
|
||||
void plusNameChanged(QString value);
|
||||
void minusNameChanged(QString value);
|
||||
void identificatorChanged(QString value);
|
||||
void largeButtonChanged(bool value);
|
||||
void largeButtonLabelChanged(QString value);
|
||||
void largeButtonColorChanged(QString value);
|
||||
};
|
||||
|
||||
class homeform : public QObject {
|
||||
@@ -116,8 +132,9 @@ class homeform : public QObject {
|
||||
Q_PROPERTY(bool licensePopupVisible READ licensePopupVisible NOTIFY licensePopupVisibleChanged WRITE
|
||||
setLicensePopupVisible)
|
||||
Q_PROPERTY(bool mapsVisible READ mapsVisible NOTIFY mapsVisibleChanged WRITE setMapsVisible)
|
||||
Q_PROPERTY(bool videoIconVisible READ videoIconVisible NOTIFY videoIconVisibleChanged WRITE setVideoIconVisible)
|
||||
Q_PROPERTY(bool videoVisible READ videoVisible NOTIFY videoVisibleChanged WRITE setVideoVisible)
|
||||
Q_PROPERTY(QUrl videoPath READ videoPath)
|
||||
Q_PROPERTY(QUrl videoPath READ videoPath NOTIFY videoPathChanged)
|
||||
Q_PROPERTY(int videoPosition READ videoPosition NOTIFY videoPositionChanged WRITE setVideoPosition)
|
||||
Q_PROPERTY(double videoRate READ videoRate NOTIFY videoRateChanged WRITE setVideoRate)
|
||||
Q_PROPERTY(double currentSpeed READ currentSpeed NOTIFY currentSpeedChanged)
|
||||
@@ -185,7 +202,7 @@ class homeform : public QObject {
|
||||
QLinearGradient backgroundGradient;
|
||||
double maxWatt = wattMaxChart();
|
||||
QSettings settings;
|
||||
double ftpSetting = settings.value(QStringLiteral("ftp"), 200.0).toDouble();
|
||||
double ftpSetting = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble();
|
||||
/*backgroundGradient.setStart(QPointF(0, 0));
|
||||
backgroundGradient.setFinalStop(QPointF(0, 1));
|
||||
backgroundGradient.setColorAt((maxWatt - (ftpSetting * 0.55)) / maxWatt, QColor("white"));
|
||||
@@ -228,14 +245,14 @@ class homeform : public QObject {
|
||||
/*backgroundGradient.setStart(QPointF(0, 0));
|
||||
backgroundGradient.setFinalStop(QPointF(0, 1));
|
||||
backgroundGradient.setColorAt((220 - (maxHeartRate *
|
||||
settings.value("heart_rate_zone1", 70.0).toDouble() / 100)) / 220, QColor("lightsteelblue"));
|
||||
backgroundGradient.setColorAt((220 - (maxHeartRate *
|
||||
settings.value("heart_rate_zone2", 80.0).toDouble() / 100)) / 220, QColor("green"));
|
||||
backgroundGradient.setColorAt((220 - (maxHeartRate *
|
||||
settings.value("heart_rate_zone3", 90.0).toDouble() / 100)) / 220, QColor("yellow"));
|
||||
backgroundGradient.setColorAt((220 - (maxHeartRate * settings.value("heart_rate_zone4",
|
||||
100.0).toDouble() / 100)) / 220, QColor("orange")); backgroundGradient.setColorAt(0.0,
|
||||
QColor("red"));*/
|
||||
settings.value(QZSettings::heart_rate_zone1, QZSettings::default_heart_rate_zone1).toDouble() /
|
||||
100)) / 220, QColor("lightsteelblue")); backgroundGradient.setColorAt((220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone2, QZSettings::default_heart_rate_zone2).toDouble() /
|
||||
100)) / 220, QColor("green")); backgroundGradient.setColorAt((220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone3, QZSettings::default_heart_rate_zone3).toDouble() /
|
||||
100)) / 220, QColor("yellow")); backgroundGradient.setColorAt((220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone4, QZSettings::default_heart_rate_zone4).toDouble() /
|
||||
100)) / 220, QColor("orange")); backgroundGradient.setColorAt(0.0, QColor("red")); */
|
||||
|
||||
// backgroundGradient.setCoordinateMode(QGradient::ObjectBoundingMode);
|
||||
// chart->setBackgroundBrush(backgroundGradient);
|
||||
@@ -244,23 +261,31 @@ class homeform : public QObject {
|
||||
plotAreaGradient.setStart(QPointF(0, 0));
|
||||
plotAreaGradient.setFinalStop(QPointF(0, 1));
|
||||
plotAreaGradient.setColorAt(
|
||||
(220 -
|
||||
(maxHeartRate * settings.value(QStringLiteral("heart_rate_zone1"), 70.0).toDouble() / 100)) /
|
||||
(220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone1, QZSettings::default_heart_rate_zone1)
|
||||
.toDouble() /
|
||||
100)) /
|
||||
160,
|
||||
QColor(QStringLiteral("lightsteelblue")));
|
||||
plotAreaGradient.setColorAt(
|
||||
(220 -
|
||||
(maxHeartRate * settings.value(QStringLiteral("heart_rate_zone2"), 80.0).toDouble() / 100)) /
|
||||
(220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone2, QZSettings::default_heart_rate_zone2)
|
||||
.toDouble() /
|
||||
100)) /
|
||||
160,
|
||||
QColor(QStringLiteral("green")));
|
||||
plotAreaGradient.setColorAt(
|
||||
(220 -
|
||||
(maxHeartRate * settings.value(QStringLiteral("heart_rate_zone3"), 90.0).toDouble() / 100)) /
|
||||
(220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone3, QZSettings::default_heart_rate_zone3)
|
||||
.toDouble() /
|
||||
100)) /
|
||||
160,
|
||||
QColor(QStringLiteral("yellow")));
|
||||
plotAreaGradient.setColorAt(
|
||||
(220 -
|
||||
(maxHeartRate * settings.value(QStringLiteral("heart_rate_zone4"), 100.0).toDouble() / 100)) /
|
||||
(220 - (maxHeartRate *
|
||||
settings.value(QZSettings::heart_rate_zone4, QZSettings::default_heart_rate_zone4)
|
||||
.toDouble() /
|
||||
100)) /
|
||||
160,
|
||||
QColor(QStringLiteral("orange")));
|
||||
plotAreaGradient.setColorAt(0.0, QColor(QStringLiteral("red")));
|
||||
@@ -287,7 +312,9 @@ class homeform : public QObject {
|
||||
|
||||
Q_INVOKABLE bool autoInclinationEnabled() {
|
||||
QSettings settings;
|
||||
bool virtual_bike = settings.value("virtual_device_force_bike", false).toBool();
|
||||
bool virtual_bike =
|
||||
settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike)
|
||||
.toBool();
|
||||
return bluetoothManager && bluetoothManager->device() &&
|
||||
bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL && !virtual_bike &&
|
||||
bluetoothManager->device()->VirtualDevice() &&
|
||||
@@ -338,7 +365,8 @@ class homeform : public QObject {
|
||||
bool generalPopupVisible();
|
||||
bool licensePopupVisible();
|
||||
bool mapsVisible();
|
||||
bool videoVisible();
|
||||
bool videoIconVisible();
|
||||
bool videoVisible() { return m_VideoVisible; }
|
||||
int videoPosition();
|
||||
double videoRate();
|
||||
double currentSpeed() {
|
||||
@@ -361,8 +389,13 @@ class homeform : public QObject {
|
||||
}
|
||||
}
|
||||
void setLicensePopupVisible(bool value);
|
||||
void setVideoVisible(bool value);
|
||||
void setVideoPosition(int position);
|
||||
void setVideoIconVisible(bool value);
|
||||
void setVideoVisible(bool value) {
|
||||
m_VideoVisible = value;
|
||||
emit videoVisibleChanged(m_VideoVisible);
|
||||
}
|
||||
void setVideoPosition(int position); // on startup
|
||||
void videoSeekPosition(int ms); // in realtime
|
||||
void setVideoRate(double rate);
|
||||
void setMapsVisible(bool value);
|
||||
void setGeneralPopupVisible(bool value);
|
||||
@@ -380,10 +413,10 @@ class homeform : public QObject {
|
||||
QSettings settings;
|
||||
if (bluetoothManager && bluetoothManager->device() &&
|
||||
bluetoothManager->device()->wattsMetric().max() >
|
||||
(settings.value(QStringLiteral("ftp"), 200.0).toDouble() * 2)) {
|
||||
(settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 2)) {
|
||||
return bluetoothManager->device()->wattsMetric().max();
|
||||
} else {
|
||||
return settings.value(QStringLiteral("ftp"), 200.0).toDouble() * 2;
|
||||
return settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble() * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,6 +520,7 @@ class homeform : public QObject {
|
||||
bool m_generalPopupVisible = false;
|
||||
bool m_LicensePopupVisible = false;
|
||||
bool m_MapsVisible = false;
|
||||
bool m_VideoIconVisible = false;
|
||||
bool m_VideoVisible = false;
|
||||
int m_VideoPosition = 0;
|
||||
double m_VideoRate = 1;
|
||||
@@ -531,6 +565,7 @@ class homeform : public QObject {
|
||||
DataObject *resistance;
|
||||
DataObject *watt;
|
||||
DataObject *avgWatt;
|
||||
DataObject *avgWattLap;
|
||||
DataObject *heart;
|
||||
DataObject *fan;
|
||||
DataObject *jouls;
|
||||
@@ -563,6 +598,21 @@ class homeform : public QObject {
|
||||
DataObject *instantaneousStrideLengthCM;
|
||||
DataObject *groundContactMS;
|
||||
DataObject *verticalOscillationMM;
|
||||
DataObject *preset_resistance_1;
|
||||
DataObject *preset_resistance_2;
|
||||
DataObject *preset_resistance_3;
|
||||
DataObject *preset_resistance_4;
|
||||
DataObject *preset_resistance_5;
|
||||
DataObject *preset_speed_1;
|
||||
DataObject *preset_speed_2;
|
||||
DataObject *preset_speed_3;
|
||||
DataObject *preset_speed_4;
|
||||
DataObject *preset_speed_5;
|
||||
DataObject *preset_inclination_1;
|
||||
DataObject *preset_inclination_2;
|
||||
DataObject *preset_inclination_3;
|
||||
DataObject *preset_inclination_4;
|
||||
DataObject *preset_inclination_5;
|
||||
|
||||
QTimer *timer;
|
||||
QTimer *backupTimer;
|
||||
@@ -575,7 +625,6 @@ class homeform : public QObject {
|
||||
const QUrl &clientIdentifierSharedKey);
|
||||
bool strava_upload_file(const QByteArray &data, const QString &remotename);
|
||||
|
||||
const QString cryptoKeySettingsProfilesTag = QStringLiteral("cryptoKeySettingsProfiles");
|
||||
quint64 cryptoKeySettingsProfiles();
|
||||
|
||||
int16_t fanOverride = 0;
|
||||
@@ -592,10 +641,13 @@ class homeform : public QObject {
|
||||
|
||||
#if defined(Q_OS_WIN) || (defined(Q_OS_MAC) && !defined(Q_OS_IOS))
|
||||
QTimer tLicense;
|
||||
QNetworkAccessManager *mgr = nullptr;
|
||||
void licenseRequest();
|
||||
#endif
|
||||
|
||||
QGeoPath gpx_preview;
|
||||
PathController pathController;
|
||||
bool videoMustBeReset = true;
|
||||
|
||||
public slots:
|
||||
void aboutToQuit();
|
||||
@@ -611,6 +663,7 @@ class homeform : public QObject {
|
||||
void Lap();
|
||||
void Minus(const QString &);
|
||||
void Plus(const QString &);
|
||||
void LargeButton(const QString &);
|
||||
void volumeDown();
|
||||
void volumeUp();
|
||||
void keyMediaPrevious();
|
||||
@@ -675,8 +728,10 @@ class homeform : public QObject {
|
||||
void changePelotonProvider(QString value);
|
||||
void generalPopupVisibleChanged(bool value);
|
||||
void licensePopupVisibleChanged(bool value);
|
||||
void videoIconVisibleChanged(bool value);
|
||||
void videoVisibleChanged(bool value);
|
||||
void videoPositionChanged(int value);
|
||||
void videoPathChanged(QUrl value);
|
||||
void videoRateChanged(double value);
|
||||
void currentSpeedChanged(double value);
|
||||
void mapsVisibleChanged(bool value);
|
||||
|
||||
@@ -35,15 +35,31 @@ void horizongr7bike::writeCharacteristic(uint8_t *data, uint8_t data_len, const
|
||||
bool wait_for_response) {
|
||||
QEventLoop loop;
|
||||
QTimer timeout;
|
||||
if (wait_for_response) {
|
||||
connect(gattFTMSService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
} else {
|
||||
connect(gattFTMSService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
}
|
||||
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, QByteArray((const char *)data, data_len));
|
||||
if (gattFTMSService) {
|
||||
if (wait_for_response) {
|
||||
connect(gattFTMSService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
} else {
|
||||
connect(gattFTMSService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
}
|
||||
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, QByteArray((const char *)data, data_len));
|
||||
} else if (customService && customWriteChar.isValid()) {
|
||||
if (wait_for_response) {
|
||||
connect(customService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
} else {
|
||||
connect(customService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
}
|
||||
|
||||
customService->writeCharacteristic(customWriteChar, QByteArray((const char *)data, data_len));
|
||||
} else {
|
||||
qDebug() << "writeCharacteristic error!";
|
||||
return;
|
||||
}
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + QByteArray((const char *)data, data_len).toHex(' ') +
|
||||
@@ -128,18 +144,10 @@ void horizongr7bike::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
|
||||
bool disable_hr_frommachinery = settings.value(QStringLiteral("heart_ignore_builtin"), false).toBool();
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
bool disable_hr_frommachinery = settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
static bool firstPacket = false;
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
if (characteristic.uuid() != QBluetoothUuid((quint16)0x2AD2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
lastPacket = newValue;
|
||||
|
||||
union flags {
|
||||
struct {
|
||||
uint16_t moreData : 1;
|
||||
@@ -162,150 +170,206 @@ void horizongr7bike::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
};
|
||||
|
||||
flags Flags;
|
||||
int index = 0;
|
||||
Flags.word_flags = (newValue.at(1) << 8) | newValue.at(0);
|
||||
index += 2;
|
||||
Flags.heartRate = 0;
|
||||
|
||||
if (!Flags.moreData) {
|
||||
if (!settings.value(QStringLiteral("speed_power_based"), false).toBool()) {
|
||||
Speed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(m_watt.value(), Inclination.value());
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
}
|
||||
emit debug(QStringLiteral(" << ") + characteristic.uuid().toString() + " " + newValue.toHex(' '));
|
||||
|
||||
if (Flags.avgSpeed) {
|
||||
double avgSpeed;
|
||||
avgSpeed =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Speed: ") + QString::number(avgSpeed));
|
||||
}
|
||||
|
||||
if (Flags.instantCadence) {
|
||||
if (settings.value(QStringLiteral("cadence_sensor_name"), QStringLiteral("Disabled"))
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
|
||||
// this bike sent a cadence 1/10 of the real one
|
||||
Cadence = (((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0) *
|
||||
settings.value(QStringLiteral("horizon_gr7_cadence_multiplier"), 1.0).toDouble();
|
||||
}
|
||||
index += 2;
|
||||
if (gattFTMSService == nullptr && characteristic.uuid() == QBluetoothUuid((quint16)0xfff4) &&
|
||||
newValue.length() == 13) {
|
||||
Cadence = newValue.at(11);
|
||||
emit debug(QStringLiteral("Current Cadence: ") + QString::number(Cadence.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgCadence) {
|
||||
double avgCadence;
|
||||
avgCadence =
|
||||
(((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0) *
|
||||
settings.value(QStringLiteral("horizon_gr7_cadence_multiplier"), 1.0).toDouble();
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Cadence: ") + QString::number(avgCadence));
|
||||
}
|
||||
|
||||
if (Flags.totDistance) {
|
||||
// this bike sent the distance but it doesn't send the avg cadence, so the parsing is wrong.
|
||||
// Let's calculate the distance by software
|
||||
/*Distance = ((double)((((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
(uint32_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint32_t)((uint8_t)newValue.at(index)))) /
|
||||
1000.0;*/
|
||||
if (firstPacket)
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
index += 3;
|
||||
} else {
|
||||
if (firstPacket)
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
if (Flags.resistanceLvl) {
|
||||
Resistance =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit resistanceRead(Resistance.value());
|
||||
m_pelotonResistance = bikeResistanceToPeloton(Resistance.value());
|
||||
index += 2;
|
||||
Resistance = newValue.at(12);
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
}
|
||||
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QStringLiteral("power_sensor_name"), QStringLiteral("Disabled"))
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
}
|
||||
if (Heart.value() > 0) {
|
||||
int avgP = ((settings.value(QZSettings::power_hr_pwr1, QZSettings::default_power_hr_pwr1).toDouble() *
|
||||
settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble()) -
|
||||
(settings.value(QZSettings::power_hr_pwr2, QZSettings::default_power_hr_pwr2).toDouble() *
|
||||
settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble())) /
|
||||
(settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble() -
|
||||
settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble()) +
|
||||
(Heart.value() * ((settings.value(QZSettings::power_hr_pwr1, QZSettings::default_power_hr_pwr1).toDouble() -
|
||||
settings.value(QZSettings::power_hr_pwr2, QZSettings::default_power_hr_pwr2).toDouble()) /
|
||||
(settings.value(QZSettings::power_hr_hr1, QZSettings::default_power_hr_hr1).toDouble() -
|
||||
settings.value(QZSettings::power_hr_hr2, QZSettings::default_power_hr_hr2).toDouble())));
|
||||
if (avgP < 50) {
|
||||
avgP = 50;
|
||||
}
|
||||
m_watt = avgP;
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgPower) {
|
||||
double avgPower;
|
||||
avgPower =
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Watt: ") + QString::number(avgPower));
|
||||
}
|
||||
|
||||
if (Flags.expEnergy && newValue.length() > index + 1) {
|
||||
KCal = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
|
||||
// energy per hour
|
||||
index += 2;
|
||||
|
||||
// energy per minute
|
||||
index += 1;
|
||||
} else {
|
||||
if (watts())
|
||||
KCal +=
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QStringLiteral("weight"), 75.0).toFloat() *
|
||||
((((0.048 * ((double)watts()) + 1.19) * settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() *
|
||||
3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = Cadence.value() * settings.value(QZSettings::cadence_sensor_speed_ratio, QZSettings::default_cadence_sensor_speed_ratio).toDouble();
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
return;
|
||||
} else if (characteristic.uuid() == QBluetoothUuid((quint16)0x2AD2)) {
|
||||
|
||||
lastPacket = newValue;
|
||||
|
||||
int index = 0;
|
||||
Flags.word_flags = (newValue.at(1) << 8) | newValue.at(0);
|
||||
index += 2;
|
||||
|
||||
if (!Flags.moreData) {
|
||||
if (!settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
|
||||
Speed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(watts(), Inclination.value(), Speed.value(),fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgSpeed) {
|
||||
double avgSpeed;
|
||||
avgSpeed = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
100.0;
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Speed: ") + QString::number(avgSpeed));
|
||||
}
|
||||
|
||||
if (Flags.instantCadence) {
|
||||
if (settings.value(QZSettings::cadence_sensor_name, QZSettings::default_cadence_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled"))) {
|
||||
|
||||
// this bike sent a cadence 1/10 of the real one
|
||||
Cadence = (((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0) *
|
||||
settings.value(QZSettings::horizon_gr7_cadence_multiplier, QZSettings::default_horizon_gr7_cadence_multiplier).toDouble();
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Cadence: ") + QString::number(Cadence.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgCadence) {
|
||||
double avgCadence;
|
||||
avgCadence = (((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index)))) /
|
||||
2.0) *
|
||||
settings.value(QZSettings::horizon_gr7_cadence_multiplier, QZSettings::default_horizon_gr7_cadence_multiplier).toDouble();
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Cadence: ") + QString::number(avgCadence));
|
||||
}
|
||||
|
||||
if (Flags.totDistance) {
|
||||
// this bike sent the distance but it doesn't send the avg cadence, so the parsing is wrong.
|
||||
// Let's calculate the distance by software
|
||||
/*Distance = ((double)((((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
(uint32_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint32_t)((uint8_t)newValue.at(index)))) /
|
||||
1000.0;*/
|
||||
if (firstPacket)
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
index += 3;
|
||||
} else {
|
||||
if (firstPacket)
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
if (Flags.resistanceLvl) {
|
||||
Resistance = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
emit resistanceRead(Resistance.value());
|
||||
m_pelotonResistance = bikeResistanceToPeloton(Resistance.value());
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
}
|
||||
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")))
|
||||
m_watt = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
}
|
||||
|
||||
if (Flags.avgPower) {
|
||||
double avgPower;
|
||||
avgPower = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Average Watt: ") + QString::number(avgPower));
|
||||
}
|
||||
|
||||
if (Flags.expEnergy && newValue.length() > index + 1) {
|
||||
KCal = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
|
||||
// energy per hour
|
||||
index += 2;
|
||||
|
||||
// energy per minute
|
||||
index += 1;
|
||||
} else {
|
||||
if (watts())
|
||||
KCal += ((((0.048 * ((double)watts()) + 1.19) *
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value("ant_heart", false).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Heart = (uint8_t)KeepAwakeHelper::heart();
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
Flags.heartRate = false;
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
Flags.heartRate = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Flags.metabolic) {
|
||||
// todo
|
||||
}
|
||||
if (Flags.metabolic) {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (Flags.elapsedTime) {
|
||||
// todo
|
||||
}
|
||||
if (Flags.elapsedTime) {
|
||||
// todo
|
||||
}
|
||||
|
||||
if (Flags.remainingTime) {
|
||||
// todo
|
||||
if (Flags.remainingTime) {
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
||||
if (Cadence.value() > 0) {
|
||||
@@ -331,8 +395,8 @@ void horizongr7bike::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
|
||||
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
|
||||
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
|
||||
@@ -350,6 +414,13 @@ void horizongr7bike::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
firstPacket = true;
|
||||
}
|
||||
|
||||
void horizongr7bike::btinit() {
|
||||
if (gattFTMSService == nullptr) {
|
||||
uint8_t write[] = {0x55, 0xaa, 0x00, 0x00, 0x02, 0x16, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x0a};
|
||||
writeCharacteristic(write, sizeof(write), QStringLiteral("init"));
|
||||
}
|
||||
}
|
||||
|
||||
void horizongr7bike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyService::ServiceState>();
|
||||
emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state)));
|
||||
@@ -421,15 +492,22 @@ void horizongr7bike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
}
|
||||
|
||||
QBluetoothUuid _gattWriteCharControlPointId((quint16)0x2AD9);
|
||||
QBluetoothUuid _customWriteChar((quint16)0xFFF3);
|
||||
if (c.properties() & QLowEnergyCharacteristic::Write && c.uuid() == _gattWriteCharControlPointId) {
|
||||
qDebug() << QStringLiteral("FTMS service and Control Point found");
|
||||
gattWriteCharControlPointId = c;
|
||||
gattFTMSService = s;
|
||||
} else if (c.properties() & QLowEnergyCharacteristic::Write && c.uuid() == _customWriteChar) {
|
||||
qDebug() << QStringLiteral("Custom Service found");
|
||||
customWriteChar = c;
|
||||
customService = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
btinit();
|
||||
|
||||
// ******************************************* virtual bike init *************************************
|
||||
if (!firstStateChanged && !virtualBike
|
||||
#ifdef Q_OS_IOS
|
||||
@@ -439,11 +517,11 @@ void horizongr7bike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence = settings.value("bike_cadence_sensor", false).toBool();
|
||||
bool ios_peloton_workaround = settings.value("ios_peloton_workaround", true).toBool();
|
||||
bool cadence = settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
|
||||
bool ios_peloton_workaround = settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
|
||||
if (ios_peloton_workaround && cadence) {
|
||||
qDebug() << "ios_peloton_workaround activated!";
|
||||
h = new lockscreen();
|
||||
|
||||
@@ -47,6 +47,7 @@ class horizongr7bike : public bike {
|
||||
void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false,
|
||||
bool wait_for_response = false);
|
||||
void startDiscover();
|
||||
void btinit();
|
||||
uint16_t watts();
|
||||
void forceResistance(resistance_t requestResistance);
|
||||
|
||||
@@ -55,7 +56,10 @@ class horizongr7bike : public bike {
|
||||
|
||||
QList<QLowEnergyService *> gattCommunicationChannelService;
|
||||
QLowEnergyCharacteristic gattWriteCharControlPointId;
|
||||
QLowEnergyService *gattFTMSService;
|
||||
QLowEnergyService *gattFTMSService = nullptr;
|
||||
|
||||
QLowEnergyService* customService = nullptr;
|
||||
QLowEnergyCharacteristic customWriteChar;
|
||||
|
||||
double bikeResistanceToPeloton(double resistance);
|
||||
const resistance_t max_resistance = 12;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,8 @@ class horizontreadmill : public treadmill {
|
||||
bool connected();
|
||||
void forceSpeed(double requestSpeed);
|
||||
void forceIncline(double requestIncline);
|
||||
double minStepInclination();
|
||||
double minStepSpeed();
|
||||
|
||||
void *VirtualTreadmill();
|
||||
void *VirtualDevice();
|
||||
@@ -78,6 +80,8 @@ class horizontreadmill : public treadmill {
|
||||
double lastInclination = 0;
|
||||
int64_t lastStart = 0;
|
||||
int64_t lastStop = 0;
|
||||
bool horizonPaused = false;
|
||||
double lastHorizonForceSpeed = 0;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
@@ -87,7 +91,71 @@ class horizontreadmill : public treadmill {
|
||||
|
||||
int32_t customRecv = 0;
|
||||
int32_t messageID = 0;
|
||||
int GenerateCRC_CCITT(uint8_t *PUPtr8, int PU16_Count);
|
||||
|
||||
void testProfileCRC();
|
||||
void updateProfileCRC();
|
||||
int GenerateCRC_CCITT(uint8_t *PUPtr8, int PU16_Count, int crcStart = 65535);
|
||||
bool checkIfForceSpeedNeeding(double requestSpeed);
|
||||
|
||||
// profiles
|
||||
uint8_t initData7[20] = {0x55, 0xaa, 0x02, 0x00, 0x01, 0x16, 0xdb, 0x02, 0xed, 0xc2,
|
||||
0x00, 0x47, 0x75, 0x65, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData8[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x05, 0xc2, 0x07};
|
||||
uint8_t initData10[20] = {0x01, 0x01, 0x00, 0xd3, 0x8a, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
uint8_t initData11[20] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
uint8_t initData12[20] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData13[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30,
|
||||
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
uint8_t initData14[1] = {0x30};
|
||||
|
||||
uint8_t initData7_1[20] = {0x55, 0xaa, 0x03, 0x00, 0x01, 0x16, 0xdb, 0x02, 0xae, 0x2a,
|
||||
0x01, 0x41, 0x69, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9_1[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0xc4, 0x07};
|
||||
uint8_t initData10_1[20] = {0x09, 0x1c, 0x00, 0x9f, 0xef, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
|
||||
uint8_t initData7_2[20] = {0x55, 0xaa, 0x04, 0x00, 0x01, 0x16, 0xdb, 0x02, 0xae, 0x2a,
|
||||
0x01, 0x41, 0x69, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9_2[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0xc4, 0x07};
|
||||
uint8_t initData10_2[20] = {0x09, 0x1c, 0x00, 0x9f, 0xef, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
|
||||
uint8_t initData7_3[20] = {0x55, 0xaa, 0x05, 0x00, 0x01, 0x16, 0xdb, 0x02, 0xa9, 0xe7,
|
||||
0x02, 0x4d, 0x65, 0x67, 0x68, 0x61, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9_3[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x06, 0xc5, 0x07};
|
||||
uint8_t initData10_3[20] = {0x0b, 0x0f, 0x00, 0x4b, 0x40, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
|
||||
uint8_t initData7_4[20] = {0x55, 0xaa, 0x06, 0x00, 0x01, 0x16, 0xdb, 0x02, 0xbc, 0x76,
|
||||
0x03, 0x44, 0x61, 0x72, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9_4[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0xca, 0x07};
|
||||
uint8_t initData10_4[20] = {0x05, 0x1c, 0x00, 0x07, 0x25, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
|
||||
uint8_t initData7_5[20] = {0x55, 0xaa, 0x07, 0x00, 0x01, 0x16, 0xdb, 0x02, 0x7d, 0xeb,
|
||||
0x04, 0x41, 0x68, 0x6f, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9_5[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x04, 0xcc, 0x07};
|
||||
uint8_t initData10_5[20] = {0x01, 0x08, 0x00, 0xc2, 0x0f, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
|
||||
uint8_t initData7_6[20] = {0x55, 0xaa, 0x08, 0x00, 0x01, 0x16, 0xdb, 0x02, 0x03, 0x0d,
|
||||
0x05, 0x55, 0x73, 0x65, 0x72, 0x20, 0x35, 0x00, 0x00, 0x00};
|
||||
uint8_t initData9_6[20] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x05, 0xc2, 0x07};
|
||||
uint8_t initData10_6[20] = {0x01, 0x01, 0x00, 0x8e, 0x6a, 0x0c, 0x00, 0x01, 0x01, 0x02,
|
||||
0x23, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30};
|
||||
// profiles end
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
|
||||
@@ -78,15 +78,17 @@ void iconceptbike::update() {
|
||||
|
||||
if (initDone) {
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!virtualBike) {
|
||||
if (!firstStateChanged && !virtualBike) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled = settings.value(QStringLiteral("virtual_device_enabled"), true).toBool();
|
||||
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
if (virtual_device_enabled) {
|
||||
emit debug(QStringLiteral("creating virtual treadmill interface..."));
|
||||
emit debug(QStringLiteral("creating virtual bike interface..."));
|
||||
virtualBike = new virtualbike(this, true);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &iconceptbike::changeInclination);
|
||||
}
|
||||
}
|
||||
firstStateChanged = 1;
|
||||
|
||||
// ********************************************************************************************************
|
||||
|
||||
if (requestResistance != -1) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user