mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
854 Commits
opencv_and
...
build-790
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e00b3e3be3 | ||
|
|
39e8e96935 | ||
|
|
fac7f30554 | ||
|
|
67449c6974 | ||
|
|
2c105055db | ||
|
|
e4b430953a | ||
|
|
c9c9d08b47 | ||
|
|
127ddba542 | ||
|
|
f1261e08a8 | ||
|
|
6102fe6331 | ||
|
|
42b7d359bf | ||
|
|
879242f27b | ||
|
|
f31bfbd796 | ||
|
|
db28e44da9 | ||
|
|
ac1daa3354 | ||
|
|
41efa25200 | ||
|
|
95c3c0d13f | ||
|
|
64ffb70988 | ||
|
|
6554fd7630 | ||
|
|
24f6c3b82f | ||
|
|
85a0ca0004 | ||
|
|
d37978431c | ||
|
|
cd99cc6b43 | ||
|
|
cfea9e9c10 | ||
|
|
1c5ac682b3 | ||
|
|
a5777a533b | ||
|
|
63717e4116 | ||
|
|
bb946ee172 | ||
|
|
2b8f82ea68 | ||
|
|
7bdd6e529a | ||
|
|
8d0565f411 | ||
|
|
cd32a90912 | ||
|
|
61cc94f7a9 | ||
|
|
f62a3278e7 | ||
|
|
8106a216c3 | ||
|
|
e48da60aa7 | ||
|
|
9803458018 | ||
|
|
e37d3ca66e | ||
|
|
0596d05e74 | ||
|
|
961de710b3 | ||
|
|
6cd52efe77 | ||
|
|
8e8942386e | ||
|
|
725b0e8976 | ||
|
|
ff32af5b94 | ||
|
|
641b93ecac | ||
|
|
386d6b9fb0 | ||
|
|
1811fe23e6 | ||
|
|
8fc91f8957 | ||
|
|
f3c82a5d85 | ||
|
|
a82515f85a | ||
|
|
ffd44bcf69 | ||
|
|
69245499fd | ||
|
|
7bb585652d | ||
|
|
717337ecc5 | ||
|
|
de755345df | ||
|
|
f29ee9b8b0 | ||
|
|
f7fd7385f3 | ||
|
|
c774e53c5f | ||
|
|
1a3aca47d3 | ||
|
|
43178057fd | ||
|
|
dbb6b32b03 | ||
|
|
a561219f29 | ||
|
|
ca0398c7d5 | ||
|
|
0af749c9f2 | ||
|
|
d2d661c7fd | ||
|
|
241e34c79e | ||
|
|
c6225db6a4 | ||
|
|
4f855f3d60 | ||
|
|
a55ccb4a97 | ||
|
|
06eccc33f4 | ||
|
|
f080bff4cd | ||
|
|
ecc06675dc | ||
|
|
d5758cf0ed | ||
|
|
d3ebdf252e | ||
|
|
81840bd831 | ||
|
|
1210ec5232 | ||
|
|
cc4a3a6623 | ||
|
|
bc3ec3b39f | ||
|
|
2c7c82bbde | ||
|
|
f18e12e1a7 | ||
|
|
0952d2b8ba | ||
|
|
69e2ed26e2 | ||
|
|
dea1450452 | ||
|
|
7accf7f184 | ||
|
|
d099e58de0 | ||
|
|
0d735c4192 | ||
|
|
03e60d96e7 | ||
|
|
5bfa0bba16 | ||
|
|
ed983a0657 | ||
|
|
8b6a4b3565 | ||
|
|
6d4572a745 | ||
|
|
711afe4b08 | ||
|
|
da43761133 | ||
|
|
977acde7d1 | ||
|
|
1405f3c2c3 | ||
|
|
fb36f7d68d | ||
|
|
381fbf5767 | ||
|
|
e4003ebd81 | ||
|
|
377bd2b667 | ||
|
|
c47df1fe49 | ||
|
|
15cc111dda | ||
|
|
0af6aee343 | ||
|
|
69006d4d18 | ||
|
|
1cd4c801f7 | ||
|
|
3c4f850127 | ||
|
|
9a5b3d279d | ||
|
|
70e82d3aaf | ||
|
|
f48392082f | ||
|
|
df8f409403 | ||
|
|
cb4f20c25e | ||
|
|
cf9321d144 | ||
|
|
89c1439049 | ||
|
|
cf0ea0f84f | ||
|
|
6f211c441c | ||
|
|
0a804c9d6d | ||
|
|
062623580a | ||
|
|
5560c920ec | ||
|
|
ec1c504083 | ||
|
|
27ce527fd6 | ||
|
|
fdc1dc7b9a | ||
|
|
1c76b898e4 | ||
|
|
b2014df95b | ||
|
|
a250ada61e | ||
|
|
dd6c8ca20c | ||
|
|
d8e489f64d | ||
|
|
741fd4367d | ||
|
|
fd2e7ef994 | ||
|
|
a142968feb | ||
|
|
4fd06f91b0 | ||
|
|
e27133fb3a | ||
|
|
9df1c4fdba | ||
|
|
39391c3200 | ||
|
|
70367b8365 | ||
|
|
8e30bde019 | ||
|
|
cb717ff213 | ||
|
|
d723bf054d | ||
|
|
491e900ec3 | ||
|
|
64247cff21 | ||
|
|
38cf417927 | ||
|
|
fcb05aba9f | ||
|
|
9142d8c54d | ||
|
|
8e7a8d14ab | ||
|
|
ca44612565 | ||
|
|
2a40356d4a | ||
|
|
315b750647 | ||
|
|
80ba54294d | ||
|
|
a0218d8d70 | ||
|
|
8d150111aa | ||
|
|
964e49ddb5 | ||
|
|
5f4dd1a1b4 | ||
|
|
b027179dd8 | ||
|
|
5d859024a1 | ||
|
|
99c02259dc | ||
|
|
7048471601 | ||
|
|
9cb1e7a190 | ||
|
|
e1c1ac441a | ||
|
|
0e621aafd5 | ||
|
|
079d406c73 | ||
|
|
9f9ab5c8ca | ||
|
|
a9be8055f2 | ||
|
|
65f49c5c52 | ||
|
|
a429c82f4c | ||
|
|
3288caacb2 | ||
|
|
f4850ff67d | ||
|
|
f644edff24 | ||
|
|
6db6221238 | ||
|
|
db823bd5f4 | ||
|
|
04e2d213da | ||
|
|
64eae75549 | ||
|
|
8118040619 | ||
|
|
c92f546141 | ||
|
|
ddf9bfbef3 | ||
|
|
8d451a4e87 | ||
|
|
c8c4597eb7 | ||
|
|
90a364a8c0 | ||
|
|
22d5bbacbc | ||
|
|
231e01fba8 | ||
|
|
8095fd2314 | ||
|
|
8c796531f6 | ||
|
|
ad28a9e2a5 | ||
|
|
2bcf5f229a | ||
|
|
c53b6e3dab | ||
|
|
471e331641 | ||
|
|
a95d630731 | ||
|
|
eea38d4ecf | ||
|
|
3f7238243f | ||
|
|
a92bfc211b | ||
|
|
a27047156d | ||
|
|
1391930a00 | ||
|
|
6c59f3ee30 | ||
|
|
eeb3a9ce6f | ||
|
|
d1352ae3dd | ||
|
|
053725a577 | ||
|
|
726a2341c0 | ||
|
|
6d7fa3b67e | ||
|
|
4883202703 | ||
|
|
6953f96e59 | ||
|
|
9910234b44 | ||
|
|
3746d89069 | ||
|
|
f2a52e932f | ||
|
|
17fb96dab8 | ||
|
|
e9467724bc | ||
|
|
56b5e759a6 | ||
|
|
f59eb258f1 | ||
|
|
0565a5cf60 | ||
|
|
102e1d6b78 | ||
|
|
7170e28f75 | ||
|
|
3f0441304c | ||
|
|
e76cb14d59 | ||
|
|
339a4279e1 | ||
|
|
02d9b74001 | ||
|
|
a587936f91 | ||
|
|
a84ad5da45 | ||
|
|
959b6db9d0 | ||
|
|
4b289c57f8 | ||
|
|
43f1bda372 | ||
|
|
8ee1046c1d | ||
|
|
60084c7981 | ||
|
|
f23614d793 | ||
|
|
e60c8c2d16 | ||
|
|
e3134a6bd9 | ||
|
|
c42d38d8cc | ||
|
|
f487634923 | ||
|
|
b5bda493cc | ||
|
|
8925d6acf7 | ||
|
|
df88e7e9d6 | ||
|
|
408ee351bb | ||
|
|
2834f6c5d8 | ||
|
|
629aa73f24 | ||
|
|
a5016a66da | ||
|
|
bd54646fe9 | ||
|
|
f6df2a7bf3 | ||
|
|
c32430c12f | ||
|
|
bee144a359 | ||
|
|
dd8fdcd796 | ||
|
|
e45c5e9c13 | ||
|
|
0523fde5bc | ||
|
|
db43605f7a | ||
|
|
ed6553c190 | ||
|
|
b84526ccea | ||
|
|
acd9637c8e | ||
|
|
1235bf7bac | ||
|
|
44a2229e5c | ||
|
|
7d6f1d31a8 | ||
|
|
af608d38c8 | ||
|
|
5b6c231fd1 | ||
|
|
80b09419bd | ||
|
|
aefc83140a | ||
|
|
4c5045315c | ||
|
|
c803d7253e | ||
|
|
b17990e378 | ||
|
|
f184b2b545 | ||
|
|
5aaed653e9 | ||
|
|
69fb207aa2 | ||
|
|
01d5a6d3ba | ||
|
|
ba742c5049 | ||
|
|
4e35e889f8 | ||
|
|
29926b7457 | ||
|
|
ccd2b1399d | ||
|
|
32a2831066 | ||
|
|
aa5f48c33b | ||
|
|
3f15f37f70 | ||
|
|
f79939be2c | ||
|
|
a1983e39f6 | ||
|
|
e50091bd26 | ||
|
|
3e9132e0d5 | ||
|
|
ad678787bb | ||
|
|
4526324dc0 | ||
|
|
e13f8510ba | ||
|
|
1e9b6a4372 | ||
|
|
2ab490e520 | ||
|
|
4a288cb144 | ||
|
|
4aee609476 | ||
|
|
104e11e5b8 | ||
|
|
df06a63678 | ||
|
|
414df68353 | ||
|
|
5ccc8cf77e | ||
|
|
bf2d9e95cb | ||
|
|
4f0ffaae32 | ||
|
|
12e27084be | ||
|
|
c02935f4b1 | ||
|
|
5969c0f37f | ||
|
|
11a1ffdf32 | ||
|
|
be8408e4c7 | ||
|
|
018ea9f080 | ||
|
|
c3b1ae9dcd | ||
|
|
a32645bb15 | ||
|
|
bd9f5ea765 | ||
|
|
8d025a91b2 | ||
|
|
006663b2f1 | ||
|
|
28761764a4 | ||
|
|
b5c47f5aa6 | ||
|
|
2f0806df7b | ||
|
|
6e5ffdccb0 | ||
|
|
5864e81e57 | ||
|
|
fc9fb178a2 | ||
|
|
56fe2c8fcc | ||
|
|
145a919f22 | ||
|
|
b47d62c2ca | ||
|
|
092e318b55 | ||
|
|
35f5065cb2 | ||
|
|
6ac55ee7e3 | ||
|
|
6461d68954 | ||
|
|
3168a84fd6 | ||
|
|
587bd6469d | ||
|
|
a2f6f45aa6 | ||
|
|
bfc301a8b9 | ||
|
|
0774a9e5c5 | ||
|
|
5b9a1d5135 | ||
|
|
c96b591360 | ||
|
|
67a2151b68 | ||
|
|
b565cef516 | ||
|
|
020d732725 | ||
|
|
1677b03113 | ||
|
|
a831add2d5 | ||
|
|
038e597177 | ||
|
|
17ab93720f | ||
|
|
34f28b4b79 | ||
|
|
fa0e981174 | ||
|
|
67de90b88e | ||
|
|
cdd3f53244 | ||
|
|
438c1a5021 | ||
|
|
ba074414b0 | ||
|
|
bc1b2d4d19 | ||
|
|
202d018521 | ||
|
|
b5bb557210 | ||
|
|
3937c9593e | ||
|
|
531ce52643 | ||
|
|
9eb282ec23 | ||
|
|
3753c33581 | ||
|
|
6859b8663f | ||
|
|
e1a5c2a7ea | ||
|
|
23d702ddd4 | ||
|
|
ac0440edaf | ||
|
|
0ed7413254 | ||
|
|
9a2d51a7fd | ||
|
|
bdc64ac13f | ||
|
|
a4a6924f7a | ||
|
|
02ac7fc4c8 | ||
|
|
1bd47aa02c | ||
|
|
974d57d595 | ||
|
|
4a8b37919c | ||
|
|
3780cf7727 | ||
|
|
3ca52a76e9 | ||
|
|
625c73556a | ||
|
|
b022207787 | ||
|
|
4275bb18a0 | ||
|
|
432413526f | ||
|
|
976fb849c7 | ||
|
|
6f861e54c2 | ||
|
|
1d85e90b15 | ||
|
|
6340c7cf82 | ||
|
|
dd2160344e | ||
|
|
abf33019ee | ||
|
|
5f3e1bfd7f | ||
|
|
28c6e035d9 | ||
|
|
84c351e55c | ||
|
|
b2ab7e1328 | ||
|
|
d48ce08102 | ||
|
|
7bfb76a415 | ||
|
|
432e82cc84 | ||
|
|
2c0f32c4c5 | ||
|
|
b6fa09702c | ||
|
|
fac68e0fce | ||
|
|
896d91a3ba | ||
|
|
cf3151465a | ||
|
|
23d450e52b | ||
|
|
eda7e72d04 | ||
|
|
fb4eec9e10 | ||
|
|
4090cd71eb | ||
|
|
616f3e1976 | ||
|
|
fd6acc3626 | ||
|
|
52b0d0c5a1 | ||
|
|
2f61a1addc | ||
|
|
280fa8c0f4 | ||
|
|
83af28ea25 | ||
|
|
7a3bf4a78e | ||
|
|
54cb9c3ef7 | ||
|
|
a96f497633 | ||
|
|
dc07457631 | ||
|
|
30008c7f9b | ||
|
|
3c557067d7 | ||
|
|
0fae320cf5 | ||
|
|
fca9e879f2 | ||
|
|
a0493cac89 | ||
|
|
6096b09f9c | ||
|
|
d1734b96af | ||
|
|
a98772f2fd | ||
|
|
9bebef29cc | ||
|
|
869bc0d720 | ||
|
|
4bc20961b4 | ||
|
|
f9fe046f54 | ||
|
|
92bffc42fa | ||
|
|
d2256f563a | ||
|
|
0cff162fcc | ||
|
|
2c73351f94 | ||
|
|
a5129f6a3a | ||
|
|
ff9c7f746a | ||
|
|
cfd8fa3eeb | ||
|
|
952052ecca | ||
|
|
bf4597f863 | ||
|
|
d973d0dd0c | ||
|
|
e46cd2421d | ||
|
|
2e729f50ec | ||
|
|
e7ae05aa16 | ||
|
|
0dc369cfe6 | ||
|
|
f2bc2a79be | ||
|
|
dbf428d239 | ||
|
|
f6d94ca133 | ||
|
|
53049c073f | ||
|
|
981f9258ca | ||
|
|
b1706eb395 | ||
|
|
44c2e45c1c | ||
|
|
00307eb228 | ||
|
|
2d851913f2 | ||
|
|
e8177e4410 | ||
|
|
b53ff75a5f | ||
|
|
1f444d0dd0 | ||
|
|
3dc61fff85 | ||
|
|
031a24764d | ||
|
|
c4b371eddf | ||
|
|
4a8c42c755 | ||
|
|
8d61e9cfff | ||
|
|
ac6468e507 | ||
|
|
1abe748ad2 | ||
|
|
390d835fba | ||
|
|
51415561a0 | ||
|
|
d7ea35cfef | ||
|
|
8aece1ac6d | ||
|
|
4e6a52030f | ||
|
|
c346aaa055 | ||
|
|
f8341e0d6b | ||
|
|
4d3dd3a86c | ||
|
|
393e7be824 | ||
|
|
2758688f2c | ||
|
|
9628f6be45 | ||
|
|
ed122948cc | ||
|
|
747858b544 | ||
|
|
eeb24b94e0 | ||
|
|
d178317f77 | ||
|
|
2ac2b278b6 | ||
|
|
9a8561b229 | ||
|
|
2c63fd3cc3 | ||
|
|
7f1eb1486a | ||
|
|
6b0a15d19b | ||
|
|
928f9bc613 | ||
|
|
1e3121375f | ||
|
|
12d5794fcd | ||
|
|
6d475919af | ||
|
|
08fa2d8fd9 | ||
|
|
1882862e03 | ||
|
|
bd0dd1c504 | ||
|
|
3874d15a44 | ||
|
|
397379ad9b | ||
|
|
ee1201cc3e | ||
|
|
f968d6628b | ||
|
|
129506f7e5 | ||
|
|
5d4665bfbb | ||
|
|
463c349fc3 | ||
|
|
ab3071aafc | ||
|
|
978ac7ee0f | ||
|
|
8a791c4dde | ||
|
|
77eb4e5b1a | ||
|
|
e3730cf22a | ||
|
|
717d90b98c | ||
|
|
98de190dd5 | ||
|
|
05b4b6ef4d | ||
|
|
c1129bbc0f | ||
|
|
0d48bab025 | ||
|
|
85e9d0f6d1 | ||
|
|
fd2d17879b | ||
|
|
c91248fd52 | ||
|
|
3dfe880b1b | ||
|
|
9065ef0c19 | ||
|
|
4ba070e089 | ||
|
|
fed4c0ca0f | ||
|
|
ab63a29cad | ||
|
|
d8ed66e0ea | ||
|
|
1274112aed | ||
|
|
be13c4176f | ||
|
|
f2cef085d2 | ||
|
|
478a27ed68 | ||
|
|
001c651c58 | ||
|
|
4e6b29d494 | ||
|
|
82ef4e4350 | ||
|
|
bcff966976 | ||
|
|
0931ef6055 | ||
|
|
f204c1bac0 | ||
|
|
93779d04c5 | ||
|
|
7f6e6e2ce0 | ||
|
|
76dc3b38b8 | ||
|
|
48345dc2d2 | ||
|
|
2cb4187951 | ||
|
|
76deb91b0b | ||
|
|
2c71206327 | ||
|
|
e3be4ffa0e | ||
|
|
868d5cc3a8 | ||
|
|
94eb866740 | ||
|
|
f192cf6c75 | ||
|
|
c7efde82b6 | ||
|
|
f32dcb4e1e | ||
|
|
6157bfdcc8 | ||
|
|
9ff91faf00 | ||
|
|
3b88bc2f1f | ||
|
|
4f7cfbbfc1 | ||
|
|
56c112ed4c | ||
|
|
f6b8984575 | ||
|
|
52579e3efc | ||
|
|
fef5d8f4a7 | ||
|
|
6c93d85932 | ||
|
|
b7763154a3 | ||
|
|
fe393bd70d | ||
|
|
3330cc516e | ||
|
|
49e288ec01 | ||
|
|
f1e14d1652 | ||
|
|
2b541c220b | ||
|
|
372d57368c | ||
|
|
21f977ad44 | ||
|
|
a152a0edb9 | ||
|
|
effb3cdfe5 | ||
|
|
e0144445a3 | ||
|
|
8042989552 | ||
|
|
d5ba21da2e | ||
|
|
9d970fbca7 | ||
|
|
600d679e21 | ||
|
|
e860224908 | ||
|
|
081d778405 | ||
|
|
5f18b4daf1 | ||
|
|
7b0065d49a | ||
|
|
65c45d5f3a | ||
|
|
12d3f469de | ||
|
|
707fe68301 | ||
|
|
69511f8c38 | ||
|
|
37ea50fca9 | ||
|
|
c91a24cf23 | ||
|
|
ea48d30f73 | ||
|
|
117c3749ea | ||
|
|
6376e45a13 | ||
|
|
e1068bc1e5 | ||
|
|
c501466372 | ||
|
|
d8dea4f69d | ||
|
|
d44fcd72f7 | ||
|
|
2a19918889 | ||
|
|
420e263a9c | ||
|
|
8a71567a46 | ||
|
|
5a5d9fb4b4 | ||
|
|
f5484768b8 | ||
|
|
5beb890d85 | ||
|
|
edf8a33b87 | ||
|
|
03ddac15da | ||
|
|
e41c60fbeb | ||
|
|
2a435b6b65 | ||
|
|
da31761c35 | ||
|
|
6908bb5d43 | ||
|
|
cf35fccca7 | ||
|
|
d4a8322160 | ||
|
|
dc5f835445 | ||
|
|
85c7a70053 | ||
|
|
b615bd008e | ||
|
|
2ea7337a0f | ||
|
|
34f34312ce | ||
|
|
d4818cc96e | ||
|
|
d801bc7984 | ||
|
|
0efe227318 | ||
|
|
40549f16e8 | ||
|
|
7295ebbf62 | ||
|
|
95db80a249 | ||
|
|
534de944d1 | ||
|
|
d4c9f2b1dd | ||
|
|
ffb2a6e072 | ||
|
|
2dc7ad7fd9 | ||
|
|
35d2eb23aa | ||
|
|
4ab4e17f03 | ||
|
|
acd80b1105 | ||
|
|
01ab6841fc | ||
|
|
e547924350 | ||
|
|
30b0bd51ca | ||
|
|
a3a2bca715 | ||
|
|
bf14b9a8e0 | ||
|
|
a53e7a6e44 | ||
|
|
5eefb07e9e | ||
|
|
55b0689d1d | ||
|
|
beb0a8a80c | ||
|
|
65f57d111a | ||
|
|
7de08d223f | ||
|
|
2b69f2dcd0 | ||
|
|
27da18fed9 | ||
|
|
22fd82cdff | ||
|
|
d9202218dd | ||
|
|
baf9e24640 | ||
|
|
9c0ab9b9f6 | ||
|
|
49e0506815 | ||
|
|
80c528f370 | ||
|
|
54fa926596 | ||
|
|
9f80a7b679 | ||
|
|
7639d19f5e | ||
|
|
9870626695 | ||
|
|
5be30f8f6c | ||
|
|
751f9c4f84 | ||
|
|
dd61b8e2ca | ||
|
|
7dfc994888 | ||
|
|
c662b84bc2 | ||
|
|
7b0ec35303 | ||
|
|
5d235eaab7 | ||
|
|
4e55e2b085 | ||
|
|
e221e4bf7e | ||
|
|
67f0be7c06 | ||
|
|
415025e43d | ||
|
|
ba1854659a | ||
|
|
f622a3e3f7 | ||
|
|
aad888cdab | ||
|
|
b3d45319ae | ||
|
|
0ecff51b14 | ||
|
|
face819d09 | ||
|
|
f8b9c65dab | ||
|
|
0b0081a506 | ||
|
|
94c63f5b77 | ||
|
|
87725cdd1d | ||
|
|
0ddeb747bf | ||
|
|
63a7476d14 | ||
|
|
28701625ac | ||
|
|
e0bc9071c5 | ||
|
|
5bd16f8200 | ||
|
|
d2b844ffb9 | ||
|
|
4018d2947c | ||
|
|
f030c319ac | ||
|
|
ccd4a9896e | ||
|
|
246bf944b2 | ||
|
|
0b7ded9020 | ||
|
|
8bf64c64be | ||
|
|
dbd0227722 | ||
|
|
7e04ab4f92 | ||
|
|
9b7e1d873c | ||
|
|
60ee86476c | ||
|
|
430378b441 | ||
|
|
b9537ff042 | ||
|
|
c0bba3943b | ||
|
|
f729260cbd | ||
|
|
bff00001ab | ||
|
|
91e5a1f14e | ||
|
|
b928be6a33 | ||
|
|
2e0dde6aa4 | ||
|
|
7b8c8ea2b8 | ||
|
|
afd6e5ce26 | ||
|
|
2b8b005762 | ||
|
|
1e639cacd1 | ||
|
|
16611c7e49 | ||
|
|
757febf35a | ||
|
|
2c46293612 | ||
|
|
9a1f9ee980 | ||
|
|
96c80d5bb6 | ||
|
|
98fbd64b89 | ||
|
|
23131f8fb8 | ||
|
|
ec966d6036 | ||
|
|
11f0d6786b | ||
|
|
0f2619233c | ||
|
|
a2ba4cefb5 | ||
|
|
a83e5951aa | ||
|
|
9fe09e7b4b | ||
|
|
0ea2269a67 | ||
|
|
fdba749812 | ||
|
|
ac257b13ed | ||
|
|
0890bf8096 | ||
|
|
ea75a04ad5 | ||
|
|
c3a4238618 | ||
|
|
8017bf64cd | ||
|
|
04633c6296 | ||
|
|
513b59c106 | ||
|
|
04c3cc329c | ||
|
|
e99d7279f4 | ||
|
|
716f917e2a | ||
|
|
0147498c69 | ||
|
|
22b3cef9d2 | ||
|
|
81e4e95272 | ||
|
|
12cc5d0221 | ||
|
|
5b1f85a8cb | ||
|
|
9a9d5fa95e | ||
|
|
8f335894e7 | ||
|
|
3292af09ec | ||
|
|
747acae290 | ||
|
|
04c13f2842 | ||
|
|
b77ed2af6a | ||
|
|
5f186204d6 | ||
|
|
6e9a1ef58a | ||
|
|
180a246902 | ||
|
|
09ab5b142c | ||
|
|
50249a5236 | ||
|
|
4da2ac2fe1 | ||
|
|
ba9253209c | ||
|
|
e8031f5a19 | ||
|
|
b649e5e0f5 | ||
|
|
da9c570029 | ||
|
|
f79eae87a9 | ||
|
|
44beb23212 | ||
|
|
ed35ece439 | ||
|
|
37b513904c | ||
|
|
639397d594 | ||
|
|
de51899ca3 | ||
|
|
ff40d68223 | ||
|
|
1385ea8b88 | ||
|
|
13c88474c6 | ||
|
|
e55577d835 | ||
|
|
6409eab90c | ||
|
|
a314dfe325 | ||
|
|
9b41e2494d | ||
|
|
8672240d72 | ||
|
|
8e83967036 | ||
|
|
8d8b1c141a | ||
|
|
64d40b5d79 | ||
|
|
91811b6b0e | ||
|
|
3e4c898d9f | ||
|
|
67398fce4b | ||
|
|
42c2c52eef | ||
|
|
94cfede7ac | ||
|
|
e8e6068aa2 | ||
|
|
056a903cf2 | ||
|
|
911e66041f | ||
|
|
dbc3c2abf2 | ||
|
|
6f37799e56 | ||
|
|
00bfd0707c | ||
|
|
6bc003db9b | ||
|
|
7b1044a634 | ||
|
|
3686b77405 | ||
|
|
ba3bb3b724 | ||
|
|
495168c204 | ||
|
|
8a9230942b | ||
|
|
100eaccc99 | ||
|
|
24c0df5075 | ||
|
|
9116a46b27 | ||
|
|
64059f2db5 | ||
|
|
2e386ef2a1 | ||
|
|
1ecee4cd3e | ||
|
|
fd523000c0 | ||
|
|
47c272d3d0 | ||
|
|
4eec504016 | ||
|
|
da08e3335e | ||
|
|
0100da67cf | ||
|
|
12e03510f6 | ||
|
|
c8a17ad70e | ||
|
|
9748558f1b | ||
|
|
c807291389 | ||
|
|
29c4e323b0 | ||
|
|
4b1408401f | ||
|
|
39e2ef50cb | ||
|
|
880ac67fbc | ||
|
|
b21695bc14 | ||
|
|
eab058f401 | ||
|
|
58f62303be | ||
|
|
22f935c827 | ||
|
|
dce2ba7067 | ||
|
|
51665c76b4 | ||
|
|
a76cf602d6 | ||
|
|
a3f6bb8d0c | ||
|
|
3f83e4a999 | ||
|
|
14546d4ed3 | ||
|
|
1afff6a79d | ||
|
|
e95bf77c9d | ||
|
|
76ebceccbc | ||
|
|
f54b900c18 | ||
|
|
42e7749856 | ||
|
|
13fb8ae05a | ||
|
|
ee27386d11 | ||
|
|
5073ed766f | ||
|
|
c571a98775 | ||
|
|
1e66fb10b9 | ||
|
|
c9bcfb201e | ||
|
|
d701d01f13 | ||
|
|
f3ae244587 | ||
|
|
755e98d49a | ||
|
|
006c365fee | ||
|
|
2d9110c251 | ||
|
|
30e945f609 | ||
|
|
d3289fa5d1 | ||
|
|
1dd8846c2e | ||
|
|
9a3dc093a2 | ||
|
|
5674c75f4f | ||
|
|
f97e11b1d2 | ||
|
|
68a5bf7f44 | ||
|
|
d644aa4523 | ||
|
|
d04a1a9f01 | ||
|
|
e907170ba2 | ||
|
|
8a55ac1088 | ||
|
|
f83c7565cc | ||
|
|
7de500503e | ||
|
|
61b15254e1 | ||
|
|
2503835a59 | ||
|
|
00ceee2ee0 | ||
|
|
c93cf781fb | ||
|
|
a17da417c2 | ||
|
|
306ce699d4 | ||
|
|
fbbd40a0f8 | ||
|
|
5398b09643 | ||
|
|
94046b18fe | ||
|
|
4e9a03d931 | ||
|
|
2392251992 | ||
|
|
973ff3a586 | ||
|
|
87e5a1905d | ||
|
|
f39ca765d8 | ||
|
|
b33ce3233d | ||
|
|
4209f6f653 | ||
|
|
7d36b4082b | ||
|
|
a3015858f9 | ||
|
|
12515752f6 | ||
|
|
9334c6b472 | ||
|
|
884bea8352 | ||
|
|
8b4c579539 | ||
|
|
c9f3a3a092 | ||
|
|
547bc8a5c9 | ||
|
|
9c600dbc00 | ||
|
|
f29d9fd1e6 | ||
|
|
8d1e98e81f | ||
|
|
94ac9d1bdd | ||
|
|
9e74918b65 | ||
|
|
3be43c14e1 | ||
|
|
e1b951e664 | ||
|
|
53126b16d3 | ||
|
|
0fb8e12d31 | ||
|
|
679300c930 | ||
|
|
4008d588d7 | ||
|
|
fda528babc | ||
|
|
0e9bac6168 | ||
|
|
f8c1330862 | ||
|
|
8e81df67d0 | ||
|
|
1a3c13eac9 | ||
|
|
15b16c7e5c | ||
|
|
b5ceb0a0f1 | ||
|
|
00939c56dd | ||
|
|
5f1ebc439e | ||
|
|
81db615692 | ||
|
|
65d12f00f4 | ||
|
|
adcb87b3c4 | ||
|
|
90900b786a | ||
|
|
b495e833bd | ||
|
|
fb01341dd1 | ||
|
|
867143e43e | ||
|
|
b85d7d72f5 | ||
|
|
32cb3b9e37 | ||
|
|
3ff8938b41 | ||
|
|
5156cb38f0 | ||
|
|
dd4a5dbc54 | ||
|
|
cf37b8705e | ||
|
|
bc8302c761 | ||
|
|
76ecf5c66e | ||
|
|
3693c2d1b2 | ||
|
|
3905bd8ba7 | ||
|
|
92cac7485e | ||
|
|
458c44758e | ||
|
|
be12859343 | ||
|
|
d201919b55 | ||
|
|
138a42c2e6 | ||
|
|
bbe69f3f60 | ||
|
|
b95b3a5018 | ||
|
|
fb0cbb74a5 | ||
|
|
deed6019ab |
552
.github/workflows/main.yml
vendored
552
.github/workflows/main.yml
vendored
@@ -14,8 +14,8 @@ on:
|
||||
branches: [ master, github-workflow-playground ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
# schedule:
|
||||
# - cron: "0 */12 * * *"
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
@@ -70,15 +70,20 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.10.11
|
||||
python-version: 3.7
|
||||
- name: download python and paddleocr
|
||||
run: |
|
||||
python -VV
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade setuptools
|
||||
python -m pip install "protobuf<=3.20.2,>=3.1.0"
|
||||
python -m pip install paddlepaddle==2.5.1
|
||||
python -m pip install paddleocr
|
||||
python -m pip install imutils
|
||||
python -m pip install "Pillow<10.0.0"
|
||||
python -m pip install opencv-python
|
||||
python -m pip install numpy
|
||||
python -m pip install pywin32
|
||||
python -m pip install paddlepaddle-gpu==2.4.2.post117 -f https://www.paddlepaddle.org.cn/whl/windows/mkl/avx/stable.html
|
||||
python -m pip install https://files.pythonhosted.org/packages/03/ac/13fbe0ebf110d57a89f055a292d4fe430fee3fb22c56f8c077e63e0c5a4e/paddlepaddle-2.4.2-cp310-cp310-win_amd64.whl
|
||||
python -m pip install paddleocr>=2.0.1
|
||||
if: matrix.config.python
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
@@ -117,15 +122,20 @@ jobs:
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/master'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
qmake
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
cd ..
|
||||
make -j8
|
||||
cd src/debug
|
||||
mkdir output
|
||||
@@ -133,15 +143,17 @@ jobs:
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libstdc++-6.dll" .
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/*.py .
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
mkdir python
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.10.11\x64 -Destination python -Recurse
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.7.9\x64 -Destination python -Recurse
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
@@ -151,12 +163,6 @@ jobs:
|
||||
- name: Build without python
|
||||
run: |
|
||||
qmake
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
cd ..
|
||||
make -j8
|
||||
cd src/debug
|
||||
mkdir output
|
||||
@@ -164,11 +170,12 @@ jobs:
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/ProgramData/Chocolatey/lib/mingw/tools/install/mingw64/bin/libstdc++-6.dll" .
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
@@ -176,23 +183,79 @@ jobs:
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python == false
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/mingw64/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output release.zip
|
||||
run: Compress-Archive src/debug/output windows-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-binary
|
||||
path: release.zip
|
||||
path: windows-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-binary-no-python
|
||||
path: release.zip
|
||||
path: windows-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
# - name: Exit if not on master branch
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
# run: exit 1
|
||||
|
||||
# - uses: actions/checkout@v3
|
||||
# with:
|
||||
# fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
|
||||
|
||||
# - name: Get previous tag
|
||||
# id: previoustag
|
||||
# uses: 'WyriHaximus/github-action-get-previous-tag@v1'
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# - name: Create Release
|
||||
# if: ${{ ! matrix.config.python }}
|
||||
# id: create_release
|
||||
# uses: actions/create-release@v1
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# with:
|
||||
# tag_name: ${{ steps.previoustag.outputs.tag }}
|
||||
# release_name: Release ${{ steps.previoustag.outputs.tag }}
|
||||
# draft: false
|
||||
# prerelease: false
|
||||
|
||||
# - name: upload windows artifact
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# if: ${{ ! matrix.config.python }}
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
# with:
|
||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
# asset_path: release.zip
|
||||
# asset_name: windows-binary-no-python.zip
|
||||
# asset_content_type: application/zip
|
||||
|
||||
# - name: upload windows artifact
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# if: ${{ matrix.config.python }}
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
# with:
|
||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
# asset_path: release.zip
|
||||
# asset_name: windows-binary.zip
|
||||
# asset_content_type: application/zip
|
||||
|
||||
# window-steam-build:
|
||||
# runs-on: windows-latest
|
||||
#
|
||||
@@ -243,6 +306,7 @@ jobs:
|
||||
# echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
# echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
# echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
# echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
# echo "#define STEAM_STORE" >> secret.h
|
||||
# cd ..
|
||||
# make -j8
|
||||
@@ -273,10 +337,23 @@ jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
linux-x86-build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: release
|
||||
uses: actions/create-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
id: create_release
|
||||
with:
|
||||
draft: false
|
||||
prerelease: false
|
||||
release_name: ${{ steps.version.outputs.version }}
|
||||
tag_name: ${{ github.ref }}
|
||||
body_path: CHANGELOG.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
# - name: Cache Qt Linux Desktop
|
||||
# id: cache-qt-linux-desktop
|
||||
# uses: actions/cache@v1
|
||||
@@ -430,7 +507,7 @@ jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
android-build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
@@ -453,30 +530,12 @@ jobs:
|
||||
sudo apt-get install -y xvfb
|
||||
Xvfb -ac ${{ env.DISPLAY }} -screen 0 1280x780x24 &
|
||||
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: bluetiger9/SmtpClient-for-Qt
|
||||
path: "src/smtpclient/"
|
||||
ref: 3fa4a0fe5797070339422cf18b5e9ed8dcb91f9c
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: cagnulein/qmdnsengine
|
||||
path: "src/qmdnsengine/"
|
||||
ref: "zwift"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: google/googletest
|
||||
path: "tst/googletest/"
|
||||
ref: "release-1.12.1"
|
||||
# This token is provided by Actions, you do not need to create your own token
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
submodules: recursive # or 'true' if you want to check out only immediate submodules
|
||||
|
||||
- name: Install packages required to run QZ inside workflow
|
||||
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
|
||||
@@ -513,7 +572,7 @@ jobs:
|
||||
- name: Install Qt Android
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
version: '5.15.0'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android'
|
||||
@@ -527,6 +586,20 @@ jobs:
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '11'
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/android/5.15.0/jar/*.* ${{ github.workspace }}/output/android/Qt/5.15.0/android/jar/
|
||||
|
||||
- name: download 3rd party files for qthttpserver
|
||||
run: cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
- name: Build qthttpserver
|
||||
run: |
|
||||
cd src/qthttpserver
|
||||
qmake
|
||||
make -j8
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
- name: Set Android NDK 21 && build
|
||||
run: |
|
||||
@@ -538,17 +611,49 @@ jobs:
|
||||
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
|
||||
export ANDROID_NDK="${ANDROID_SDK_ROOT}/ndk-bundle"
|
||||
export ANDROID_NDK_ROOT="${ANDROID_NDK}"
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
echo "#define LICENSE" >> secret.h
|
||||
cd ..
|
||||
|
||||
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK
|
||||
rm -rf /usr/local/lib/android/sdk/ndk/25.1.8937393
|
||||
qmake -spec android-clang 'ANDROID_ABIS=armeabi-v7a arm64-v8a x86 x86_64' 'ANDROID_NDK_ROOT=/usr/local/lib/android/sdk/ndk/21.4.7075529' && make -j4 && make INSTALL_ROOT=${{ github.workspace }}/output/android/ install
|
||||
sed -i '1s|{|{\n "android-extra-libs": "${{ github.workspace }}/android_openssl/no-asm/latest/arm/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm64/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm64/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86_64/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86_64/libssl_1_1.so",|' src/android-qdomyos-zwift-deployment-settings.json
|
||||
cat src/android-qdomyos-zwift-deployment-settings.json
|
||||
|
||||
- name: Build APK (not usable for production due to unpatched QT library)
|
||||
run: cd src; androiddeployqt --input android-qdomyos-zwift-deployment-settings.json --output ${{ github.workspace }}/output/android/ --android-platform android-31 --gradle --aab
|
||||
|
||||
- name: Archive apk binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: fdroid-android-trial
|
||||
path: ${{ github.workspace }}/output/android/build/outputs/apk/debug/
|
||||
|
||||
# - name: Exit if not on master branch
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
# run: exit 1
|
||||
|
||||
# - name: upload windows artifact
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
# with:
|
||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
# asset_path: ${{ github.workspace }}/output/android/build/outputs/apk/debug/android-debug.apk
|
||||
# asset_name: fdroid-android-trial.zip
|
||||
# asset_content_type: application/zip
|
||||
|
||||
ios-build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-12
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
@@ -600,5 +705,342 @@ jobs:
|
||||
run: cp qt-patches/ios/5.15.2/binary/*.* ${{ github.workspace }}/output/ios/Qt/5.15.2/ios/lib/
|
||||
|
||||
- name: Build
|
||||
run: qmake CONFIG+=debug && make -j4
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
qmake CONFIG+=debug && make -j4
|
||||
|
||||
# causes iOS build on Mac to fail
|
||||
# - name: Commit moc files
|
||||
# uses: EndBug/add-and-commit@v9
|
||||
# with:
|
||||
# message: 'moc files added'
|
||||
# add: 'src/moc_*.cpp --force'
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
|
||||
window-msvc2019-build:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {python: true}
|
||||
- {python: false}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: bluetiger9/SmtpClient-for-Qt
|
||||
path: "src/smtpclient/"
|
||||
ref: 3fa4a0fe5797070339422cf18b5e9ed8dcb91f9c
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: cagnulein/qmdnsengine
|
||||
path: "src/qmdnsengine/"
|
||||
ref: "zwift"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: google/googletest
|
||||
path: "tst/googletest/"
|
||||
ref: "release-1.12.1"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout qHttpServer
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: qt-labs/qthttpserver
|
||||
path: "src/qthttpserver"
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: download python and paddleocr
|
||||
run: |
|
||||
python -VV
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade setuptools
|
||||
python -m pip install "protobuf<=3.20.2,>=3.1.0"
|
||||
python -m pip install paddlepaddle==2.5.1
|
||||
python -m pip install paddleocr
|
||||
python -m pip install imutils
|
||||
python -m pip install "Pillow<10.0.0"
|
||||
python -m pip install opencv-python
|
||||
python -m pip install numpy
|
||||
python -m pip install pywin32
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
host: 'windows'
|
||||
modules: 'qtnetworkauth qtcharts'
|
||||
target: "desktop"
|
||||
arch: win64_msvc2019_64
|
||||
dir: "${{github.workspace}}/qt/"
|
||||
install-deps: "true"
|
||||
cache: 'true'
|
||||
cache-key-prefix: 'install-qt-action-windows'
|
||||
|
||||
- name: Install MSVC compiler
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
|
||||
toolset: 14.2
|
||||
arch: x64
|
||||
|
||||
- name: download 3rd party files for qthttpserver
|
||||
run: |
|
||||
cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
- name: Build qthttpserver
|
||||
run: |
|
||||
cd src\qthttpserver
|
||||
qmake
|
||||
nmake
|
||||
nmake install
|
||||
cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/master'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/*.py .
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
mkdir python
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.7.9\x64 -Destination python -Recurse
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Build without python
|
||||
run: |
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python == false
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/msvc2019/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2019-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2019-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-msvc2019-binary
|
||||
path: windows-msvc2019-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-msvc2019-binary-no-python
|
||||
path: windows-msvc2019-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
window-msvc2019-aiserver-build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: bluetiger9/SmtpClient-for-Qt
|
||||
path: "src/smtpclient/"
|
||||
ref: 3fa4a0fe5797070339422cf18b5e9ed8dcb91f9c
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: cagnulein/qmdnsengine
|
||||
path: "src/qmdnsengine/"
|
||||
ref: "zwift"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: google/googletest
|
||||
path: "tst/googletest/"
|
||||
ref: "release-1.12.1"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout qHttpServer
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: qt-labs/qthttpserver
|
||||
path: "src/qthttpserver"
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
host: 'windows'
|
||||
modules: 'qtnetworkauth qtcharts'
|
||||
target: "desktop"
|
||||
arch: win64_msvc2019_64
|
||||
dir: "${{github.workspace}}/qt/"
|
||||
install-deps: "true"
|
||||
cache: 'true'
|
||||
cache-key-prefix: 'install-qt-action-windows'
|
||||
|
||||
- name: Install MSVC compiler
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
|
||||
toolset: 14.2
|
||||
arch: x64
|
||||
|
||||
- name: download 3rd party files for qthttpserver
|
||||
run: |
|
||||
cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
- name: Build qthttpserver
|
||||
run: |
|
||||
cd src\qthttpserver
|
||||
qmake
|
||||
nmake
|
||||
nmake install
|
||||
cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/master'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd src
|
||||
echo "#define AISERVER" >> aiserver.h
|
||||
cd ..
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/zwift-incline-ai-server.py zwift-incline.py
|
||||
cp ../../windows/zwift-incline-climb-portal-ai-server.py zwift-incline-climb-portal.py
|
||||
cp ../../windows/zwift-workout-ai-server.py zwift-workout.py
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/msvc2019/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2019-ai-server-binary.zip
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-msvc2019-ai-server-binary
|
||||
path: windows-msvc2019-ai-server-binary.zip
|
||||
|
||||
upload_to_release:
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-20.04
|
||||
if: github.event_name == 'schedule'
|
||||
needs: [linux-x86-build, window-msvc2019-build, ios-build, window-build, android-build] # Specify the job dependencies
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Update nightly release
|
||||
uses: andelf/nightly-release@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
prerelease: false
|
||||
name: 'QZ nightly build $$'
|
||||
body: |
|
||||
This is a nightly build of QZ.
|
||||
|
||||
You can use this if you want to try new features without waiting for releases.
|
||||
From time to time, in development builds, old difficult-to-reproduce bugs are
|
||||
fixed, but it is also true that in the development process with the introduction
|
||||
of new complex code, the stability of the program may suffer compared to
|
||||
official releases, so **use it with caution**!
|
||||
|
||||
__Please help us improve QZ by reporting any issues you encounter!__ :wink:
|
||||
files: |
|
||||
windows-msvc2019-binary-no-python/*
|
||||
windows-msvc2019-binary/*
|
||||
windows-msvc2019-ai-server-binary/*
|
||||
windows-binary-no-python/*
|
||||
windows-binary/*
|
||||
fdroid-android-trial/*
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -49,3 +49,4 @@ src/inner_templates/googlemaps/cesium-key.js
|
||||
*.autosave
|
||||
.vscode/settings.json
|
||||
/tst/Devices/.vs
|
||||
src/inner_templates/googlemaps/cesium-key.js
|
||||
|
||||
7
.gitmodules
vendored
7
.gitmodules
vendored
@@ -13,3 +13,10 @@
|
||||
path = tst/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
branch = tags/release-1.12.1
|
||||
[submodule "src/qthttpserver"]
|
||||
path = src/qthttpserver
|
||||
url = https://github.com/qt-labs/qthttpserver
|
||||
[submodule "zwiftplay"]
|
||||
path = zwiftplay
|
||||
url = https://github.com/cagnulein/zwiftplay.git
|
||||
branch = lib
|
||||
|
||||
113
README.md
113
README.md
@@ -7,35 +7,100 @@ Zwift bridge for Treadmills and Bike!
|
||||
[<img src="docs/img/app_store.png">](https://apps.apple.com/app/id1543684531?fbclid=IwAR10H6y3mEgwkTlGJON3e8voYOh2wt3kLFOpFzoIXaYZ_N0y0pDvKxHMUaM)
|
||||
<a href="https://www.buymeacoffee.com/cagnulein" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>
|
||||
|
||||

|
||||
|
||||
[](https://www.youtube.com/watch?v=GgG3dMhmo2Y)
|
||||
|
||||

|
||||

|
||||
|
||||
UI on Linux
|
||||
|
||||

|
||||
|
||||
UI on MacOS
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot1.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot2.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot3.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot4.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot5.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
### Features
|
||||
|
||||
1. Domyos compatible
|
||||
2. Toorx TRX Route Key compatible
|
||||
3. Echelon Connect Sport compatible
|
||||
4. Zwift compatible
|
||||
5. Create, load and save train programs
|
||||
6. Measure distance, elevation gain and watts
|
||||
7. Gpx import (with difficulty slider)
|
||||
8. Realtime Charts
|
||||
# UI Features
|
||||
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|Tiles Customization|X|X|X|X|Order and visibility of each tile|
|
||||
|Profiles|X|X|X|X|Different user or different fitness device profiles|
|
||||
|UI Zoom Customization|X|X|X|X||
|
||||
|
||||
# Peloton Features
|
||||
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|Bike metrics on the peloton app|X||X|||
|
||||
|Power zone with auto resistance|X|||||
|
||||
|Peloton real-time resistance conversion|X||X||with the possibility to customize it|
|
||||
|Peloton real-time auto-resistance|X||X||with the possibility to customize it|
|
||||
|Peloton auto speed and auto inclination||X|X||with the possibility to customize it|
|
||||
|
||||
# Heart Rate Features
|
||||
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|Heart Rate support|X|X|X|X|Apple Watch, ANT+ devices and Bluetooth devices|
|
||||
|Heart Rate Zones Customizations|X|X|X|X||
|
||||
|Ability to calculate Wattage from HR and Cadence|X||||for the bikes that doesn't have a power sensor|
|
||||
|
||||
# 3rd Apps Compatibility
|
||||
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|Zwift Compatibility|X|X|X|X||
|
||||
|Zwift Auto resistance|X||X|||
|
||||
|Zwift Auto inclination and speed||X|X||https://www.youtube.com/watch?v=KTQ2n7yeDbo|
|
||||
|Wahoo RGT Compatibility|X|X|X|X||
|
||||
|VzFit Compatibility|X|X|X|X||
|
||||
|Rouvy Compatibility|X|X|X|X||
|
||||
|IFIT app Compatibility|X|||||
|
||||
|Echelon app Compatibility|X|||||
|
||||
|Wahoo Dircon Compatibility|X|X|X|X|in order to send data to Zwift or RGT with Wifi only!|
|
||||
|One device only support for Zwift and Wahoo RGT|X|X|X|X|using Wahoo Dircon https://www.youtube.com/watch?v=gYYUXNWFAok|
|
||||
|BitGym Compatibility|X|X|X|X||
|
||||
|
||||
# Training Program
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|Builtin video support (Kinomap like)|X|X|X|X|Files could be local or on the cloud!|
|
||||
|GPX auto following|X|X|X|X||
|
||||
|2D/3D maps for GPX|X|X|X|X||
|
||||
|ZWO (Zwift workout file) compatibility|X|X|X|X||
|
||||
|XML Workout file compatibility|X|X|X|X||
|
||||
|Auto follow workout based on your heart rate|X|X|X|X||
|
||||
|Random workout|X|X|X|X||
|
||||
|
||||
|
||||
# Statistics
|
||||
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|E-Mail report|X|X|X|X|at the end of the workout|
|
||||
|Strava integration|X|X|X|X|press stop at the end of the workout to auto upload it|
|
||||
|
||||
# Misc
|
||||
|
||||
|Feature|Bike|Treadmill|Elliptical|Rower|Notes|
|
||||
|:---|:---:|:---:|:---:|:---:|---:|
|
||||
|Resistance shifting with bluetooth remote|X||X|||
|
||||
|TTS support|X|X|X|X||
|
||||
|
||||

|
||||
|
||||
### Installation
|
||||
|
||||
You can install on multiple platforms.
|
||||
You can install it on multiple platforms.
|
||||
Read the [installation procedure](docs/10_Installation.md)
|
||||
|
||||
|
||||
@@ -45,7 +110,7 @@ You can run the app on [Macintosh or Linux devices](docs/10_Installation.md). IO
|
||||
|
||||
QDomyos-Zwift works on every [FTMS-compatible application](docs/20_supported_devices_and_applications.md), and virtually any [bluetooth enabled device](docs/20_supported_devices_and_applications.md).
|
||||
|
||||
### No gui version
|
||||
### No GUI version
|
||||
|
||||
run as
|
||||
|
||||
@@ -57,7 +122,7 @@ https://github.com/ProH4Ck/treadmill-bridge
|
||||
|
||||
https://www.livestrong.com/article/422012-what-is-10-degrees-in-incline-on-a-treadmill/
|
||||
|
||||
Icons used in this documentation comes from [flaticon.com](https://www.flaticon.com)
|
||||
Icons used in this documentation come from [flaticon.com](https://www.flaticon.com)
|
||||
|
||||
### Blog
|
||||
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "swiftDebug.h"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -53,12 +53,17 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_accessibility_support_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bluetooth.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bluetooth_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bodymovin_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bootstrap_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_charts.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_charts_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_clipboard_support_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_concurrent.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_concurrent_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_core.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_core_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_datavisualization.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_datavisualization_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_devicediscovery_support_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_edid_support_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri \
|
||||
@@ -71,6 +76,9 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_gui_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_help.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_help_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_httpserver.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_httpserver_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_httpserver.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_location.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_location_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_macextras.pri \
|
||||
@@ -95,6 +103,8 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_positioning_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_positioningquick.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_positioningquick_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_purchasing.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_purchasing_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qml.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qml_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qmldebug_private.pri \
|
||||
@@ -107,6 +117,16 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qmlworkerscript_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3d.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3d_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dassetimport.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dassetimport_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3drender.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3drender_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3druntimerender.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3druntimerender_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dutils.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dutils_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quickcontrols2.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quickcontrols2_private.pri \
|
||||
@@ -120,12 +140,21 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_remoteobjects_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_repparser.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_repparser_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_script.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_script_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scripttools.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scripttools_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scxml.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scxml_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sensors.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sensors_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_serialbus.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_serialbus_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sql.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sql_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_sslserver.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_sslserver_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sslserver.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_svg.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_svg_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_testlib.pri \
|
||||
@@ -136,6 +165,8 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_uiplugin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_uitools.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_uitools_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_virtualkeyboard.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_virtualkeyboard_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_webchannel.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_webchannel_private.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_websockets.pri \
|
||||
@@ -194,15 +225,26 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtiff.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtmedia_audioengine.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtmultimedia_m3u.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtpassthrucanbus.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtpeakcanbus.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtposition_cl.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensorgestures_plugin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensorgestures_shakeplugin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensors_generic.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensors_ios.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qttinycanbus.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtuiotouchplugin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualcanbus.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_hangul.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_openwnn.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_pinyin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_tcime.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_thai.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboardplugin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtwebview_darwin.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qwbmp.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qwebgl.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qwebp.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_scene2d.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/qt_functions.prf \
|
||||
@@ -219,6 +261,9 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/features/default_pre.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/mac/default_pre.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/default_pre.prf \
|
||||
../defaults.pri \
|
||||
../src/purchasing/purchasing.pri \
|
||||
../src/qdomyos-zwift.pri \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/resolve_config.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/resolve_config.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/default_post.prf \
|
||||
@@ -226,6 +271,9 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/default_post.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/macx-ios-clang/features/default_post.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/mac/objective_c.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/qmltypes.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/metatypes.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/ltcg.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/qml_debug.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/mac/mac.prf \
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/bitcode.prf \
|
||||
@@ -264,6 +312,18 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/lib/libqtharfbuzz_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Core_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libqtpcre2_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/mediaservice/libqavfmediaplayer_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_esri_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_itemsoverlay_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_mapbox_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_mapboxgl_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_nokia_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_osm_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/webview/libqtwebview_darwin_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/mediaservice/libqavfcamera_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/mediaservice/libqtmedia_audioengine_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/audio/libqtaudio_coreaudio_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/playlistformats/libqtmultimedia_m3u_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/imageformats/libqgif_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/imageformats/libqicns_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/imageformats/libqico_debug.prl \
|
||||
@@ -288,32 +348,51 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/plugins/qmltooling/libqmldbg_server_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/qmltooling/libqmldbg_tcp_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/bearer/libqgenericbearer_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/texttospeech/libqtexttospeech_speechios_debug.prl \
|
||||
../../Qt/5.15.2/ios/plugins/sqldrivers/libqsqlite_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5HttpServer_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5SslServer_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Charts_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Widgets_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Location_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5PositioningQuick_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5QuickControls2_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Quick_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Multimedia_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5WebView_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Bluetooth_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Xml_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Positioning_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5QmlModels_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Qml_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5NetworkAuth_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5WebSockets_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Network_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5TextToSpeech_debug.prl \
|
||||
../../Qt/5.15.2/ios/lib/libQt5Concurrent_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick.2/libqtquick2plugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Layouts/libqquicklayoutsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/libqtquickcontrols2plugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Material/libqtquickcontrols2materialstyleplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/libqtgraphicaleffectsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Window.2/libwindowplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/settings/libqmlsettingsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQml/libqmlplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Templates.2/libqtquicktemplates2plugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/private/libqtgraphicaleffectsprivate_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQml/Models.2/libmodelsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQml/WorkerScript.2/libworkerscriptplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Dialogs/libdialogplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Window.2/libwindowplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Material/libqtquickcontrols2materialstyleplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtWebView/libdeclarative_webview_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtCharts/libqtchartsqml2_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/folderlistmodel/libqmlfolderlistmodelplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/settings/libqmlsettingsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Dialogs/libdialogplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtPositioning/libdeclarative_positioning_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtLocation/libdeclarative_location_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Dialogs/Private/libdialogsprivateplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls/libqtquickcontrolsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/PrivateWidgets/libwidgetsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Layouts/libqquicklayoutsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/libqtgraphicaleffectsplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/platform/libqtlabsplatformplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtMultimedia/libdeclarative_multimedia_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/private/libqtgraphicaleffectsprivate_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Fusion/libqtquickcontrols2fusionstyleplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Universal/libqtquickcontrols2universalstyleplugin_debug.prl \
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Imagine/libqtquickcontrols2imaginestyleplugin_debug.prl
|
||||
@@ -361,12 +440,17 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_accessibility_support_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bluetooth.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bluetooth_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bodymovin_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_bootstrap_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_charts.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_charts_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_clipboard_support_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_concurrent.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_concurrent_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_core.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_core_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_datavisualization.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_datavisualization_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_devicediscovery_support_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_edid_support_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_eventdispatcher_support_private.pri:
|
||||
@@ -379,6 +463,9 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_gui_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_help.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_help_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_httpserver.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_httpserver_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_httpserver.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_location.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_location_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_macextras.pri:
|
||||
@@ -403,6 +490,8 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_positioning_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_positioningquick.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_positioningquick_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_purchasing.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_purchasing_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qml.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qml_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qmldebug_private.pri:
|
||||
@@ -415,6 +504,16 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qmlworkerscript_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_qtmultimediaquicktools_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3d.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3d_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dassetimport.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dassetimport_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3drender.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3drender_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3druntimerender.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3druntimerender_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dutils.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick3dutils_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quick_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quickcontrols2.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_quickcontrols2_private.pri:
|
||||
@@ -428,12 +527,21 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_remoteobjects_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_repparser.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_repparser_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_script.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_script_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scripttools.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scripttools_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scxml.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_scxml_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sensors.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sensors_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_serialbus.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_serialbus_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sql.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sql_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_sslserver.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules-inst/qt_lib_sslserver_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_sslserver.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_svg.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_svg_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_testlib.pri:
|
||||
@@ -444,6 +552,8 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_uiplugin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_uitools.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_uitools_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_virtualkeyboard.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_virtualkeyboard_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_webchannel.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_webchannel_private.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_lib_websockets.pri:
|
||||
@@ -502,15 +612,26 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtiff.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtmedia_audioengine.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtmultimedia_m3u.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtpassthrucanbus.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtpeakcanbus.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtposition_cl.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtposition_positionpoll.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensorgestures_plugin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensorgestures_shakeplugin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensors_generic.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtsensors_ios.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qttinycanbus.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtuiotouchplugin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualcanbus.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_hangul.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_openwnn.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_pinyin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_tcime.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboard_thai.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtvirtualkeyboardplugin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qtwebview_darwin.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qwbmp.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qwebgl.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_qwebp.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/modules/qt_plugin_scene2d.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/qt_functions.prf:
|
||||
@@ -527,6 +648,9 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/features/default_pre.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/mac/default_pre.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/default_pre.prf:
|
||||
../defaults.pri:
|
||||
../src/purchasing/purchasing.pri:
|
||||
../src/qdomyos-zwift.pri:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/resolve_config.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/resolve_config.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/default_post.prf:
|
||||
@@ -534,6 +658,9 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/default_post.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/macx-ios-clang/features/default_post.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/mac/objective_c.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/qmltypes.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/metatypes.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/ltcg.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/qml_debug.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/mac/mac.prf:
|
||||
../../Qt/5.15.2/ios/mkspecs/features/uikit/bitcode.prf:
|
||||
@@ -572,6 +699,18 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/lib/libqtharfbuzz_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Core_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libqtpcre2_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/mediaservice/libqavfmediaplayer_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_esri_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_itemsoverlay_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_mapbox_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_mapboxgl_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_nokia_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/geoservices/libqtgeoservices_osm_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/webview/libqtwebview_darwin_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/mediaservice/libqavfcamera_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/mediaservice/libqtmedia_audioengine_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/audio/libqtaudio_coreaudio_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/playlistformats/libqtmultimedia_m3u_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/imageformats/libqgif_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/imageformats/libqicns_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/imageformats/libqico_debug.prl:
|
||||
@@ -596,32 +735,51 @@ qdomyoszwift.xcodeproj/project.pbxproj: ../src/qdomyos-zwift.pro ../../Qt/5.15.2
|
||||
../../Qt/5.15.2/ios/plugins/qmltooling/libqmldbg_server_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/qmltooling/libqmldbg_tcp_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/bearer/libqgenericbearer_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/texttospeech/libqtexttospeech_speechios_debug.prl:
|
||||
../../Qt/5.15.2/ios/plugins/sqldrivers/libqsqlite_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5HttpServer_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5SslServer_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Charts_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Widgets_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Location_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5PositioningQuick_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5QuickControls2_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Quick_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Multimedia_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5WebView_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Bluetooth_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Xml_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Positioning_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5QmlModels_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Qml_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5NetworkAuth_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5WebSockets_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Network_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5TextToSpeech_debug.prl:
|
||||
../../Qt/5.15.2/ios/lib/libQt5Concurrent_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick.2/libqtquick2plugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Layouts/libqquicklayoutsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/libqtquickcontrols2plugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Material/libqtquickcontrols2materialstyleplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/libqtgraphicaleffectsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Window.2/libwindowplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/settings/libqmlsettingsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQml/libqmlplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Templates.2/libqtquicktemplates2plugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/private/libqtgraphicaleffectsprivate_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQml/Models.2/libmodelsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQml/WorkerScript.2/libworkerscriptplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Dialogs/libdialogplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Window.2/libwindowplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Material/libqtquickcontrols2materialstyleplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtWebView/libdeclarative_webview_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtCharts/libqtchartsqml2_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/folderlistmodel/libqmlfolderlistmodelplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/settings/libqmlsettingsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Dialogs/libdialogplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtPositioning/libdeclarative_positioning_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtLocation/libdeclarative_location_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Dialogs/Private/libdialogsprivateplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls/libqtquickcontrolsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/PrivateWidgets/libwidgetsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Layouts/libqquicklayoutsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/libqtgraphicaleffectsplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/Qt/labs/platform/libqtlabsplatformplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtMultimedia/libdeclarative_multimedia_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtGraphicalEffects/private/libqtgraphicaleffectsprivate_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Fusion/libqtquickcontrols2fusionstyleplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Universal/libqtquickcontrols2universalstyleplugin_debug.prl:
|
||||
../../Qt/5.15.2/ios/qml/QtQuick/Controls.2/Imagine/libqtquickcontrols2imaginestyleplugin_debug.prl:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -104,6 +104,9 @@ extension MainController: WorkoutTrackingDelegate {
|
||||
"\(heartRate)" as AnyObject])
|
||||
WorkoutTracking.distance = WatchKitConnection.distance
|
||||
WorkoutTracking.kcal = WatchKitConnection.kcal
|
||||
WorkoutTracking.speed = WatchKitConnection.speed
|
||||
WorkoutTracking.power = WatchKitConnection.power
|
||||
WorkoutTracking.cadence = WatchKitConnection.cadence
|
||||
|
||||
if Locale.current.measurementSystem != "Metric" {
|
||||
self.distanceLabel.setText("Distance \(String(format:"%.2f", WorkoutTracking.distance))")
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>CA92.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -24,6 +24,9 @@ class WatchKitConnection: NSObject {
|
||||
public static var distance = 0.0
|
||||
public static var kcal = 0.0
|
||||
public static var stepCadence = 0
|
||||
public static var speed = 0.0
|
||||
public static var cadence = 0.0
|
||||
public static var power = 0.0
|
||||
weak var delegate: WatchKitConnectionDelegate?
|
||||
|
||||
private override init() {
|
||||
@@ -66,6 +69,13 @@ extension WatchKitConnection: WatchKitConnectionProtocol {
|
||||
WatchKitConnection.distance = dDistance
|
||||
let dKcal = Double(result["kcal"] as! Double)
|
||||
WatchKitConnection.kcal = dKcal
|
||||
|
||||
let dSpeed = Double(result["speed"] as! Double)
|
||||
WatchKitConnection.speed = dSpeed
|
||||
let dPower = Double(result["power"] as! Double)
|
||||
WatchKitConnection.power = dPower
|
||||
let dCadence = Double(result["cadence"] as! Double)
|
||||
WatchKitConnection.cadence = dCadence
|
||||
}, errorHandler: { (error) in
|
||||
print(error)
|
||||
})
|
||||
|
||||
@@ -31,6 +31,10 @@ class WorkoutTracking: NSObject {
|
||||
public static var cadenceTimeStamp = NSDate().timeIntervalSince1970
|
||||
public static var cadenceLastSteps = Double()
|
||||
public static var cadenceSteps = 0
|
||||
public static var speed = Double()
|
||||
public static var power = Double()
|
||||
public static var cadence = Double()
|
||||
public static var lastDateMetric = Date()
|
||||
var sport: Int = 0
|
||||
let healthStore = HKHealthStore()
|
||||
let configuration = HKWorkoutConfiguration()
|
||||
@@ -146,14 +150,37 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
|
||||
let infoToShare = Set([
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
var infoToShare: Set<HKSampleType> = []
|
||||
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
infoToShare = Set([
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.quantityType(forIdentifier: .cyclingPower)!,
|
||||
HKSampleType.quantityType(forIdentifier: .cyclingSpeed)!,
|
||||
HKSampleType.quantityType(forIdentifier: .cyclingCadence)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningPower)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningSpeed)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningStrideLength)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningVerticalOscillation)!,
|
||||
HKSampleType.quantityType(forIdentifier: .walkingSpeed)!,
|
||||
HKSampleType.quantityType(forIdentifier: .walkingStepLength)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
infoToShare = Set([
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
}
|
||||
|
||||
HKHealthStore().requestAuthorization(toShare: infoToShare, read: infoToRead) { (success, error) in
|
||||
if success {
|
||||
@@ -168,6 +195,7 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
}
|
||||
|
||||
func startWorkOut() {
|
||||
WorkoutTracking.lastDateMetric = Date()
|
||||
print("Start workout")
|
||||
configWorkout()
|
||||
workoutSession.startActivity(with: Date())
|
||||
@@ -312,6 +340,135 @@ extension WorkoutTracking: HKLiveWorkoutBuilderDelegate {
|
||||
handleSendStatisticsData(statistics)
|
||||
}
|
||||
}
|
||||
|
||||
if(sport == 0) {
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
let wattPerInterval = HKQuantity(unit: HKUnit.watt(),
|
||||
doubleValue: WorkoutTracking.power)
|
||||
|
||||
if(WorkoutTracking.lastDateMetric.distance(to: Date()) < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
guard let powerType = HKQuantityType.quantityType(
|
||||
forIdentifier: .cyclingPower) else {
|
||||
return
|
||||
}
|
||||
let wattPerIntervalSample = HKQuantitySample(type: powerType,
|
||||
quantity: wattPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([wattPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
let cadencePerInterval = HKQuantity(unit: HKUnit.count().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.cadence / 60.0)
|
||||
|
||||
guard let cadenceType = HKQuantityType.quantityType(
|
||||
forIdentifier: .cyclingCadence) else {
|
||||
return
|
||||
}
|
||||
let cadencePerIntervalSample = HKQuantitySample(type: cadenceType,
|
||||
quantity: cadencePerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([cadencePerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
let speedPerInterval = HKQuantity(unit: HKUnit.meter().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.speed * 0.277778)
|
||||
|
||||
guard let speedType = HKQuantityType.quantityType(
|
||||
forIdentifier: .cyclingSpeed) else {
|
||||
return
|
||||
}
|
||||
let speedPerIntervalSample = HKQuantitySample(type: speedType,
|
||||
quantity: speedPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([speedPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
} else if(sport == 1) {
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
let wattPerInterval = HKQuantity(unit: HKUnit.watt(),
|
||||
doubleValue: WorkoutTracking.power)
|
||||
|
||||
if(WorkoutTracking.lastDateMetric.distance(to: Date()) < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
guard let powerType = HKQuantityType.quantityType(
|
||||
forIdentifier: .runningPower) else {
|
||||
return
|
||||
}
|
||||
let wattPerIntervalSample = HKQuantitySample(type: powerType,
|
||||
quantity: wattPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([wattPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
let speedPerInterval = HKQuantity(unit: HKUnit.meter().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.speed * 0.277778)
|
||||
|
||||
guard let speedType = HKQuantityType.quantityType(
|
||||
forIdentifier: .runningSpeed) else {
|
||||
return
|
||||
}
|
||||
let speedPerIntervalSample = HKQuantitySample(type: speedType,
|
||||
quantity: speedPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([speedPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
} else if(sport == 2) {
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
let speedPerInterval = HKQuantity(unit: HKUnit.meter().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.speed * 0.277778)
|
||||
|
||||
guard let speedType = HKQuantityType.quantityType(
|
||||
forIdentifier: .walkingSpeed) else {
|
||||
return
|
||||
}
|
||||
let speedPerIntervalSample = HKQuantitySample(type: speedType,
|
||||
quantity: speedPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([speedPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
}
|
||||
|
||||
WorkoutTracking.lastDateMetric = Date()
|
||||
}
|
||||
|
||||
func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
|
||||
|
||||
@@ -28,7 +28,7 @@ $ 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 release for MacOs
|
||||
Download and install https://download.qt.io/archive/qt/5.12/5.12.12/qt-opensource-mac-x64-5.12.12.dmg and simply run the qdomyos-zwift release for MacOs
|
||||
|
||||
## On Raspberry Pi Zero W
|
||||
|
||||
@@ -77,7 +77,7 @@ Apply the changes `sudo systemctl restart dhcpcd.service` and ensure you have in
|
||||
|
||||
#### Enable SSH access
|
||||
|
||||
You might want to access your raspberry remotely while it is attached to your fitness equipement.
|
||||
You might want to access your raspberry remotely while it is attached to your fitness equipment.
|
||||
|
||||
`sudo raspi-config` > `Interface Options` > `SSH`
|
||||
|
||||
@@ -175,7 +175,7 @@ Then reboot to check operations (`sudo reboot`)
|
||||
|
||||
### (optional) Enable overlay FS
|
||||
|
||||
Once that everything is working as expected, and if you dedicate your raspeberry pi to this usage, you might want to enable the read-only overlay FS.
|
||||
Once that everything is working as expected, and if you dedicate your Raspberry pi to this usage, you might want to enable the read-only overlay FS.
|
||||
|
||||
By enabling the overlay read-only system, your SD card will be read-only only and every file written will be to RAM.
|
||||
Then at each reboot the RAM is erased and you'll revert to the initial status of the overlay file-system.
|
||||
|
||||
@@ -18,7 +18,7 @@ Please refer to this article for more information under [QML Operations](https:/
|
||||
|
||||
## Configuration in NativeQT mode
|
||||
|
||||
This is the list of settings available in the application. These settings needs to be appended to the binary command line.
|
||||
This is the list of settings available in the application. These settings need to be appended to the binary command line.
|
||||
*Example :* `sudo ./qdomyos-zwift -no-gui` for disabling any graphical interface.
|
||||
|
||||
| **Option** | **Type** | **Default** | **Function** |
|
||||
@@ -35,8 +35,8 @@ This is the list of settings available in the application. These settings needs
|
||||
| -heart-service | Boolean | True | Simulate HR service (required for applications not reading FTMS) |
|
||||
| -only-virtualbike | Boolean | False | |
|
||||
| -only-virtualtreadmill | Boolean | False | |
|
||||
| -no-reconnection | Boolean | False | QZ will not try to reconnect your fitness equipement if enabled |
|
||||
| -bluetooth-relaxed | Boolean | False | In case of deconnections from QZ to your fitness equipement |
|
||||
| -no-reconnection | Boolean | False | QZ will not try to reconnect your fitness equipment if enabled |
|
||||
| -bluetooth-relaxed | Boolean | False | In case of deconnections from QZ to your fitness equipment |
|
||||
| -bike-cadence-sensor | Boolean | False | |
|
||||
| -bike-power-sensor | Boolean | False | |
|
||||
| -battery-service | Boolean | False | |
|
||||
@@ -45,7 +45,7 @@ This is the list of settings available in the application. These settings needs
|
||||
| -run-cadence-sensor | Boolean | False | |
|
||||
| -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) |
|
||||
| -name | String | | Force bluetooth device name (if QZ struggles to find your 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 |
|
||||
|
||||
505
docs/50_writing_tests.md
Normal file
505
docs/50_writing_tests.md
Normal file
@@ -0,0 +1,505 @@
|
||||
# QDomyos-Zwift Guide to Writing Unit Tests
|
||||
|
||||
## About
|
||||
|
||||
The testing project tst/qdomyos-zwift-tests.pro contains test code that uses the Google Test library.
|
||||
|
||||
## Adding a new device
|
||||
|
||||
New devices are added to the main QZ application by creating or modifying a subclass of the bluetoothdevice class.
|
||||
|
||||
At minimum, each device has a corresponding BluetoothDeviceTestData subclass in the test project, which is coded to provide information to the test framework to generate tests for device detection and potentially other things.
|
||||
|
||||
In the test project
|
||||
* create a new folder for the device under tst/Devices. This is for anything you define for testing this device.
|
||||
* add a new class with header file and optionally .cpp file to the project in that folder. Name the class DeviceNameTestData, substituting an appropriate name in place of "DeviceName".
|
||||
* edit the header file to inherit the class from the BluetoothDeviceTestData abstract subclass appropriate to the device type, i.e. BikeTestData, RowerTestData, EllipticalTestData, TreadmillTestData.
|
||||
* have this new subclass' constructor pass a unique test name to its superclass.
|
||||
|
||||
The tests are not organised around real devices that are handled, but the bluetoothdevice subclass that handles them - the "driver" of sorts.
|
||||
|
||||
You need to provide the following:
|
||||
- patterns for valid names (e.g. equals a value, starts with a value, case sensitivity, specific length)
|
||||
- invalid names to ensure the device is not identified when the name is invalid
|
||||
- configuration settings that are required for the device to be detected
|
||||
- invalid configurations to test that the device is not detected, e.g. when it's disabled in the settings, but the name is correct
|
||||
- exclusion devices: if a device with the same name but of a higher priority type is detected, this device should not be detected
|
||||
- valid and invalid QBluetoothDeviceInfo configurations, e.g. to check the device is only detected when the manufacturer data is set correctly, or certain services are available or not.
|
||||
|
||||
## Tools in the Test Framework
|
||||
|
||||
### TestSettings
|
||||
|
||||
The detection of many devices depends on settings that are accessed programmatically using the QSettings class and the constants in the QZSettings namespace. The TestSettings class stores a QSettings object with what is intended to be a unique application and organisation name, to keep the configuration it represents seperate from others in the system. It also makes the stored QSettings object the default by setting the QCoreApplication's organisation and application names to those of the QSettings object. The original values are restored by calling the deactivate() function or on object destruction.
|
||||
|
||||
i.e. a test will
|
||||
* apply a configuration from a TestSettings object
|
||||
* perform device detection
|
||||
* use the TestSettings object to restore the previous settings either directly or by letting its destructor be called.
|
||||
|
||||
### DeviceDiscoveryInfo
|
||||
|
||||
This class contains a set of fields that store strongly typed QSettings values.
|
||||
It also provides methods to read and write the values it knows about from and to a QSettings object.
|
||||
|
||||
It is used in conjunction with a TestSettings object to write a configuration during a test.
|
||||
|
||||
|
||||
## Writing a device detection test
|
||||
|
||||
Because of the way the TestData classes currently work, it may be necessary to define multiple test data classes to cover the various cases.
|
||||
For example, if any of a list of names is enough to identify a device, or another group of names but with a certain service in the bluetooth device info, that will require multiple classes.
|
||||
|
||||
### Recognition by Name
|
||||
|
||||
Consider the detection code for the Domyos Bike:
|
||||
|
||||
```
|
||||
} else if (b.name().startsWith(QStringLiteral("Domyos-Bike")) &&
|
||||
!b.name().startsWith(QStringLiteral("DomyosBridge")) && !domyosBike && filter) {
|
||||
|
||||
```
|
||||
|
||||
Reading this, to identify this device:
|
||||
- bluetooth name should start with "Domyos-Bike" using a case sensitive comparison
|
||||
- bluetooth name should NOT start with "DomyosBridge", also using a case sensitive comparison
|
||||
- there should not have been a device using the corresponding device class detected already (i.e. domyos)
|
||||
- filter has not been activated (this isn't tested)
|
||||
|
||||
In this case, we are not testing the last two, but can test the first two.
|
||||
|
||||
|
||||
```
|
||||
#pragma once
|
||||
|
||||
#include "Devices/Bike/biketestdata.h"
|
||||
#include "devices/domyosbike/domyosbike.h"
|
||||
|
||||
class DomyosBikeTestData : public BikeTestData {
|
||||
|
||||
public:
|
||||
DomyosBikeTestData() : BikeTestData("Domyos Bike") {
|
||||
|
||||
this->addDeviceName("Domyos-Bike", comparison::StartsWith);
|
||||
this->addInvalidDeviceName("DomyosBridge", comparison::StartsWith);
|
||||
}
|
||||
|
||||
// not used yet
|
||||
deviceType get_expectedDeviceType() const override { return deviceType::DomyosBike; }
|
||||
|
||||
bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override {
|
||||
return dynamic_cast<domyosbike*>(detectedDevice)!=nullptr;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The constructor adds a valid device name, and an invalid one. Various overloads of these methods and other members of the comparison enumeration provide other capabilities for specifying test data. If you add a valid device name that says the name should start with a value, additional names will be added automatically to the valid list with additional characters to test that it is in fact a "starts with" relationship. Also, valid and invalid names will be generated base on whether the comparison is case sensitive or not.
|
||||
|
||||
The get_expectedDeviceType() function is not actually used and is part of an unfinished refactoring of the device detection code, whereby the bluetoothdevice object doesn't actually get created intially. You could add a new value to the deviceType enum and return that, but it's not used yet. There's always deviceType::None.
|
||||
|
||||
The get_isExpectedDevice(bluetoothdevice *) function must be overridden to indicate if the specified object is of the type expected for this test data.
|
||||
|
||||
### Configuration Settings
|
||||
|
||||
Consider the CompuTrainerTestData. This device is not detected by name, but only by whether or not it is enabled in the settings.
|
||||
To specify this in the test data, we override one of the configureSettings methods, the one for the simple case where there is a single valid and a single invalid configuration.
|
||||
|
||||
Settings from QSettings that contribute to tests should be put into the DeviceDiscoveryInfo class.
|
||||
|
||||
For example, for the Computrainer Bike, the "computrainer_serial_port" value from the QSettings determines if the bike should be detected or not.
|
||||
|
||||
```
|
||||
class DeviceDiscoveryInfo {
|
||||
public :
|
||||
...
|
||||
QString computrainer_serial_port = nullptr;
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
The getValues and setValues methods should be updated to include the addition(s):
|
||||
|
||||
```
|
||||
|
||||
void DeviceDiscoveryInfo::setValues(QSettings &settings, bool clear) const {
|
||||
if(clear) settings.clear();
|
||||
...
|
||||
settings.setValue(QZSettings::computrainer_serialport, this->computrainer_serial_port);
|
||||
...
|
||||
}
|
||||
|
||||
void DeviceDiscoveryInfo::getValues(QSettings &settings){
|
||||
...
|
||||
this->computrainer_serial_port = settings.value(QZSettings::computrainer_serialport, QZSettings::default_computrainer_serialport).toString();
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In the following example, the DeviceDiscoveryInfo class has been updated to contain the device's configuration setting (computrainer_serial_port).
|
||||
- if an enabling configuration is requested (enable==true) a string that is known to be accepted is supplied
|
||||
- if a disabling configuration is requested (enable==false) an empty string is supplied.
|
||||
|
||||
This example uses the simpler of 2 configureSettings methods returns true/false to indicate if the configuration should be used for the test.
|
||||
|
||||
```
|
||||
#pragma once
|
||||
|
||||
#include "Devices/Bike/biketestdata.h"
|
||||
#include "devices/computrainerbike/computrainerbike.h"
|
||||
|
||||
class CompuTrainerTestData : public BikeTestData {
|
||||
protected:
|
||||
bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override {
|
||||
info.computrainer_serial_port = enable ? "X":QString();
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
CompuTrainerTestData() : BikeTestData("CompuTrainer Bike") {
|
||||
// any name
|
||||
this->addDeviceName("", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
|
||||
deviceType get_expectedDeviceType() const override { return deviceType::CompuTrainerBike; }
|
||||
|
||||
bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override {
|
||||
return dynamic_cast<computrainerbike*>(detectedDevice)!=nullptr;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Similarly, the Pafers Bike has a simple configuration setting:
|
||||
|
||||
```
|
||||
#include "Devices/Bike/biketestdata.h"
|
||||
#include "devices/pafersbike/pafersbike.h"
|
||||
|
||||
|
||||
class PafersBikeTestData : public BikeTestData {
|
||||
protected:
|
||||
bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override {
|
||||
// the treadmill is given priority
|
||||
info.pafers_treadmill = !enable;
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
PafersBikeTestData() : BikeTestData("Pafers Bike") {
|
||||
this->addDeviceName("PAFERS_", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
|
||||
deviceType get_expectedDeviceType() const override { return deviceType::PafersBike; }
|
||||
|
||||
bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override {
|
||||
return dynamic_cast<pafersbike*>(detectedDevice)!=nullptr;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
A more complicated example is the Pafers Treadmill. It involves a name match, but also some configuration settings obtained earlier...
|
||||
|
||||
```
|
||||
bool pafers_treadmill = settings.value(QZSettings::pafers_treadmill, QZSettings::default_pafers_treadmill).toBool();
|
||||
...
|
||||
|
||||
bool pafers_treadmill_bh_iboxster_plus =
|
||||
settings
|
||||
.value(QZSettings::pafers_treadmill_bh_iboxster_plus, QZSettings::default_pafers_treadmill_bh_iboxster_plus)
|
||||
.toBool();
|
||||
...
|
||||
|
||||
} else if (b.name().toUpper().startsWith(QStringLiteral("PAFERS_")) && !pafersTreadmill &&
|
||||
(pafers_treadmill || pafers_treadmill_bh_iboxster_plus) && filter) {
|
||||
```
|
||||
|
||||
Here the device could be activated due to a name match and various combinations of settings.
|
||||
For this, the configureSettings function that takes a vector of DeviceDiscoveryInfo objects which is populated with configurations that lead to the specified result (enable = detected, !enable=not detected). Instead of returning a boolean to indicate if a configuration has been supplied, it populates a vector of DeviceDiscoveryInfo objects.
|
||||
|
||||
```
|
||||
#pragma once
|
||||
|
||||
#include "Devices/Treadmill/treadmilltestdata.h"
|
||||
#include "devices/paferstreadmill/paferstreadmill.h"
|
||||
|
||||
class PafersTreadmillTestData : public TreadmillTestData {
|
||||
protected:
|
||||
void configureSettings(const DeviceDiscoveryInfo& info, bool enable, std::vector<DeviceDiscoveryInfo>& configurations) const override {
|
||||
DeviceDiscoveryInfo config(info);
|
||||
|
||||
if (enable) {
|
||||
for(int x = 1; x<=3; x++) {
|
||||
config.pafers_treadmill = x & 1;
|
||||
config.pafers_treadmill_bh_iboxster_plus = x & 2;
|
||||
configurations.push_back(config);
|
||||
}
|
||||
} else {
|
||||
config.pafers_treadmill = false;
|
||||
config.pafers_treadmill_bh_iboxster_plus = false;
|
||||
configurations.push_back(config);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
PafersTreadmillTestData() : TreadmillTestData("Pafers Treadmill") {
|
||||
this->addDeviceName("PAFERS_", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
|
||||
deviceType get_expectedDeviceType() const override { return deviceType::PafersTreadmill; }
|
||||
|
||||
bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override {
|
||||
return dynamic_cast<paferstreadmill*>(detectedDevice)!=nullptr;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Considering Extra QBluetoothDeviceInfo Content
|
||||
|
||||
Detection of some devices requires some specific bluetooth device information.
|
||||
|
||||
Supplying enabling and disabling QBluetoothDeviceInfo objects is done using a similar pattern to the multiple configurations scenario.
|
||||
For example, the M3iBike requires specific manufacturer information.
|
||||
|
||||
|
||||
```
|
||||
void M3IBikeTestData::configureBluetoothDeviceInfos(const QBluetoothDeviceInfo& info, bool enable, std::vector<QBluetoothDeviceInfo>& bluetoothDeviceInfos) const {
|
||||
// The M3I bike detector looks into the manufacturer data.
|
||||
|
||||
QBluetoothDeviceInfo result = info;
|
||||
|
||||
if(!enable) {
|
||||
result.setManufacturerData(1, QByteArray("Invalid manufacturer data."));
|
||||
bluetoothDeviceInfos.push_back(result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int key=0;
|
||||
result.setManufacturerData(key++, hex2bytes("02010639009F00000000000000000014008001"));
|
||||
|
||||
bluetoothDeviceInfos.push_back(result);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The test framework populates the incoming QBluetoothDeviceInfo object with a name and a UUID. This is expected to have nothing else defined.
|
||||
Another example is one of the test data classes for detecting a device that uses the statesbike class:
|
||||
|
||||
Detection code from bluetooth.cpp:
|
||||
|
||||
```
|
||||
((b.name().toUpper().startsWith("KICKR CORE")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818)))
|
||||
```
|
||||
|
||||
This condition is actually extracted from a more complicated example where the current test data classes can't cover all the detection criteria in one implementation. This is why this class inherits from StagesBikeTestData rather than BikeTestData directly.
|
||||
|
||||
```
|
||||
class StagesBike3TestData : public StagesBikeTestData {
|
||||
protected:
|
||||
void configureBluetoothDeviceInfos(const QBluetoothDeviceInfo& info, bool enable, std::vector<QBluetoothDeviceInfo>& bluetoothDeviceInfos) const override {
|
||||
// The condition, if the name is acceptable, is:
|
||||
// !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818)))
|
||||
|
||||
if(enable) {
|
||||
QBluetoothDeviceInfo result = info;
|
||||
result.setServiceUuids(QVector<QBluetoothUuid>({QBluetoothUuid((quint16)0x1818)}));
|
||||
bluetoothDeviceInfos.push_back(result);
|
||||
} else {
|
||||
QBluetoothDeviceInfo hasInvalid = info;
|
||||
hasInvalid.setServiceUuids(QVector<QBluetoothUuid>({QBluetoothUuid((quint16)0x1826)}));
|
||||
QBluetoothDeviceInfo hasBoth = hasInvalid;
|
||||
hasBoth.setServiceUuids(QVector<QBluetoothUuid>({QBluetoothUuid((quint16)0x1818),QBluetoothUuid((quint16)0x1826)}));
|
||||
|
||||
bluetoothDeviceInfos.push_back(info); // has neither
|
||||
bluetoothDeviceInfos.push_back(hasInvalid);
|
||||
bluetoothDeviceInfos.push_back(hasBoth);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
StagesBike3TestData() : StagesBikeTestData("Stages Bike (KICKR CORE)") {
|
||||
|
||||
this->addDeviceName("KICKR CORE", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
In this case, it populates the vector with the single enabling configuration if that's what's been requested, otherwise 3 disabling ones.
|
||||
|
||||
### Exclusions
|
||||
|
||||
Sometimes there might be ambiguity when multiple devices are available, and the detection code may specify that if the other conditions match, but certain specific kinds of devices (the exclusion devices) have already been detected, the newly matched device should be ignored.
|
||||
|
||||
The TestData class can be made to cover this by overriding the configureExclusions() method to add instances of the TestData classes for the exclusion devices to the object's internal list of exclusions.
|
||||
|
||||
Detection code:
|
||||
|
||||
```
|
||||
} else if (b.name().startsWith(QStringLiteral("ECH")) && !echelonRower && !echelonStride &&
|
||||
!echelonConnectSport && filter) {
|
||||
```
|
||||
The configureExclusions code is overridden to specify the exclusion test data objects. Note that the test for a previously detected device of the same type is not included.
|
||||
|
||||
```
|
||||
#pragma once
|
||||
|
||||
#include "Devices/Bike/biketestdata.h"
|
||||
#include "Devices/EchelonRower/echelonrowertestdata.h"
|
||||
#include "Devices/EchelonStrideTreadmill/echelonstridetreadmilltestdata.h"
|
||||
#include "devices/echelonconnectsport/echelonconnectsport.h"
|
||||
|
||||
class EchelonConnectSportBikeTestData : public BikeTestData {
|
||||
|
||||
public:
|
||||
EchelonConnectSportBikeTestData() : BikeTestData("Echelon Connect Sport Bike") {
|
||||
this->addDeviceName("ECH", comparison::StartsWith);
|
||||
}
|
||||
|
||||
void configureExclusions() override {
|
||||
this->exclude(new EchelonRowerTestData());
|
||||
this->exclude(new EchelonStrideTreadmillTestData());
|
||||
}
|
||||
|
||||
deviceType get_expectedDeviceType() const override { return deviceType::EchelonConnectSport; }
|
||||
|
||||
bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override {
|
||||
return dynamic_cast<echelonconnectsport*>(detectedDevice)!=nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
```
|
||||
|
||||
### When a single TestData Class Can't Cover all the Conditions
|
||||
|
||||
Detection code:
|
||||
|
||||
```
|
||||
QString powerSensorName =
|
||||
settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name).toString();
|
||||
...
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("STAGES ")) ||
|
||||
(b.name().toUpper().startsWith("TACX SATORI")) ||
|
||||
((b.name().toUpper().startsWith("KICKR CORE")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818))) ||
|
||||
(b.name().toUpper()==QStringLiteral("QD")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ASSIOMA")) &&
|
||||
powerSensorName.startsWith(QStringLiteral("Disabled")))) &&
|
||||
!stagesBike && !ftmsBike && filter) {
|
||||
```
|
||||
|
||||
This presents 3 scenarios for the current test framework.
|
||||
1. Match names only (starts with:"STAGES ", starts with: "TACX SATORI", equals: "QD")
|
||||
2. Match the name "KICKR CORE", presence and absence of specific service ids
|
||||
3. Match the name "ASSIOMA" and the power sensor name setting starts with "Disabled"
|
||||
|
||||
The framework is not currently capable of specifying all these scenarios in a single class.
|
||||
The generated test data is approximately the combinations of these lists: names * settings * bluetoothdeviceInfo * exclusions.
|
||||
If a combination should not exist, a separate class should be used.
|
||||
|
||||
In the example of the StagesBikeTestData classes, the exclusions, which apply to all situations, are implemented in the superclass StagesBikeTestData,
|
||||
|
||||
|
||||
```
|
||||
#pragma once
|
||||
|
||||
#include "Devices/Bike/biketestdata.h"
|
||||
#include "devices/stagesbike/stagesbike.h"
|
||||
#include "Devices/FTMSBike/ftmsbiketestdata.h"
|
||||
|
||||
class StagesBikeTestData : public BikeTestData {
|
||||
protected:
|
||||
StagesBikeTestData(std::string testName): BikeTestData(testName) {
|
||||
}
|
||||
|
||||
void configureExclusions() override {
|
||||
this->exclude(new FTMSBike1TestData());
|
||||
this->exclude(new FTMSBike2TestData());
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
deviceType get_expectedDeviceType() const override { return deviceType::StagesBike; }
|
||||
|
||||
bool get_isExpectedDevice(bluetoothdevice * detectedDevice) const override {
|
||||
return dynamic_cast<stagesbike*>(detectedDevice)!=nullptr;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The name-match only in one subclass:
|
||||
|
||||
```
|
||||
class StagesBike1TestData : public StagesBikeTestData {
|
||||
|
||||
public:
|
||||
StagesBike1TestData() : StagesBikeTestData("Stages Bike") {
|
||||
this->addDeviceName("STAGES ", comparison::StartsWithIgnoreCase);
|
||||
this->addDeviceName("TACX SATORI", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
The name and setting match in another subclass:
|
||||
|
||||
```
|
||||
|
||||
class StagesBike2TestData : public StagesBikeTestData {
|
||||
protected:
|
||||
bool configureSettings(DeviceDiscoveryInfo& info, bool enable) const override {
|
||||
info.powerSensorName = enable ? "Disabled":"Roberto";
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
StagesBike2TestData() : StagesBikeTestData("Stages Bike (Assioma / Power Sensor disabled") {
|
||||
|
||||
this->addDeviceName("ASSIOMA", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
The name and bluetooth device info configurations in another:
|
||||
|
||||
```
|
||||
|
||||
class StagesBike3TestData : public StagesBikeTestData {
|
||||
protected:
|
||||
void configureBluetoothDeviceInfos(const QBluetoothDeviceInfo& info, bool enable, std::vector<QBluetoothDeviceInfo>& bluetoothDeviceInfos) const override {
|
||||
// The condition, if the name is acceptable, is:
|
||||
// !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818)))
|
||||
|
||||
if(enable) {
|
||||
QBluetoothDeviceInfo result = info;
|
||||
result.setServiceUuids(QVector<QBluetoothUuid>({QBluetoothUuid((quint16)0x1818)}));
|
||||
bluetoothDeviceInfos.push_back(result);
|
||||
} else {
|
||||
QBluetoothDeviceInfo hasInvalid = info;
|
||||
hasInvalid.setServiceUuids(QVector<QBluetoothUuid>({QBluetoothUuid((quint16)0x1826)}));
|
||||
QBluetoothDeviceInfo hasBoth = hasInvalid;
|
||||
hasBoth.setServiceUuids(QVector<QBluetoothUuid>({QBluetoothUuid((quint16)0x1818),QBluetoothUuid((quint16)0x1826)}));
|
||||
|
||||
bluetoothDeviceInfos.push_back(info); // has neither
|
||||
bluetoothDeviceInfos.push_back(hasInvalid);
|
||||
bluetoothDeviceInfos.push_back(hasBoth);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
StagesBike3TestData() : StagesBikeTestData("Stages Bike (KICKR CORE)") {
|
||||
|
||||
this->addDeviceName("KICKR CORE", comparison::StartsWithIgnoreCase);
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## Telling Google Test Where to Look
|
||||
|
||||
To register your test data class(es) with Google Test:
|
||||
|
||||
- open tst/Devices/devices.h
|
||||
- add a #include for your new header file(s)
|
||||
- add your new classes to the BluetoothDeviceTestDataTypes list.
|
||||
|
||||
This will add tests for your new device class to test runs of the tests in the BluetoothDeviceTestSuite class, which are about detecting, and not detecting devices in circumstances generated from the TestData classes.
|
||||
|
||||
|
||||
13
helpers/wireshark-json-filter.py
Normal file
13
helpers/wireshark-json-filter.py
Normal file
@@ -0,0 +1,13 @@
|
||||
import json
|
||||
|
||||
json_file_path = "C:\\Work\\qdomyos-zwift\\helpers\\tmp.json"
|
||||
|
||||
with open(json_file_path, 'r') as file:
|
||||
# Carica i dati JSON
|
||||
json_data = json.load(file)
|
||||
|
||||
for item in json_data:
|
||||
try:
|
||||
print(item['_source']['layers']['btatt']['btatt.value_raw'][0])
|
||||
except:
|
||||
pass
|
||||
BIN
qt-patches/android/5.15.0/jar/QtAndroidBluetooth.jar
Normal file
BIN
qt-patches/android/5.15.0/jar/QtAndroidBluetooth.jar
Normal file
Binary file not shown.
BIN
qt-patches/windows/5.15.2/binary/mingw64/Qt5Bluetooth.dll
Normal file
BIN
qt-patches/windows/5.15.2/binary/mingw64/Qt5Bluetooth.dll
Normal file
Binary file not shown.
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetooth.dll
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetooth.dll
Normal file
Binary file not shown.
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetooth.exp
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetooth.exp
Normal file
Binary file not shown.
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetooth.lib
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetooth.lib
Normal file
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
QMAKE_PRL_BUILD_DIR = C:/qt-everywhere-src-5.15.2/qtconnectivity/src/bluetooth
|
||||
QMAKE_PRO_INPUT = bluetooth.pro
|
||||
QMAKE_PRL_TARGET = Qt5Bluetooth.lib
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin windows prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl flat debug_and_release precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe shared shared release no_plugin_manifest win32 msvc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd rdseed shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions release ReleaseBuild Release build_pass c++11 generated_privates relative_qt_rpath target_qt c++11 strict_c++ c++14 c++1z qt_install_headers need_fwd_pri qt_install_module debug_and_release build_all create_cmake skip_target_version_ext release ReleaseBuild Release build_pass have_target dll exclusive_builds debug_info no_autoqmake thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.15.2
|
||||
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetoothd.dll
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetoothd.dll
Normal file
Binary file not shown.
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetoothd.exp
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetoothd.exp
Normal file
Binary file not shown.
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetoothd.lib
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/Qt5Bluetoothd.lib
Normal file
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
QMAKE_PRL_BUILD_DIR = C:/qt-everywhere-src-5.15.2/qtconnectivity/src/bluetooth
|
||||
QMAKE_PRO_INPUT = bluetooth.pro
|
||||
QMAKE_PRL_TARGET = Qt5Bluetoothd.lib
|
||||
QMAKE_PRL_CONFIG = lex yacc debug depend_includepath testcase_targets import_plugins import_qpa_plugin windows prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on link_prl flat debug_and_release precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe shared shared no_plugin_manifest win32 msvc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd rdseed shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions debug DebugBuild Debug build_pass c++11 generated_privates relative_qt_rpath target_qt c++11 strict_c++ c++14 c++1z qt_install_headers need_fwd_pri qt_install_module debug_and_release build_all create_cmake skip_target_version_ext debug DebugBuild Debug build_pass have_target dll no_plist exclusive_builds debug_info no_autoqmake thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.15.2
|
||||
BIN
qt-patches/windows/5.15.2/binary/msvc2019/ucrtbased.dll
Normal file
BIN
qt-patches/windows/5.15.2/binary/msvc2019/ucrtbased.dll
Normal file
Binary file not shown.
1357
qt-patches/windows/5.15.2/qlowenergycontroller_win.cpp
Normal file
1357
qt-patches/windows/5.15.2/qlowenergycontroller_win.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1162
qt-patches/windows/5.15.2/qlowenergycontroller_winrt.cpp
Normal file
1162
qt-patches/windows/5.15.2/qlowenergycontroller_winrt.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1740
qt-patches/windows/5.15.2/qlowenergycontroller_winrt_new.cpp
Normal file
1740
qt-patches/windows/5.15.2/qlowenergycontroller_winrt_new.cpp
Normal file
File diff suppressed because it is too large
Load Diff
25
src/ChartFooter.qml
Normal file
25
src/ChartFooter.qml
Normal file
@@ -0,0 +1,25 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Loader {
|
||||
id: chartFooterLoader
|
||||
sourceComponent: ChartFooterInnerJS
|
||||
anchors.fill: parent
|
||||
active: false
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
source: CHARTJS ? "ChartFooterInnerJS.qml":"ChartFooterInnerNoJS.qml"
|
||||
onLoaded: {
|
||||
if(CHARTJS) {
|
||||
chartFooterLoader.active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/ChartFooterInnerJS.qml
Normal file
31
src/ChartFooterInnerJS.qml
Normal file
@@ -0,0 +1,31 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
import QtWebView 1.1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Settings {
|
||||
id: settings
|
||||
}
|
||||
WebView {
|
||||
id: webView
|
||||
anchors.fill: parent
|
||||
url: "http://localhost:" + settings.value("template_inner_QZWS_port") + "/chartjs/chartlive.htm"
|
||||
visible: rootItem.chartFooterVisible
|
||||
onLoadingChanged: {
|
||||
if (loadRequest.errorString) {
|
||||
console.error(loadRequest.errorString);
|
||||
console.error("port " + settings.value("template_inner_QZWS_port"));
|
||||
}
|
||||
}
|
||||
onVisibleChanged: {
|
||||
console.log("onVisibleChanged" + visible)
|
||||
if(visible === true) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
src/ChartFooterInnerNoJS.qml
Normal file
12
src/ChartFooterInnerNoJS.qml
Normal file
@@ -0,0 +1,12 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Settings {
|
||||
id: settings
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import QtLocation 5.6
|
||||
|
||||
ColumnLayout {
|
||||
signal trainprogram_open_clicked(url name)
|
||||
signal trainprogram_open_other_folder(url name)
|
||||
signal trainprogram_preview(url name)
|
||||
FileDialog {
|
||||
id: fileDialogTrainProgram
|
||||
@@ -18,7 +19,11 @@ ColumnLayout {
|
||||
folder: shortcuts.home
|
||||
onAccepted: {
|
||||
console.log("You chose: " + fileDialogTrainProgram.fileUrl)
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
if(OS_VERSION === "Android") {
|
||||
trainprogram_open_other_folder(fileDialogTrainProgram.fileUrl)
|
||||
} else {
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
}
|
||||
fileDialogTrainProgram.close()
|
||||
}
|
||||
onRejected: {
|
||||
|
||||
100
src/Home.qml
100
src/Home.qml
@@ -291,59 +291,75 @@ HomeForm{
|
||||
}
|
||||
|
||||
footer:
|
||||
Rectangle {
|
||||
objectName: "footerrectangle"
|
||||
visible: rootItem.videoVisible
|
||||
anchors.top: gridView.bottom
|
||||
Item {
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
// Removed Timer, Play/Pause/Resume is now done via Homeform.cpp
|
||||
/*
|
||||
Timer {
|
||||
id: pauseTimer
|
||||
interval: 1000; running: true; repeat: true
|
||||
onTriggered: { if(visible == true) { (rootItem.currentSpeed > 0 ?
|
||||
videoPlaybackHalf.play() :
|
||||
videoPlaybackHalf.pause()) } }
|
||||
height: (rootItem.chartFooterVisible ? parent.height / 4 : parent.height / 2)
|
||||
anchors.top: gridView.bottom
|
||||
visible: rootItem.chartFooterVisible || rootItem.videoVisible
|
||||
|
||||
Rectangle {
|
||||
id: chartFooterRectangle
|
||||
visible: rootItem.chartFooterVisible
|
||||
anchors.fill: parent
|
||||
ChartFooter {
|
||||
anchors.fill: parent
|
||||
visible: rootItem.chartFooterVisible
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
onVisibleChanged: {
|
||||
if(visible === true) {
|
||||
console.log("mediaPlayer onCompleted: " + rootItem.videoPath)
|
||||
console.log("videoRate: " + rootItem.videoRate)
|
||||
videoPlaybackHalf.source = rootItem.videoPath
|
||||
//videoPlaybackHalf.playbackRate = rootItem.videoRate
|
||||
Rectangle {
|
||||
objectName: "footerrectangle"
|
||||
visible: rootItem.videoVisible
|
||||
anchors.fill: parent
|
||||
// Removed Timer, Play/Pause/Resume is now done via Homeform.cpp
|
||||
/*
|
||||
Timer {
|
||||
id: pauseTimer
|
||||
interval: 1000; running: true; repeat: true
|
||||
onTriggered: { if(visible == true) { (rootItem.currentSpeed > 0 ?
|
||||
videoPlaybackHalf.play() :
|
||||
videoPlaybackHalf.pause()) } }
|
||||
}
|
||||
*/
|
||||
|
||||
onVisibleChanged: {
|
||||
if(visible === true) {
|
||||
console.log("mediaPlayer onCompleted: " + rootItem.videoPath)
|
||||
console.log("videoRate: " + rootItem.videoRate)
|
||||
videoPlaybackHalf.source = rootItem.videoPath
|
||||
//videoPlaybackHalf.playbackRate = rootItem.videoRate
|
||||
|
||||
videoPlaybackHalf.seek(rootItem.videoPosition)
|
||||
videoPlaybackHalf.play()
|
||||
videoPlaybackHalf.muted = rootItem.currentCoordinateValid
|
||||
} else {
|
||||
videoPlaybackHalf.stop()
|
||||
}
|
||||
|
||||
videoPlaybackHalf.seek(rootItem.videoPosition)
|
||||
videoPlaybackHalf.play()
|
||||
videoPlaybackHalf.muted = rootItem.currentCoordinateValid
|
||||
} else {
|
||||
videoPlaybackHalf.stop()
|
||||
}
|
||||
|
||||
}
|
||||
MediaPlayer {
|
||||
id: videoPlaybackHalf
|
||||
objectName: "videoplaybackhalf"
|
||||
autoPlay: false
|
||||
playbackRate: rootItem.videoRate
|
||||
|
||||
MediaPlayer {
|
||||
id: videoPlaybackHalf
|
||||
objectName: "videoplaybackhalf"
|
||||
autoPlay: false
|
||||
playbackRate: rootItem.videoRate
|
||||
|
||||
onError: {
|
||||
if (videoPlaybackHalf.NoError !== error) {
|
||||
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||
onError: {
|
||||
if (videoPlaybackHalf.NoError !== error) {
|
||||
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
VideoOutput {
|
||||
id:videoPlayer
|
||||
anchors.fill: parent
|
||||
source: videoPlaybackHalf
|
||||
}
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
id:videoPlayer
|
||||
anchors.fill: parent
|
||||
source: videoPlaybackHalf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
property int currentId: -1 // Original position in model
|
||||
|
||||
522
src/QTelnet.cpp
Normal file
522
src/QTelnet.cpp
Normal file
@@ -0,0 +1,522 @@
|
||||
#include "QTelnet.h"
|
||||
|
||||
#include "QTelnet.h"
|
||||
#include <QHostAddress>
|
||||
|
||||
const char QTelnet::IACWILL[2] = { IAC, WILL };
|
||||
const char QTelnet::IACWONT[2] = { IAC, WONT };
|
||||
const char QTelnet::IACDO[2] = { IAC, DO };
|
||||
const char QTelnet::IACDONT[2] = { IAC, DONT };
|
||||
const char QTelnet::IACSB[2] = { IAC, SB };
|
||||
const char QTelnet::IACSE[2] = { IAC, SE };
|
||||
|
||||
char QTelnet::_sendCodeArray[2] = { IAC, 0 };
|
||||
char QTelnet::_arrCRLF[2] = { 13, 10 };
|
||||
char QTelnet::_arrCR[2] = { 13, 0 };
|
||||
|
||||
QTelnet::QTelnet(QObject *parent) :
|
||||
QTcpSocket(parent), m_actualSB(0)
|
||||
{
|
||||
connect( this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)) );
|
||||
connect( this, SIGNAL(readyRead()), this, SLOT(onReadyRead()) );
|
||||
}
|
||||
|
||||
QString QTelnet::peerInfo() const
|
||||
{
|
||||
return QString("%1 (%2):%3").arg(peerName()).arg(peerAddress().toString()).arg(peerPort());
|
||||
}
|
||||
|
||||
bool QTelnet::isConnected() const
|
||||
{
|
||||
return state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
|
||||
bool QTelnet::testBinaryMode() const
|
||||
{
|
||||
return m_receivedDX[(unsigned char)TELOPT_BINARY] == DO;
|
||||
}
|
||||
|
||||
void QTelnet::connectToHost(const QString &host, quint16 port)
|
||||
{
|
||||
if( !isConnected() )
|
||||
{
|
||||
resetProtocol();
|
||||
abort();
|
||||
QTcpSocket::connectToHost(host, port);
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::sendData(const QByteArray &ba)
|
||||
{
|
||||
if( isConnected() )
|
||||
transpose( ba.constData(), ba.count() );
|
||||
}
|
||||
|
||||
void QTelnet::socketError(QAbstractSocket::SocketError err)
|
||||
{
|
||||
Q_UNUSED(err);
|
||||
disconnectFromHost();
|
||||
}
|
||||
|
||||
void QTelnet::write(const char c)
|
||||
{
|
||||
QTcpSocket::write( (char*)&c, 1 );
|
||||
}
|
||||
|
||||
void QTelnet::setCustomCR(char cr, char cr2)
|
||||
{
|
||||
_arrCR[0] = cr;
|
||||
_arrCR[1] = cr2;
|
||||
}
|
||||
|
||||
void QTelnet::setCustomCRLF(char lf, char cr)
|
||||
{
|
||||
_arrCR[0] = lf;
|
||||
_arrCR[1] = cr;
|
||||
}
|
||||
|
||||
// Envia el codigo de control al servidor.
|
||||
void QTelnet::sendTelnetControl(char codigo)
|
||||
{
|
||||
_sendCodeArray[1] = codigo;
|
||||
QTcpSocket::write(_sendCodeArray, 2);
|
||||
}
|
||||
|
||||
void QTelnet::writeCustomCRLF()
|
||||
{
|
||||
QTcpSocket::write(_arrCRLF, 2);
|
||||
}
|
||||
|
||||
void QTelnet::writeCustomCR()
|
||||
{
|
||||
QTcpSocket::write(_arrCR, 2);
|
||||
}
|
||||
|
||||
/// Resetea los datos del protocolo. Debe llamarse cada vez que se inicia una conexión nueva.
|
||||
void QTelnet::resetProtocol()
|
||||
{
|
||||
for( int i = 0; i < 256; i++ )
|
||||
{
|
||||
m_receivedDX[i] =
|
||||
m_receivedWX[i] =
|
||||
m_sentDX[i] =
|
||||
m_sentWX[i] = 0;
|
||||
m_negotiationState = STATE_DATA;
|
||||
m_buffSB.clear();
|
||||
m_actualSB = 0;
|
||||
}
|
||||
m_oldWinSize.setHeight(-1);
|
||||
m_oldWinSize.setWidth(-1);
|
||||
}
|
||||
|
||||
void QTelnet::sendSB(char code, char *arr, int iLen)
|
||||
{
|
||||
write(IAC);
|
||||
write(SB);
|
||||
write(code);
|
||||
|
||||
QTcpSocket::write(arr, iLen);
|
||||
|
||||
write(IAC);
|
||||
write(SE);
|
||||
}
|
||||
void QTelnet::sendWindowSize()
|
||||
{
|
||||
if( isConnected() && (m_receivedDX[TELOPT_NAWS] == DO) && (m_oldWinSize != m_winSize) )
|
||||
{
|
||||
char size[4];
|
||||
|
||||
m_oldWinSize = m_winSize;
|
||||
size[0] = (m_winSize.width()>>8) & 0xFF;
|
||||
size[1] = m_winSize.width() & 0xFF;
|
||||
size[2] = (m_winSize.height()>>8) & 0xFF;
|
||||
size[3] = m_winSize.height() & 0xFF;
|
||||
sendSB(TELOPT_NAWS, size, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an incoming IAC SB type chars IAC SE
|
||||
void QTelnet::handleSB()
|
||||
{
|
||||
switch( m_actualSB )
|
||||
{
|
||||
case TELOPT_TTYPE:
|
||||
if( (m_buffSB.count() > 0) && ((unsigned char)m_buffSB[0] == (unsigned char)TELQUAL_SEND) )
|
||||
{
|
||||
QTcpSocket::write(IACSB, 2);
|
||||
write(TELOPT_TTYPE);
|
||||
write(TELQUAL_IS);
|
||||
/* FIXME: need more logic here if we use
|
||||
* more than one terminal type
|
||||
*/
|
||||
QTcpSocket::write("SiraggaTerminal", 15);
|
||||
QTcpSocket::write(IACSE, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Analiza el texto saliente para que cumpla las normas del protocolo.
|
||||
// Además ya lo escribe en el socket.
|
||||
void QTelnet::transpose(const char *buf, int iLen)
|
||||
{
|
||||
for( int i = 0; i < iLen; i++ )
|
||||
{
|
||||
switch( buf[i] )
|
||||
{
|
||||
case IAC:
|
||||
// Escape IAC twice in stream ... to be telnet protocol compliant
|
||||
// this is there in binary and non-binary mode.
|
||||
write(IAC);
|
||||
write(IAC);
|
||||
break;
|
||||
case 10: // \n
|
||||
// We need to heed RFC 854. LF (\n) is 10, CR (\r) is 13
|
||||
// we assume that the Terminal sends \n for lf+cr and \r for just cr
|
||||
// linefeed+carriage return is CR LF
|
||||
|
||||
// En modo binario no se traduce nada.
|
||||
if( testBinaryMode() )
|
||||
write(buf[i]);
|
||||
else
|
||||
writeCustomCRLF();
|
||||
break;
|
||||
case 13: // \r
|
||||
// carriage return is CR NUL */
|
||||
|
||||
// En modo binario no se traduce nada.
|
||||
if( testBinaryMode() )
|
||||
write(buf[i]);
|
||||
else
|
||||
writeCustomCR();
|
||||
break;
|
||||
default:
|
||||
// all other characters are just copied
|
||||
write(buf[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::willsReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentDX[(unsigned char)action]) || (WILL != m_receivedWX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentDX[(unsigned char)action] = reply;
|
||||
m_receivedWX[(unsigned char)action] = WILL;
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::wontsReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentDX[(unsigned char)action]) || (WONT != m_receivedWX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentDX[(unsigned char)action] = reply;
|
||||
m_receivedWX[(unsigned char)action] = WONT;
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::doesReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentWX[(unsigned char)action]) || (DO != m_receivedDX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentWX[(unsigned char)action] = reply;
|
||||
m_receivedDX[(unsigned char)action] = DO;
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::dontsReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentWX[(unsigned char)action]) || (DONT != m_receivedDX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentWX[(unsigned char)action] = reply;
|
||||
m_receivedDX[(unsigned char)action] = DONT;
|
||||
}
|
||||
}
|
||||
|
||||
// Analiza el buffer de entrada colocá ndolo en el buffer de procesado usando el protocolo telnet.
|
||||
qint64 QTelnet::doTelnetInProtocol(qint64 buffSize)
|
||||
{
|
||||
qint64 iIn, iOut;
|
||||
char b;
|
||||
|
||||
for( iIn = 0, iOut = 0; iIn < buffSize; iIn++ )
|
||||
{
|
||||
b = m_buffIncoming[iIn];
|
||||
|
||||
switch( m_negotiationState )
|
||||
{
|
||||
case STATE_DATA:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IAC;
|
||||
break;
|
||||
case '\r':
|
||||
m_negotiationState = STATE_DATAR;
|
||||
break;
|
||||
case '\n':
|
||||
m_negotiationState = STATE_DATAN;
|
||||
break;
|
||||
default:
|
||||
m_buffProcessed[iOut++] = b;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DATAN:
|
||||
case STATE_DATAR:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IAC;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
m_buffProcessed[iOut++] = '\n';
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
default:
|
||||
m_buffProcessed[iOut++] = b;
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IAC:
|
||||
switch( b )
|
||||
{
|
||||
case IAC: // Dos IAC seguidos, se intenta enviar un caracter con el valor IAC.
|
||||
m_negotiationState = STATE_DATA;
|
||||
m_buffProcessed[iOut++] = IAC;
|
||||
break;
|
||||
case WILL:
|
||||
m_negotiationState = STATE_IACWILL;
|
||||
break;
|
||||
case WONT:
|
||||
m_negotiationState = STATE_IACWONT;
|
||||
break;
|
||||
case DONT:
|
||||
m_negotiationState = STATE_IACDONT;
|
||||
break;
|
||||
case DO:
|
||||
m_negotiationState = STATE_IACDO;
|
||||
break;
|
||||
case EOR:
|
||||
emitEndOfRecord();
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case SB:
|
||||
m_negotiationState = STATE_IACSB;
|
||||
m_buffSB.clear();
|
||||
break;
|
||||
default:
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IACWILL:
|
||||
switch( b )
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
emitEchoLocal(false);
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
case TELOPT_EOR:
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
default:
|
||||
willsReply(b, DONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACWONT:
|
||||
switch(b)
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
emitEchoLocal(true);
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
case TELOPT_EOR:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
default:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACDO:
|
||||
switch( b )
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
doesReply(b, WILL);
|
||||
emitEchoLocal(true);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
doesReply(b, WILL);
|
||||
break;
|
||||
case TELOPT_TTYPE:
|
||||
doesReply(b, WILL);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
doesReply(b, WILL);
|
||||
break;
|
||||
case TELOPT_NAWS:
|
||||
m_receivedDX[(unsigned char)b] = (unsigned char)DO;
|
||||
m_sentWX[(unsigned char)b] = (unsigned char)WILL;
|
||||
write(IAC);
|
||||
write(WILL);
|
||||
write(b);
|
||||
|
||||
// Enviamos el tamaño de la pantalla.
|
||||
sendWindowSize();
|
||||
break;
|
||||
default:
|
||||
doesReply(b, WONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACDONT:
|
||||
switch (b)
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
dontsReply(b, WONT);
|
||||
emitEchoLocal(false);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
case TELOPT_NAWS:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
default:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACSB:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
// Entramos en estado IAC en la sub-negociación.
|
||||
m_negotiationState = STATE_IACSBIAC;
|
||||
break;
|
||||
default:
|
||||
// Iniciamos la sub-negociación.
|
||||
m_buffSB.clear();
|
||||
m_actualSB = b;
|
||||
m_negotiationState = STATE_IACSBDATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IACSBDATA: // Estamos en datos de la subnegociación.
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IACSBDATAIAC;
|
||||
break;
|
||||
default:
|
||||
m_buffSB.append(b);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IACSBIAC:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
// Reiniciamos la sub-negociación.
|
||||
m_buffSB.clear();
|
||||
m_actualSB = b;
|
||||
m_negotiationState = STATE_IACSBDATA;
|
||||
default:
|
||||
// Salimos de la sub-negociación.
|
||||
m_negotiationState = STATE_DATA;
|
||||
}
|
||||
break;
|
||||
case STATE_IACSBDATAIAC:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IACSBDATA;
|
||||
m_buffSB.append(IAC);
|
||||
break;
|
||||
case SE:
|
||||
handleSB();
|
||||
m_actualSB = 0;
|
||||
m_buffSB.clear();
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case SB:
|
||||
handleSB();
|
||||
m_buffSB.clear();
|
||||
m_negotiationState = STATE_IACSB;
|
||||
break;
|
||||
default:
|
||||
m_buffSB.clear();
|
||||
m_actualSB = 0;
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return iOut;
|
||||
}
|
||||
|
||||
void QTelnet::onReadyRead()
|
||||
{
|
||||
qint64 readed;
|
||||
qint64 processed;
|
||||
|
||||
while( (readed = read(m_buffIncoming, IncommingBufferSize)) != 0 )
|
||||
{
|
||||
switch( readed )
|
||||
{
|
||||
case -1:
|
||||
disconnectFromHost();
|
||||
break;
|
||||
default:
|
||||
processed = doTelnetInProtocol(readed);
|
||||
if( processed > 0 )
|
||||
Q_EMIT(newData(m_buffProcessed, processed));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
src/QTelnet.h
Normal file
136
src/QTelnet.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#ifndef QTELNET_H
|
||||
#define QTELNET_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qtcpsocket.h>
|
||||
#include <qsize.h>
|
||||
#include <QString>
|
||||
|
||||
#define IncommingBufferSize (1500)
|
||||
|
||||
class QTelnet : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum SocketStatus
|
||||
{
|
||||
Disconnected,
|
||||
Resolving, // Resolving host
|
||||
Connecting, // Connecting to host.
|
||||
Connected // Connected to host.
|
||||
};
|
||||
|
||||
protected:
|
||||
enum TelnetStateCodes
|
||||
{
|
||||
STATE_DATA = (char)0,
|
||||
STATE_IAC = (char)1,
|
||||
STATE_IACSB = (char)2,
|
||||
STATE_IACWILL = (char)3,
|
||||
STATE_IACDO = (char)4,
|
||||
STATE_IACWONT = (char)5,
|
||||
STATE_IACDONT = (char)6,
|
||||
STATE_IACSBIAC = (char)7,
|
||||
STATE_IACSBDATA = (char)8,
|
||||
STATE_IACSBDATAIAC = (char)9,
|
||||
STATE_DATAR = (char)10,
|
||||
STATE_DATAN = (char)11
|
||||
};
|
||||
enum TelnetCodes
|
||||
{
|
||||
// Negociación entrada/salida (cliente<->servidor)
|
||||
IAC = (char)255, // Inicia la secuencia para la negociación telnet.
|
||||
EOR = (char)239, // Estando en la negociación, End Of Record.
|
||||
WILL = (char)251, // Estando en la negociación, Acepta el protocolo?
|
||||
WONT = (char)252, // Estando en la negociación, Acepta el protocolo?
|
||||
DO = (char)253, // Estando en la negociación, Protocolo aceptado.
|
||||
DONT = (char)254, // Estando en la negociación, Protocolo denegado.
|
||||
SB = (char)250, // Estando en la negociación, inicia secuencia de sub-negociación.
|
||||
SE = (char)240, // Estando en la sub-negociación, fin de sub-negociación.
|
||||
|
||||
// Negociación de salida (cliente->servidor)
|
||||
TELOPT_BINARY = (char)0, // Estando en la negociación, pide modo binario.
|
||||
TELOPT_ECHO = (char)1, // Estando en la negociación, pide echo local.
|
||||
TELOPT_SGA = (char)2, // Estando en la negociación, pide Supress Go Ahead.
|
||||
TELOPT_EOR = (char)25, // Estando en la negociación, informa End Of Record.
|
||||
TELOPT_NAWS = (char)31, // Estando en la negociación, Negotiate Abaut Window Size.
|
||||
TELOPT_TTYPE = (char)24 // Estando en la negociación, Terminal Type.
|
||||
};
|
||||
enum TelnetQualifiers
|
||||
{
|
||||
TELQUAL_IS = (char)0,
|
||||
TELQUAL_SEND = (char)1
|
||||
};
|
||||
|
||||
private:
|
||||
static const char IACWILL[2];
|
||||
static const char IACWONT[2];
|
||||
static const char IACDO[2];
|
||||
static const char IACDONT[2];
|
||||
static const char IACSB[2];
|
||||
static const char IACSE[2];
|
||||
static char _sendCodeArray[2];
|
||||
static char _arrCRLF[2];
|
||||
static char _arrCR[2];
|
||||
|
||||
QSize m_winSize; // Tamaño de la pantalla en caracteres.
|
||||
QSize m_oldWinSize; // Tamaño de la pantalla que se envió por última vez al server. Para no enviar el mismo dato.
|
||||
enum TelnetStateCodes m_negotiationState;
|
||||
char m_receivedDX[256]; // What IAC DO(NT) request do we have received already ?
|
||||
char m_receivedWX[256]; // What IAC WILL/WONT request do we have received already ?
|
||||
char m_sentDX[256]; // What IAC DO/DONT request do we have sent already ?
|
||||
char m_sentWX[256]; // What IAC WILL/WONT request do we have sent already ?
|
||||
void resetProtocol();
|
||||
|
||||
char m_buffIncoming[IncommingBufferSize];
|
||||
char m_buffProcessed[IncommingBufferSize];
|
||||
QByteArray m_buffSB;
|
||||
int m_actualSB;
|
||||
|
||||
void emitEndOfRecord() { Q_EMIT(endOfRecord()); }
|
||||
void emitEchoLocal(bool bEcho) { Q_EMIT(echoLocal(bEcho)); }
|
||||
|
||||
void sendTelnetControl(char codigo);
|
||||
void handleSB(void);
|
||||
void transpose(const char *buf, int iLen);
|
||||
|
||||
void willsReply(char action, char reply);
|
||||
void wontsReply(char action, char reply);
|
||||
void doesReply(char action, char reply);
|
||||
void dontsReply(char action, char reply);
|
||||
|
||||
void sendSB(char code, char *arr, int iLen);
|
||||
qint64 doTelnetInProtocol(qint64 buffSize);
|
||||
|
||||
public:
|
||||
explicit QTelnet(QObject *parent = 0);
|
||||
|
||||
virtual void connectToHost(const QString &host, quint16 port);
|
||||
void sendData(const QByteArray &ba);
|
||||
void setCustomCRLF(char lf = 13, char cr = 10);
|
||||
void setCustomCR(char cr = 10, char cr2 = 0);
|
||||
|
||||
void writeCustomCRLF();
|
||||
void writeCustomCR();
|
||||
|
||||
void write(const char c);
|
||||
|
||||
bool isConnected() const;
|
||||
bool testBinaryMode() const;
|
||||
void setWindSize(QSize s) {m_winSize = s;}
|
||||
void sendWindowSize();
|
||||
|
||||
QString peerInfo()const;
|
||||
|
||||
signals:
|
||||
void newData(const char *buff, int len);
|
||||
void endOfRecord();
|
||||
void echoLocal(bool echo);
|
||||
|
||||
private slots:
|
||||
void socketError(QAbstractSocket::SocketError err);
|
||||
void onReadyRead();
|
||||
};
|
||||
|
||||
#endif // QTELNET_H
|
||||
@@ -93,7 +93,7 @@ Item {
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
/*Button {
|
||||
Button {
|
||||
id: restoreButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -101,7 +101,8 @@ Item {
|
||||
text: "Restore Purchases"
|
||||
onClicked: {
|
||||
console.log("restoring...");
|
||||
toast.show("Restoring...");
|
||||
iapStore.restorePurchases();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import Qt.labs.settings 1.0
|
||||
|
||||
ColumnLayout {
|
||||
signal trainprogram_open_clicked(url name)
|
||||
signal trainprogram_open_other_folder(url name)
|
||||
signal trainprogram_preview(url name)
|
||||
FileDialog {
|
||||
id: fileDialogTrainProgram
|
||||
@@ -16,7 +17,11 @@ ColumnLayout {
|
||||
folder: shortcuts.home
|
||||
onAccepted: {
|
||||
console.log("You chose: " + fileDialogTrainProgram.fileUrl)
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
if(OS_VERSION === "Android") {
|
||||
trainprogram_open_other_folder(fileDialogTrainProgram.fileUrl)
|
||||
} else {
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
}
|
||||
fileDialogTrainProgram.close()
|
||||
}
|
||||
onRejected: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0"?>
|
||||
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.13.98" android:versionCode="614" android:installLocation="auto">
|
||||
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.16.52" android:versionCode="781" 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 -->
|
||||
@@ -79,6 +79,19 @@
|
||||
android:name=".ForegroundService"
|
||||
android:enabled="true"
|
||||
android:exported="true"></service>
|
||||
<service
|
||||
android:name=".WearableMessageListenerService"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
|
||||
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/qz"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".ChannelService"></service>
|
||||
<service android:name=".FloatingWindowGFG" android:enabled="true" android:exported="true"/>
|
||||
|
||||
|
||||
@@ -6,9 +6,14 @@ buildscript {
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.6.0'
|
||||
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.9.4'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "com.google.protobuf" version "0.9.4"
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
@@ -17,14 +22,16 @@ repositories {
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'com.google.protobuf'
|
||||
|
||||
def amazon = System.getenv('AMAZON')
|
||||
println(amazon)
|
||||
|
||||
dependencies {
|
||||
compile 'com.rvalerio:fgchecker:1.1.0'
|
||||
implementation "androidx.core:core-ktx:+"
|
||||
implementation "androidx.core:core-ktx:1.12.0"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0"
|
||||
implementation 'com.google.protobuf:protobuf-javalite:3.25.1'
|
||||
|
||||
if(amazon == "1") {
|
||||
// amazon app store
|
||||
@@ -39,13 +46,38 @@ dependencies {
|
||||
def appcompat_version = "1.3.1"
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||
implementation "com.android.billingclient:billing:5.0.0"
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
implementation 'com.android.support:appcompat-v7:28.0.0'
|
||||
|
||||
implementation "androidx.appcompat:appcompat:$appcompat_version"
|
||||
implementation "androidx.appcompat:appcompat-resources:$appcompat_version"
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'com.github.mik3y:usb-serial-for-android:v3.4.6'
|
||||
androidTestImplementation "com.android.support:support-annotations:28.0.0"
|
||||
implementation 'com.google.android.gms:play-services-wearable:+'
|
||||
|
||||
implementation 'com.jakewharton.timber:timber:5.0.1'
|
||||
implementation 'org.bouncycastle:bcpkix-jdk15on:1.60'
|
||||
implementation 'org.bouncycastle:bcprov-jdk15on:1.60'
|
||||
}
|
||||
|
||||
import org.apache.tools.ant.taskdefs.condition.Os
|
||||
|
||||
// Compatible with macOS on Apple Silicon
|
||||
def archSuffix = Os.isFamily(Os.FAMILY_MAC) ? ':osx-x86_64' : ''
|
||||
|
||||
protobuf {
|
||||
protoc {
|
||||
artifact = "com.google.protobuf:protoc:3.25.1$archSuffix"
|
||||
}
|
||||
generateProtoTasks {
|
||||
all().configureEach { task ->
|
||||
task.builtins {
|
||||
java {
|
||||
option "lite"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
protoc_platform=osx-x86_64
|
||||
|
||||
0
src/android/gradlew
vendored
Normal file → Executable file
0
src/android/gradlew
vendored
Normal file → Executable file
BIN
src/android/libs/zaplibrary-debug.aar
Normal file
BIN
src/android/libs/zaplibrary-debug.aar
Normal file
Binary file not shown.
@@ -27,6 +27,7 @@
|
||||
|
||||
<!-- Concept2 PM3,PM4 -->
|
||||
<usb-device vendor-id="17A4" product-id="0002" />
|
||||
<usb-device vendor-id="17A4" product-id="0001" />
|
||||
|
||||
<!-- CDC driver -->
|
||||
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
|
||||
|
||||
@@ -35,11 +35,13 @@ public class Ant {
|
||||
static boolean speedRequest = false;
|
||||
static boolean heartRequest = false;
|
||||
static boolean garminKey = false;
|
||||
static boolean treadmill = false;
|
||||
|
||||
public void antStart(Activity a, boolean SpeedRequest, boolean HeartRequest, boolean GarminKey) {
|
||||
public void antStart(Activity a, boolean SpeedRequest, boolean HeartRequest, boolean GarminKey, boolean Treadmill) {
|
||||
Log.v(TAG, "antStart");
|
||||
speedRequest = SpeedRequest;
|
||||
heartRequest = HeartRequest;
|
||||
treadmill = Treadmill;
|
||||
garminKey = GarminKey;
|
||||
|
||||
activity = a;
|
||||
|
||||
@@ -35,9 +35,14 @@ public class CSafeRowerUSBHID {
|
||||
|
||||
public static void open(Context context) {
|
||||
Log.d("QZ","CSafeRowerUSBHID open");
|
||||
hidBridge = new HidBridge(context, 0x0002, 0x17A4);
|
||||
hidBridge = new HidBridge(context, 0x0002, 0x17A4);
|
||||
boolean ret = hidBridge.OpenDevice();
|
||||
Log.d("QZ","hidBridge.OpenDevice " + ret);
|
||||
if(ret == false) {
|
||||
hidBridge = new HidBridge(context, 0x0001, 0x17A4);
|
||||
ret = hidBridge.OpenDevice();
|
||||
Log.d("QZ","hidBridge.OpenDevice " + ret);
|
||||
}
|
||||
hidBridge.StartReadingThread();
|
||||
Log.d("QZ","hidBridge.StartReadingThread");
|
||||
}
|
||||
|
||||
@@ -50,10 +50,12 @@ public class ChannelService extends Service {
|
||||
HeartChannelController heartChannelController = null;
|
||||
PowerChannelController powerChannelController = null;
|
||||
SpeedChannelController speedChannelController = null;
|
||||
SDMChannelController sdmChannelController = null;
|
||||
|
||||
private ServiceConnection mAntRadioServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
Log.v(TAG, "onServiceConnected");
|
||||
// Must pass in the received IBinder object to correctly construct an AntService object
|
||||
mAntRadioService = new AntService(service);
|
||||
|
||||
@@ -68,6 +70,8 @@ public class ChannelService extends Service {
|
||||
// radio by attempting to acquire a channel.
|
||||
boolean legacyInterfaceInUse = mAntChannelProvider.isLegacyInterfaceInUse();
|
||||
|
||||
Log.v(TAG, "onServiceConnected mChannelAvailable=" + mChannelAvailable + " legacyInterfaceInUse=" + legacyInterfaceInUse);
|
||||
|
||||
// If there are channels OR legacy interface in use, allow adding channels
|
||||
if (mChannelAvailable || legacyInterfaceInUse) {
|
||||
mAllowAddChannel = true;
|
||||
@@ -76,7 +80,11 @@ public class ChannelService extends Service {
|
||||
mAllowAddChannel = false;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
openAllChannels();
|
||||
} catch (ChannelNotAvailableException exception) {
|
||||
Log.e(TAG, "Channel not available!!");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
@@ -104,6 +112,9 @@ public class ChannelService extends Service {
|
||||
if (null != speedChannelController) {
|
||||
speedChannelController.speed = speed;
|
||||
}
|
||||
if (null != sdmChannelController) {
|
||||
sdmChannelController.speed = speed;
|
||||
}
|
||||
}
|
||||
|
||||
void setPower(int power) {
|
||||
@@ -119,10 +130,14 @@ public class ChannelService extends Service {
|
||||
if (null != speedChannelController) {
|
||||
speedChannelController.cadence = cadence;
|
||||
}
|
||||
if (null != sdmChannelController) {
|
||||
sdmChannelController.cadence = cadence;
|
||||
}
|
||||
}
|
||||
|
||||
int getHeart() {
|
||||
if (null != heartChannelController) {
|
||||
Log.v(TAG, "getHeart");
|
||||
return heartChannelController.heart;
|
||||
}
|
||||
return 0;
|
||||
@@ -137,12 +152,16 @@ public class ChannelService extends Service {
|
||||
}
|
||||
|
||||
public void openAllChannels() throws ChannelNotAvailableException {
|
||||
if (Ant.heartRequest)
|
||||
if (Ant.heartRequest && heartChannelController == null)
|
||||
heartChannelController = new HeartChannelController(acquireChannel());
|
||||
|
||||
if (Ant.speedRequest) {
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
if(Ant.treadmill && sdmChannelController == null) {
|
||||
sdmChannelController = new SDMChannelController(acquireChannel());
|
||||
} else if(powerChannelController == null) {
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,9 +172,12 @@ public class ChannelService extends Service {
|
||||
powerChannelController.close();
|
||||
if (speedChannelController != null)
|
||||
speedChannelController.close();
|
||||
if (sdmChannelController != null)
|
||||
sdmChannelController.close();
|
||||
heartChannelController = null;
|
||||
powerChannelController = null;
|
||||
speedChannelController = null;
|
||||
sdmChannelController = null;
|
||||
}
|
||||
|
||||
AntChannel acquireChannel() throws ChannelNotAvailableException {
|
||||
|
||||
28
src/android/src/ContentHelper.java
Normal file
28
src/android/src/ContentHelper.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.util.Log;
|
||||
|
||||
public class ContentHelper {
|
||||
|
||||
public static String getFileName(Context context, Uri uri) {
|
||||
String result = null;
|
||||
if (uri.getScheme().equals("content")) {
|
||||
Log.d("ContentHelper", "content");
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
Log.d("ContentHelper", "cursor " + cursor);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||
Log.d("ContentHelper", "result " + result);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
308
src/android/src/SDMChannelController.java
Normal file
308
src/android/src/SDMChannelController.java
Normal file
@@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.dsi.ant.channel.AntChannel;
|
||||
import com.dsi.ant.channel.AntCommandFailedException;
|
||||
import com.dsi.ant.channel.IAntChannelEventHandler;
|
||||
import com.dsi.ant.message.ChannelId;
|
||||
import com.dsi.ant.message.ChannelType;
|
||||
import com.dsi.ant.message.EventCode;
|
||||
import com.dsi.ant.message.fromant.ChannelEventMessage;
|
||||
import com.dsi.ant.message.fromant.MessageFromAntType;
|
||||
import com.dsi.ant.message.ipc.AntMessageParcel;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class SDMChannelController {
|
||||
// The device type and transmission type to be part of the channel ID message
|
||||
private static final int CHANNEL_SPEED_DEVICE_TYPE = 0x7C;
|
||||
private static final int CHANNEL_SPEED_TRANSMISSION_TYPE = 1;
|
||||
|
||||
// The period and frequency values the channel will be configured to
|
||||
private static final int CHANNEL_SPEED_PERIOD = 8134; // 1 Hz
|
||||
private static final int CHANNEL_SPEED_FREQUENCY = 57;
|
||||
|
||||
private static final String TAG = SDMChannelController.class.getSimpleName();
|
||||
public static final int SPEED_SENSOR_ID = 0x9e3d4b99;
|
||||
|
||||
private static final double MILLISECOND_TO_1_1024_CONVERSION = 0.9765625;
|
||||
|
||||
private AntChannel mAntChannel;
|
||||
|
||||
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
|
||||
|
||||
private boolean mIsOpen;
|
||||
double speed = 0.0;
|
||||
int cadence = 0;
|
||||
byte stride_count = 0;
|
||||
|
||||
public SDMChannelController(AntChannel antChannel) {
|
||||
mAntChannel = antChannel;
|
||||
openChannel();
|
||||
}
|
||||
|
||||
boolean openChannel() {
|
||||
if (null != mAntChannel) {
|
||||
if (mIsOpen) {
|
||||
Log.w(TAG, "Channel was already open");
|
||||
} else {
|
||||
// Channel ID message contains device number, type and transmission type. In
|
||||
// order for master (TX) channels and slave (RX) channels to connect, they
|
||||
// must have the same channel ID, or wildcard (0) is used.
|
||||
ChannelId channelId = new ChannelId(SPEED_SENSOR_ID & 0xFFFF,
|
||||
CHANNEL_SPEED_DEVICE_TYPE, CHANNEL_SPEED_TRANSMISSION_TYPE);
|
||||
|
||||
try {
|
||||
// Setting the channel event handler so that we can receive messages from ANT
|
||||
mAntChannel.setChannelEventHandler(mChannelEventCallback);
|
||||
|
||||
// Performs channel assignment by assigning the type to the channel. Additional
|
||||
// features (such as, background scanning and frequency agility) can be enabled
|
||||
// by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
|
||||
mAntChannel.assign(ChannelType.BIDIRECTIONAL_MASTER);
|
||||
|
||||
/*
|
||||
* Configures the channel ID, messaging period and rf frequency after assigning,
|
||||
* then opening the channel.
|
||||
*
|
||||
* For any additional ANT features such as proximity search or background scanning, refer to
|
||||
* the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
mAntChannel.setChannelId(channelId);
|
||||
mAntChannel.setPeriod(CHANNEL_SPEED_PERIOD);
|
||||
mAntChannel.setRfFrequency(CHANNEL_SPEED_FREQUENCY);
|
||||
mAntChannel.open();
|
||||
mIsOpen = true;
|
||||
|
||||
Log.d(TAG, "Opened channel with device number: " + SPEED_SENSOR_ID);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
} catch (AntCommandFailedException e) {
|
||||
// This will release, and therefore unassign if required
|
||||
channelError("Open failed", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "No channel available");
|
||||
}
|
||||
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
void channelError(RemoteException e) {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
|
||||
if (e.getResponseMessage() != null) {
|
||||
String initiatingMessageId = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getInitiatingMessageId());
|
||||
String rawResponseCode = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getRawResponseCode());
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(initiatingMessageId)
|
||||
.append(" failed with code ")
|
||||
.append(rawResponseCode);
|
||||
} else {
|
||||
String attemptedMessageId = "0x" + Integer.toHexString(
|
||||
e.getAttemptedMessageType().getMessageId());
|
||||
String failureReason = e.getFailureReason().toString();
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(attemptedMessageId)
|
||||
.append(" failed with reason ")
|
||||
.append(failureReason);
|
||||
}
|
||||
|
||||
Log.e(TAG, logString.toString());
|
||||
|
||||
mAntChannel.release();
|
||||
|
||||
Log.e(TAG, "ANT Command Failed");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// TODO kill all our resources
|
||||
if (null != mAntChannel) {
|
||||
mIsOpen = false;
|
||||
|
||||
// Releasing the channel to make it available for others.
|
||||
// After releasing, the AntChannel instance cannot be reused.
|
||||
mAntChannel.release();
|
||||
mAntChannel = null;
|
||||
}
|
||||
|
||||
Log.e(TAG, "Channel Closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Channel Event Handler Interface so that messages can be
|
||||
* received and channel death events can be handled.
|
||||
*/
|
||||
public class ChannelEventCallback implements IAntChannelEventHandler {
|
||||
long lastTime = 0;
|
||||
double totalWay = 0.0;
|
||||
double totalRotations = 0.0;
|
||||
long lastSpeedEventTime = 0;
|
||||
long lastCadenceEventTime = 0;
|
||||
long elapsedMillis = 0;
|
||||
int rotations;
|
||||
int rev;
|
||||
double wheel = 0.1;
|
||||
Timer carousalTimer = null;
|
||||
|
||||
@Override
|
||||
public void onChannelDeath() {
|
||||
// Display channel death message when channel dies
|
||||
Log.e(TAG, "Channel Death");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
|
||||
Log.d(TAG, "Rx: " + antParcel);
|
||||
Log.d(TAG, "Message Type: " + messageType);
|
||||
|
||||
if(carousalTimer == null) {
|
||||
carousalTimer = new Timer(); // At this line a new Thread will be created
|
||||
carousalTimer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Tx Unsollicited");
|
||||
long realtimeMillis = SystemClock.elapsedRealtime();
|
||||
double speedM_s = speed / 3.6;
|
||||
long deltaTime = (realtimeMillis - lastTime);
|
||||
lastTime = realtimeMillis;
|
||||
|
||||
byte[] payload = new byte[8];
|
||||
|
||||
payload[0] = (byte) 0x01;
|
||||
payload[1] = (byte) (((lastTime % 256000) / 5) & 0xFF);
|
||||
payload[2] = (byte) ((lastTime % 256000) / 1000);
|
||||
payload[3] = (byte) 0x00;
|
||||
payload[4] = (byte) speedM_s;
|
||||
payload[5] = (byte) ((speedM_s - (double)((int)speedM_s)) / (1.0/256.0));
|
||||
payload[6] = (byte) stride_count++; // bad but it works on zwift
|
||||
payload[7] = (byte) ((double)deltaTime * 0.03125);
|
||||
|
||||
if (mIsOpen) {
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, 250); // delay
|
||||
}
|
||||
|
||||
// Switching on message type to handle different types of messages
|
||||
switch (messageType) {
|
||||
// If data message, construct from parcel and update channel data
|
||||
case BROADCAST_DATA:
|
||||
// Rx Data
|
||||
//updateData(new BroadcastDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case ACKNOWLEDGED_DATA:
|
||||
// Rx Data
|
||||
//updateData(new AcknowledgedDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case CHANNEL_EVENT:
|
||||
// Constructing channel event message from parcel
|
||||
ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
|
||||
EventCode code = eventMessage.getEventCode();
|
||||
Log.d(TAG, "Event Code: " + code);
|
||||
|
||||
// Switching on event code to handle the different types of channel events
|
||||
switch (code) {
|
||||
case TX:
|
||||
long realtimeMillis = SystemClock.elapsedRealtime();
|
||||
double speedM_s = speed / 3.6;
|
||||
long deltaTime = (realtimeMillis - lastTime);
|
||||
// in case the treadmill doesn't provide cadence, I have to force it. ANT+ requires cadence
|
||||
lastTime = realtimeMillis;
|
||||
|
||||
byte[] payload = new byte[8];
|
||||
|
||||
payload[0] = (byte) 0x01;
|
||||
payload[1] = (byte) (((lastTime % 256000) / 5) & 0xFF);
|
||||
payload[2] = (byte) ((lastTime % 256000) / 1000);
|
||||
payload[3] = (byte) 0x00;
|
||||
payload[4] = (byte) speedM_s;
|
||||
payload[5] = (byte) ((speedM_s - (double)((int)speedM_s)) / (1.0/256.0));
|
||||
payload[6] = (byte) stride_count;
|
||||
payload[7] = (byte) ((double)deltaTime * 0.03125);
|
||||
|
||||
if (mIsOpen) {
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_COLLISION:
|
||||
break;
|
||||
case RX_SEARCH_TIMEOUT:
|
||||
// TODO May want to keep searching
|
||||
Log.e(TAG, "No Device Found");
|
||||
break;
|
||||
case CHANNEL_CLOSED:
|
||||
case RX_FAIL:
|
||||
case RX_FAIL_GO_TO_SEARCH:
|
||||
case TRANSFER_RX_FAILED:
|
||||
case TRANSFER_TX_COMPLETED:
|
||||
case TRANSFER_TX_FAILED:
|
||||
case TRANSFER_TX_START:
|
||||
case UNKNOWN:
|
||||
// TODO More complex communication will need to handle these events
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANT_VERSION:
|
||||
case BURST_TRANSFER_DATA:
|
||||
case CAPABILITIES:
|
||||
case CHANNEL_ID:
|
||||
case CHANNEL_RESPONSE:
|
||||
case CHANNEL_STATUS:
|
||||
case SERIAL_NUMBER:
|
||||
case OTHER:
|
||||
// TODO More complex communication will need to handle these message types
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
95
src/android/src/Shortcuts.java
Normal file
95
src/android/src/Shortcuts.java
Normal file
@@ -0,0 +1,95 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
import android.app.Service;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Deque;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import android.content.pm.ShortcutManager;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import java.io.File;
|
||||
import android.graphics.drawable.Icon;
|
||||
|
||||
|
||||
public class Shortcuts {
|
||||
public static void createShortcutsForFiles(String folder, Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||
ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);
|
||||
|
||||
List<ShortcutInfo> shortcuts = new ArrayList<>();
|
||||
|
||||
Log.d("Shortcuts", folder);
|
||||
File[] files = new File(folder, "profiles").listFiles();
|
||||
if (files != null) {
|
||||
for (int i = 0; i < files.length && i < 5; i++) { // Limit to 5 shortcuts
|
||||
File file = files[i];
|
||||
String fileNameWithoutExtension = file.getName();
|
||||
int dotIndex = fileNameWithoutExtension.lastIndexOf('.');
|
||||
if (dotIndex > 0) { // Check if there is a dot, indicating an extension exists
|
||||
fileNameWithoutExtension = fileNameWithoutExtension.substring(0, dotIndex);
|
||||
}
|
||||
Log.d("Shortcuts", file.getAbsolutePath());
|
||||
Intent intent = new Intent(context, context.getClass());
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
intent.putExtra("profile_path", file.getAbsolutePath());
|
||||
|
||||
ShortcutInfo shortcut = new ShortcutInfo.Builder(context, "id" + fileNameWithoutExtension)
|
||||
.setShortLabel(fileNameWithoutExtension)
|
||||
.setLongLabel("Open " + fileNameWithoutExtension)
|
||||
.setIcon(Icon.createWithResource(context, R.drawable.icon))
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
|
||||
shortcuts.add(shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
shortcutManager.setDynamicShortcuts(shortcuts);
|
||||
getAllExtras(context);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getProfileExtras(Context context) {
|
||||
Intent intent = ((Activity)context).getIntent(); // Ottieni l'Intent che ha avviato l'attività
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
for (String key : extras.keySet()) {
|
||||
Object value = extras.get(key);
|
||||
if("profile_path".equals(key)) {
|
||||
Log.d("Shortcuts", "profile_path: " + value.toString());
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public static void getAllExtras(Context context) {
|
||||
Intent intent = ((Activity)context).getIntent(); // Ottieni l'Intent che ha avviato l'attività
|
||||
Bundle extras = intent.getExtras();
|
||||
if (extras != null) {
|
||||
for (String key : extras.keySet()) {
|
||||
Object value = extras.get(key);
|
||||
Log.d("Shortcuts", "Key: " + key + ", Value: " + value.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/android/src/WearableController.java
Normal file
42
src/android/src/WearableController.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import android.os.Looper;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class WearableController {
|
||||
static Context _context;
|
||||
static Intent _intent = null;
|
||||
|
||||
public static void start(Context context) {
|
||||
_context = context;
|
||||
|
||||
if(_intent == null)
|
||||
_intent = new Intent(context, WearableMessageListenerService.class);
|
||||
// FloatingWindowGFG service is started
|
||||
context.startService(_intent);
|
||||
Log.v("WearableController", "started");
|
||||
}
|
||||
|
||||
public static int getHeart() {
|
||||
return WearableMessageListenerService.getHeart();
|
||||
}
|
||||
}
|
||||
131
src/android/src/WearableMessageListenerService.java
Normal file
131
src/android/src/WearableMessageListenerService.java
Normal file
@@ -0,0 +1,131 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.wearable.MessageClient;
|
||||
import com.google.android.gms.wearable.DataClient;
|
||||
import com.google.android.gms.wearable.DataEvent;
|
||||
import com.google.android.gms.wearable.DataEventBuffer;
|
||||
import com.google.android.gms.wearable.MessageEvent;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.wearable.DataItemBuffer;
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import android.util.Log;
|
||||
import android.os.Bundle;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class WearableMessageListenerService extends Service implements
|
||||
MessageClient.OnMessageReceivedListener, GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,DataClient.OnDataChangedListener {
|
||||
|
||||
private GoogleApiClient googleApiClient;
|
||||
private MessageClient mWearableClient;
|
||||
private String TAG = "WearableMessageListenerService";
|
||||
private static int heart_rate = 0;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.v("WearableMessageListenerService","onCreate");
|
||||
}
|
||||
|
||||
public static int getHeart() {
|
||||
return heart_rate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// Your service logic here
|
||||
|
||||
googleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.addConnectionCallbacks (this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.build();
|
||||
|
||||
googleApiClient.connect();
|
||||
|
||||
// Register the MessageClient.OnMessageReceivedListener
|
||||
mWearableClient = Wearable.getMessageClient(this);
|
||||
mWearableClient.addListener(this);
|
||||
Wearable.getDataClient(this).addListener(this);
|
||||
|
||||
Log.v("WearableMessageListenerService","onStartCommand");
|
||||
|
||||
// Return START_STICKY to restart the service if it's killed by the system
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
for (DataEvent event : dataEvents) {
|
||||
if (event.getType() == DataEvent.TYPE_DELETED) {
|
||||
Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
|
||||
} else if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||
Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri() + " " + event.getDataItem().getUri().getPath());
|
||||
if(event.getDataItem().getUri().getPath().equals("/qz")) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DataItemBuffer result = Wearable.DataApi.getDataItems(googleApiClient).await();
|
||||
if (result.getStatus().isSuccess()) {
|
||||
if (result.getCount() == 1) {
|
||||
heart_rate = DataMap.fromByteArray(result.get(0).getData())
|
||||
.getInt("heart_rate", 0);
|
||||
} else {
|
||||
Log.e(TAG, "Unexpected number of DataItems found.\n"
|
||||
+ "\tExpected: 1\n"
|
||||
+ "\tActual: " + result.getCount());
|
||||
}
|
||||
} else if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "onHandleIntent: failed to get current alarm state");
|
||||
}
|
||||
Log.d(TAG, "Heart: " + heart_rate);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
Log.v("WearableMessageListenerService","onConnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
Log.v("WearableMessageListenerService","onConnectionSuspended");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
Log.v("WearableMessageListenerService","onConnectionFailed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(final MessageEvent messageEvent) {
|
||||
String path = messageEvent.getPath();
|
||||
byte[] data = messageEvent.getData();
|
||||
|
||||
// Handle the received message data here
|
||||
String messageData = new String(data); // Assuming it's a simple string message
|
||||
|
||||
Log.v("Wearable", path);
|
||||
Log.v("Wearable", messageData);
|
||||
|
||||
// You can then perform actions or update data in your service based on the received message
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// This service does not support binding
|
||||
return null;
|
||||
}
|
||||
}
|
||||
55
src/android/src/ZapClickLayer.java
Normal file
55
src/android/src/ZapClickLayer.java
Normal file
@@ -0,0 +1,55 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import android.os.Looper;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.IntentFilter;
|
||||
import android.widget.Toast;
|
||||
import com.che.zap.play.ZwiftPlayDevice;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ZapClickLayer {
|
||||
|
||||
private static Context context;
|
||||
|
||||
private static final String TAG = "ZapClickLayer: ";
|
||||
private static ZwiftPlayDevice device = initDevice();
|
||||
|
||||
private static ZwiftPlayDevice initDevice() {
|
||||
ZwiftPlayDevice d = new ZwiftPlayDevice();
|
||||
return d;
|
||||
}
|
||||
|
||||
public static int processCharacteristic(byte[] value) {
|
||||
Log.d(TAG, "processCharacteristic");
|
||||
return device.processCharacteristic("QZ", value);
|
||||
}
|
||||
|
||||
public static byte[] buildHandshakeStart() {
|
||||
Log.d(TAG, "buildHandshakeStart");
|
||||
return device.buildHandshakeStart();
|
||||
}
|
||||
}
|
||||
65
src/android/src/ZwiftAPI.java
Normal file
65
src/android/src/ZwiftAPI.java
Normal file
@@ -0,0 +1,65 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import android.os.Looper;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import com.garmin.android.connectiq.ConnectIQ;
|
||||
import com.garmin.android.connectiq.ConnectIQAdbStrategy;
|
||||
import com.garmin.android.connectiq.IQApp;
|
||||
import com.garmin.android.connectiq.IQDevice;
|
||||
import com.garmin.android.connectiq.exception.InvalidStateException;
|
||||
import com.garmin.android.connectiq.exception.ServiceUnavailableException;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.IntentFilter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
public class ZwiftAPI {
|
||||
|
||||
private static Context context;
|
||||
|
||||
private static final String TAG = "ZwiftAPI: ";
|
||||
private static ZwiftMessages.PlayerState playerState;
|
||||
|
||||
public static void zwift_api_decodemessage_player(byte[] value) {
|
||||
try {
|
||||
playerState = ZwiftMessages.PlayerState.parseFrom(value);
|
||||
// Ora puoi usare 'message' come un oggetto normale
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
// Gestisci l'eccezione se il messaggio non può essere parsato
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static float getAltitude() {
|
||||
Log.d(TAG, "getAltitude " + playerState.getAltitude());
|
||||
return playerState.getAltitude();
|
||||
}
|
||||
|
||||
public static float getDistance() {
|
||||
Log.d(TAG, "getDistance " + playerState.getDistance());
|
||||
return playerState.getDistance();
|
||||
}
|
||||
}
|
||||
155
src/android/src/main/proto/zwift_messages.proto
Normal file
155
src/android/src/main/proto/zwift_messages.proto
Normal file
@@ -0,0 +1,155 @@
|
||||
syntax="proto3";
|
||||
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
message PlayerState {
|
||||
int32 id = 1;
|
||||
int64 worldTime = 2;
|
||||
int32 distance = 3;
|
||||
int32 roadTime = 4;
|
||||
int32 laps = 5;
|
||||
int32 speed = 6;
|
||||
int32 roadPosition = 8;
|
||||
int32 cadenceUHz = 9;
|
||||
int32 heartrate = 11;
|
||||
int32 power = 12;
|
||||
int64 heading = 13;
|
||||
int32 lean = 14;
|
||||
int32 climbing = 15;
|
||||
int32 time = 16;
|
||||
int32 f19 = 19;
|
||||
int32 f20 = 20;
|
||||
int32 progress = 21;
|
||||
int64 customisationId = 22;
|
||||
int32 justWatching = 23;
|
||||
int32 calories = 24;
|
||||
float x = 25;
|
||||
float altitude = 26;
|
||||
float y = 27;
|
||||
int32 watchingRiderId = 28;
|
||||
int32 groupId = 29;
|
||||
int64 sport = 31;
|
||||
}
|
||||
|
||||
message ClientToServer {
|
||||
int32 connected = 1;
|
||||
int32 rider_id = 2;
|
||||
int64 world_time = 3;
|
||||
PlayerState state = 7;
|
||||
int32 seqno = 4;
|
||||
int64 tag8 = 8;
|
||||
int64 tag9 = 9;
|
||||
int64 last_update = 10;
|
||||
int64 tag11 = 11;
|
||||
int64 last_player_update = 12;
|
||||
}
|
||||
|
||||
message SegmentResult {
|
||||
int64 id = 1;
|
||||
int64 rider_id = 2;
|
||||
int64 event_subgroup_id = 6;
|
||||
string first_name = 7;
|
||||
string last_name = 8;
|
||||
string finish_time_str = 10;
|
||||
int64 elapsed_ms = 11;
|
||||
int32 powermeter = 12;
|
||||
int32 weight = 13;
|
||||
int32 power = 15;
|
||||
int32 heartrate = 19;
|
||||
}
|
||||
|
||||
message SegmentResults {
|
||||
int64 world_id = 1;
|
||||
int64 segment_id = 2;
|
||||
int64 event_subgroup_id = 3;
|
||||
repeated SegmentResult segment_results = 4;
|
||||
}
|
||||
|
||||
message UnknownMessage1 {
|
||||
// string firstName=7;
|
||||
// string lastName=8;
|
||||
// string timestamp=17;
|
||||
}
|
||||
|
||||
message UnknownMessage {
|
||||
// int64 tag1=1;
|
||||
// UnknownMessage1 tag4=4;
|
||||
}
|
||||
|
||||
message ServerToClient {
|
||||
int32 tag1 = 1;
|
||||
int32 rider_id = 2;
|
||||
int64 world_time = 3;
|
||||
int32 seqno = 4;
|
||||
repeated PlayerState player_states = 8;
|
||||
repeated UnknownMessage player_updates = 9;
|
||||
int64 tag11 = 11;
|
||||
int64 tag17 = 17;
|
||||
int32 num_msgs = 18;
|
||||
int32 msgnum = 19;
|
||||
}
|
||||
|
||||
message WorldAttributes {
|
||||
int32 world_id = 1;
|
||||
string name = 2;
|
||||
int64 tag3 = 3;
|
||||
int64 tag5 = 4;
|
||||
int64 world_time = 6;
|
||||
int64 clock_time = 7;
|
||||
}
|
||||
|
||||
message WorldAttribute {
|
||||
int64 world_time = 2;
|
||||
}
|
||||
|
||||
message EventSubgroupProtobuf {
|
||||
int32 id = 1;
|
||||
string name = 2;
|
||||
int32 rules = 8;
|
||||
int32 route = 22;
|
||||
int32 laps = 25;
|
||||
int32 startLocation = 29;
|
||||
int32 label = 30;
|
||||
int32 paceType = 31;
|
||||
int32 jerseyHash = 36;
|
||||
}
|
||||
|
||||
message RiderAttributes {
|
||||
int32 f2 = 2;
|
||||
int32 f3 = 3;
|
||||
message AttributeMessage {
|
||||
int32 myId = 1;
|
||||
int32 theirId = 2;
|
||||
string firstName = 3;
|
||||
string lastName = 4;
|
||||
int32 countryCode = 5;
|
||||
}
|
||||
AttributeMessage attributeMessage = 4;
|
||||
int32 theirId = 10;
|
||||
int32 f13 = 13;
|
||||
}
|
||||
|
||||
message Profiles {
|
||||
repeated Profile profiles = 1;
|
||||
}
|
||||
|
||||
message Profile {
|
||||
int32 id = 1;
|
||||
string firstName = 4;
|
||||
string lastName = 5;
|
||||
int32 male = 6;
|
||||
int32 weight = 9;
|
||||
int32 bodyType = 12;
|
||||
int32 countryCode = 34;
|
||||
int32 totalDistance = 35;
|
||||
int32 totalDistanceClimbed = 36;
|
||||
int32 totalTimeInMinutes = 37;
|
||||
int32 totalWattHours = 41;
|
||||
int32 height = 42;
|
||||
int32 totalExperiencePoints = 46;
|
||||
int32 achievementLevel = 49;
|
||||
int32 powerSource = 52;
|
||||
int32 age = 55;
|
||||
string launchedGameClient = 108;
|
||||
int32 currentActivityId = 109;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "characteristicnotifier2a53.h"
|
||||
#include "treadmill.h"
|
||||
|
||||
CharacteristicNotifier2A53::CharacteristicNotifier2A53(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a53, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2A53::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
value.append(0x02); // total distance
|
||||
uint16_t speed = Bike->currentSpeed().value() / 3.6 * 256;
|
||||
uint32_t distance = Bike->odometer() * 10000.0;
|
||||
value.append((char)((speed & 0xFF)));
|
||||
value.append((char)((speed >> 8) & 0xFF));
|
||||
value.append((char)(Bike->currentCadence().value()));
|
||||
value.append((char)((distance & 0xFF)));
|
||||
value.append((char)((distance >> 8) & 0xFF));
|
||||
value.append((char)((distance >> 16) & 0xFF));
|
||||
value.append((char)((distance >> 24) & 0xFF));
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "characteristicnotifier2a63.h"
|
||||
|
||||
CharacteristicNotifier2A63::CharacteristicNotifier2A63(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a63, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2A63::notify(QByteArray &value) {
|
||||
double normalizeWattage = Bike->wattsMetric().value();
|
||||
if (normalizeWattage < 0)
|
||||
normalizeWattage = 0;
|
||||
|
||||
if (Bike->deviceType() == bluetoothdevice::BIKE) {
|
||||
value.append((char)0x20); // crank data present
|
||||
value.append((char)0x00);
|
||||
value.append((char)(((uint16_t)normalizeWattage) & 0xFF)); // watt
|
||||
value.append((char)(((uint16_t)normalizeWattage) >> 8) & 0xFF); // watt
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) & 0xFF)); // revs count
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) >> 8) & 0xFF); // revs count
|
||||
value.append((char)(Bike->lastCrankEventTime() & 0xff)); // eventtime
|
||||
value.append((char)(Bike->lastCrankEventTime() >> 8) & 0xFF); // eventtime
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER_H
|
||||
#define CHARACTERISTICNOTIFIER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#define CN_INVALID -1
|
||||
#define CN_OK 0
|
||||
|
||||
class CharacteristicNotifier : public QObject {
|
||||
Q_OBJECT
|
||||
quint16 my_uuid;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier(quint16 uuid, QObject *parent = nullptr) : QObject(parent), my_uuid(uuid) {}
|
||||
virtual int notify(QByteArray &out) = 0;
|
||||
quint16 uuid() const { return my_uuid; }
|
||||
signals:
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER_H
|
||||
#ifndef CHARACTERISTICNOTIFIER_H
|
||||
#define CHARACTERISTICNOTIFIER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#define CN_INVALID -1
|
||||
#define CN_OK 0
|
||||
|
||||
class CharacteristicNotifier : public QObject {
|
||||
Q_OBJECT
|
||||
quint16 my_uuid;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier(quint16 uuid, QObject *parent = nullptr) : QObject(parent), my_uuid(uuid) {}
|
||||
virtual int notify(QByteArray &out) = 0;
|
||||
quint16 uuid() const { return my_uuid; }
|
||||
signals:
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER_H
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "characteristicnotifier2a37.h"
|
||||
|
||||
CharacteristicNotifier2A37::CharacteristicNotifier2A37(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a37, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2A37::notify(QByteArray &valueHR) {
|
||||
valueHR.append(char(0)); // Flags that specify the format of the value.
|
||||
valueHR.append(char(Bike->metrics_override_heartrate())); // Actual value.
|
||||
return CN_OK;
|
||||
}
|
||||
#include "characteristicnotifier2a37.h"
|
||||
|
||||
CharacteristicNotifier2A37::CharacteristicNotifier2A37(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a37, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2A37::notify(QByteArray &valueHR) {
|
||||
valueHR.append(char(0)); // Flags that specify the format of the value.
|
||||
valueHR.append(char(Bike->metrics_override_heartrate())); // Actual value.
|
||||
return CN_OK;
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2A37_H
|
||||
#define CHARACTERISTICNOTIFIER2A37_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A37 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A37(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A37_H
|
||||
#ifndef CHARACTERISTICNOTIFIER2A37_H
|
||||
#define CHARACTERISTICNOTIFIER2A37_H
|
||||
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A37 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A37(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A37_H
|
||||
20
src/characteristics/characteristicnotifier2a53.cpp
Normal file
20
src/characteristics/characteristicnotifier2a53.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "characteristicnotifier2a53.h"
|
||||
#include "devices/treadmill.h"
|
||||
|
||||
CharacteristicNotifier2A53::CharacteristicNotifier2A53(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a53, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2A53::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
value.append(0x02); // total distance
|
||||
uint16_t speed = Bike->currentSpeed().value() / 3.6 * 256;
|
||||
uint32_t distance = Bike->odometer() * 10000.0;
|
||||
value.append((char)((speed & 0xFF)));
|
||||
value.append((char)((speed >> 8) & 0xFF));
|
||||
value.append((char)(Bike->currentCadence().value()));
|
||||
value.append((char)((distance & 0xFF)));
|
||||
value.append((char)((distance >> 8) & 0xFF));
|
||||
value.append((char)((distance >> 16) & 0xFF));
|
||||
value.append((char)((distance >> 24) & 0xFF));
|
||||
return CN_OK;
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2A53_H
|
||||
#define CHARACTERISTICNOTIFIER2A53_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A53 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A53(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A53_H
|
||||
#ifndef CHARACTERISTICNOTIFIER2A53_H
|
||||
#define CHARACTERISTICNOTIFIER2A53_H
|
||||
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A53 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A53(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A53_H
|
||||
@@ -1,36 +1,36 @@
|
||||
#include "characteristicnotifier2a5b.h"
|
||||
#include <QSettings>
|
||||
|
||||
CharacteristicNotifier2A5B::CharacteristicNotifier2A5B(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a5b, parent), Bike(Bike) {
|
||||
QSettings settings;
|
||||
bike_wheel_revs = settings.value(QZSettings::bike_wheel_revs, QZSettings::default_bike_wheel_revs).toBool();
|
||||
}
|
||||
|
||||
int CharacteristicNotifier2A5B::notify(QByteArray &value) {
|
||||
if (!bike_wheel_revs) {
|
||||
value.append((char)0x02); // crank data present
|
||||
} else {
|
||||
|
||||
value.append((char)0x03); // crank and wheel data present
|
||||
|
||||
if (Bike->currentSpeed().value()) {
|
||||
|
||||
const double wheelCircumference = 2000.0; // millimeters
|
||||
wheelRevs++;
|
||||
lastWheelTime +=
|
||||
(uint16_t)(1024.0 / ((Bike->currentSpeed().value() / 3.6) / (wheelCircumference / 1000.0)));
|
||||
}
|
||||
value.append((char)((wheelRevs & 0xFF))); // wheel count
|
||||
value.append((char)((wheelRevs >> 8) & 0xFF)); // wheel count
|
||||
value.append((char)((wheelRevs >> 16) & 0xFF)); // wheel count
|
||||
value.append((char)((wheelRevs >> 24) & 0xFF)); // wheel count
|
||||
value.append((char)(lastWheelTime & 0xff)); // eventtime
|
||||
value.append((char)(lastWheelTime >> 8) & 0xFF); // eventtime
|
||||
}
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) & 0xFF)); // revs count
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) >> 8) & 0xFF); // revs count
|
||||
value.append((char)(Bike->lastCrankEventTime() & 0xff)); // eventtime
|
||||
value.append((char)(Bike->lastCrankEventTime() >> 8) & 0xFF); // eventtime
|
||||
return CN_OK;
|
||||
}
|
||||
#include "characteristicnotifier2a5b.h"
|
||||
#include <QSettings>
|
||||
|
||||
CharacteristicNotifier2A5B::CharacteristicNotifier2A5B(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a5b, parent), Bike(Bike) {
|
||||
QSettings settings;
|
||||
bike_wheel_revs = settings.value(QZSettings::bike_wheel_revs, QZSettings::default_bike_wheel_revs).toBool();
|
||||
}
|
||||
|
||||
int CharacteristicNotifier2A5B::notify(QByteArray &value) {
|
||||
if (!bike_wheel_revs) {
|
||||
value.append((char)0x02); // crank data present
|
||||
} else {
|
||||
|
||||
value.append((char)0x03); // crank and wheel data present
|
||||
|
||||
if (Bike->currentSpeed().value()) {
|
||||
|
||||
const double wheelCircumference = 2000.0; // millimeters
|
||||
wheelRevs++;
|
||||
lastWheelTime +=
|
||||
(uint16_t)(1024.0 / ((Bike->currentSpeed().value() / 3.6) / (wheelCircumference / 1000.0)));
|
||||
}
|
||||
value.append((char)((wheelRevs & 0xFF))); // wheel count
|
||||
value.append((char)((wheelRevs >> 8) & 0xFF)); // wheel count
|
||||
value.append((char)((wheelRevs >> 16) & 0xFF)); // wheel count
|
||||
value.append((char)((wheelRevs >> 24) & 0xFF)); // wheel count
|
||||
value.append((char)(lastWheelTime & 0xff)); // eventtime
|
||||
value.append((char)(lastWheelTime >> 8) & 0xFF); // eventtime
|
||||
}
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) & 0xFF)); // revs count
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) >> 8) & 0xFF); // revs count
|
||||
value.append((char)(Bike->lastCrankEventTime() & 0xff)); // eventtime
|
||||
value.append((char)(Bike->lastCrankEventTime() >> 8) & 0xFF); // eventtime
|
||||
return CN_OK;
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2A5B_H
|
||||
#define CHARACTERISTICNOTIFIER2A5B_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A5B : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
uint16_t lastWheelTime = 0;
|
||||
uint32_t wheelRevs = 0;
|
||||
bool bike_wheel_revs;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A5B(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A5B_H
|
||||
#ifndef CHARACTERISTICNOTIFIER2A5B_H
|
||||
#define CHARACTERISTICNOTIFIER2A5B_H
|
||||
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A5B : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
uint16_t lastWheelTime = 0;
|
||||
uint32_t wheelRevs = 0;
|
||||
bool bike_wheel_revs;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A5B(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A5B_H
|
||||
70
src/characteristics/characteristicnotifier2a63.cpp
Normal file
70
src/characteristics/characteristicnotifier2a63.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
#include "characteristicnotifier2a63.h"
|
||||
|
||||
CharacteristicNotifier2A63::CharacteristicNotifier2A63(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2a63, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2A63::notify(QByteArray &value) {
|
||||
double normalizeWattage = Bike->wattsMetric().value();
|
||||
if (normalizeWattage < 0)
|
||||
normalizeWattage = 0;
|
||||
|
||||
if (Bike->deviceType() == bluetoothdevice::BIKE) {
|
||||
/*
|
||||
// set measurement
|
||||
measurement[2] = power & 0xFF;
|
||||
measurement[3] = (power >> 8) & 0xFF;
|
||||
|
||||
measurement[4] = wheelrev & 0xFF;
|
||||
measurement[5] = (wheelrev >> 8) & 0xFF;
|
||||
measurement[6] = (wheelrev >> 16) & 0xFF;
|
||||
measurement[7] = (wheelrev >> 24) & 0xFF;
|
||||
|
||||
measurement[8] = lastwheel & 0xFF;
|
||||
measurement[9] = (lastwheel >> 8) & 0xFF;
|
||||
|
||||
measurement[10] = crankrev & 0xFF;
|
||||
measurement[11] = (crankrev >> 8) & 0xFF;
|
||||
|
||||
measurement[12] = lastcrank & 0xFF;
|
||||
measurement[13] = (lastcrank >> 8) & 0xFF;
|
||||
|
||||
// speed & distance
|
||||
// NOTE : based on Apple Watch default wheel dimension 700c x 2.5mm
|
||||
// NOTE : 3 is theoretical crank:wheel gear ratio
|
||||
// NOTE : 2.13 is circumference of 700c in meters
|
||||
|
||||
wheelCount = crankCount * 3;
|
||||
speed = cadence * 3 * 2.13 * 60 / 1000;
|
||||
distance = wheelCount * 2.13 / 1000;
|
||||
|
||||
#if defined(USEPOWER)
|
||||
lastWheelK = lastCrankK * 2; // 1/2048 s granularity
|
||||
#else
|
||||
lastWheelK = lastCrankK * 1; // 1/1024 s granularity
|
||||
#endif
|
||||
|
||||
*/
|
||||
|
||||
uint32_t wheelCount = (uint32_t)Bike->currentCrankRevolutions() * 3;
|
||||
uint16_t lastWheelK = Bike->lastCrankEventTime() * 2;
|
||||
|
||||
value.append((char)0x30); // crank data present and wheel for apple watch
|
||||
value.append((char)0x00);
|
||||
value.append((char)(((uint16_t)normalizeWattage) & 0xFF)); // watt
|
||||
value.append((char)(((uint16_t)normalizeWattage) >> 8) & 0xFF); // watt
|
||||
|
||||
value.append((char)(((uint32_t)wheelCount) & 0xFF)); // revs count
|
||||
value.append((char)(((uint32_t)wheelCount) >> 8) & 0xFF); // revs count
|
||||
value.append((char)(((uint32_t)wheelCount) >> 16) & 0xFF); // revs count
|
||||
value.append((char)(((uint32_t)wheelCount) >> 24) & 0xFF); // revs count
|
||||
value.append((char)(lastWheelK & 0xff)); // eventtime
|
||||
value.append((char)(lastWheelK >> 8) & 0xFF); // eventtime
|
||||
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) & 0xFF)); // revs count
|
||||
value.append((char)(((uint16_t)Bike->currentCrankRevolutions()) >> 8) & 0xFF); // revs count
|
||||
value.append((char)(Bike->lastCrankEventTime() & 0xff)); // eventtime
|
||||
value.append((char)(Bike->lastCrankEventTime() >> 8) & 0xFF); // eventtime
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2A63_H
|
||||
#define CHARACTERISTICNOTIFIER2A63_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A63 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A63(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A63_H
|
||||
#ifndef CHARACTERISTICNOTIFIER2A63_H
|
||||
#define CHARACTERISTICNOTIFIER2A63_H
|
||||
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2A63 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2A63(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2A63_H
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "characteristicnotifier2acc.h"
|
||||
#include "treadmill.h"
|
||||
#include "devices/treadmill.h"
|
||||
#include <qmath.h>
|
||||
|
||||
CharacteristicNotifier2ACC::CharacteristicNotifier2ACC(bluetoothdevice *Bike, QObject *parent)
|
||||
@@ -10,7 +10,7 @@ int CharacteristicNotifier2ACC::notify(QByteArray &value) {
|
||||
value.append((char)0x14); // heart rate and elapsed time
|
||||
value.append((char)0x00);
|
||||
value.append((char)0x00);
|
||||
value.append((char)0x0C); // resistance and power target supported
|
||||
value.append((char)0x0F); // resistance, power, speed and inclination target supported
|
||||
value.append((char)0xE0); // indoor simulation, wheel and spin down supported
|
||||
value.append((char)0x00);
|
||||
value.append((char)0x00);
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CHARACTERISTICNOTIFIES2ACC_H
|
||||
#define CHARACTERISTICNOTIFIES2ACC_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2ACC : public CharacteristicNotifier {
|
||||
@@ -1,48 +1,63 @@
|
||||
#include "characteristicnotifier2acd.h"
|
||||
#include "treadmill.h"
|
||||
#include <qmath.h>
|
||||
|
||||
CharacteristicNotifier2ACD::CharacteristicNotifier2ACD(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2acd, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2ACD::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
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;
|
||||
char b = normalizeSpeed & 0XFF;
|
||||
QByteArray speedBytes;
|
||||
speedBytes.append(b);
|
||||
speedBytes.append(a);
|
||||
uint16_t normalizeIncline = 0;
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
normalizeIncline = (uint32_t)qRound(((treadmill *)Bike)->currentInclination().value() * 10);
|
||||
a = (normalizeIncline >> 8) & 0XFF;
|
||||
b = normalizeIncline & 0XFF;
|
||||
QByteArray inclineBytes;
|
||||
inclineBytes.append(b);
|
||||
inclineBytes.append(a);
|
||||
double ramp = 0;
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
ramp = qRadiansToDegrees(qAtan(((treadmill *)Bike)->currentInclination().value() / 100));
|
||||
int16_t normalizeRamp = (int32_t)qRound(ramp * 10);
|
||||
a = (normalizeRamp >> 8) & 0XFF;
|
||||
b = normalizeRamp & 0XFF;
|
||||
QByteArray rampBytes;
|
||||
rampBytes.append(b);
|
||||
rampBytes.append(a);
|
||||
|
||||
value.append(speedBytes); // Actual value.
|
||||
|
||||
value.append(inclineBytes); // incline
|
||||
|
||||
value.append(rampBytes); // ramp angle
|
||||
|
||||
value.append(Bike->currentHeart().value()); // current heart rate
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
#include "characteristicnotifier2acd.h"
|
||||
#include "devices/treadmill.h"
|
||||
#include <qmath.h>
|
||||
|
||||
CharacteristicNotifier2ACD::CharacteristicNotifier2ACD(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2acd, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2ACD::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
value.append(0x0C); // Inclination available and distance for peloton
|
||||
value.append((char)0x01); // heart rate available
|
||||
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
char a = (normalizeSpeed >> 8) & 0XFF;
|
||||
char b = normalizeSpeed & 0XFF;
|
||||
QByteArray speedBytes;
|
||||
speedBytes.append(b);
|
||||
speedBytes.append(a);
|
||||
|
||||
// peloton wants the distance from the qz startup to handle stacked classes
|
||||
// https://github.com/cagnulein/qdomyos-zwift/issues/2018
|
||||
uint32_t normalizeDistance = (uint32_t)qRound(Bike->odometerFromStartup() * 1000);
|
||||
a = (normalizeDistance >> 16) & 0XFF;
|
||||
b = (normalizeDistance >> 8) & 0XFF;
|
||||
char c = normalizeDistance & 0XFF;
|
||||
QByteArray distanceBytes;
|
||||
distanceBytes.append(c);
|
||||
distanceBytes.append(b);
|
||||
distanceBytes.append(a);
|
||||
|
||||
|
||||
uint16_t normalizeIncline = 0;
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
normalizeIncline = (uint32_t)qRound(((treadmill *)Bike)->currentInclination().value() * 10);
|
||||
a = (normalizeIncline >> 8) & 0XFF;
|
||||
b = normalizeIncline & 0XFF;
|
||||
QByteArray inclineBytes;
|
||||
inclineBytes.append(b);
|
||||
inclineBytes.append(a);
|
||||
double ramp = 0;
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
ramp = qRadiansToDegrees(qAtan(((treadmill *)Bike)->currentInclination().value() / 100));
|
||||
int16_t normalizeRamp = (int32_t)qRound(ramp * 10);
|
||||
a = (normalizeRamp >> 8) & 0XFF;
|
||||
b = normalizeRamp & 0XFF;
|
||||
QByteArray rampBytes;
|
||||
rampBytes.append(b);
|
||||
rampBytes.append(a);
|
||||
|
||||
value.append(speedBytes); // Actual value.
|
||||
|
||||
value.append(distanceBytes); // Actual value.
|
||||
|
||||
value.append(inclineBytes); // incline
|
||||
|
||||
value.append(rampBytes); // ramp angle
|
||||
|
||||
value.append(Bike->currentHeart().value()); // current heart rate
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2ACD_H
|
||||
#define CHARACTERISTICNOTIFIER2ACD_H
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2ACD : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2ACD(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2ACD_H
|
||||
#ifndef CHARACTERISTICNOTIFIER2ACD_H
|
||||
#define CHARACTERISTICNOTIFIER2ACD_H
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2ACD : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2ACD(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2ACD_H
|
||||
@@ -1,68 +1,77 @@
|
||||
#include "characteristicnotifier2ad2.h"
|
||||
#include "elliptical.h"
|
||||
#include "treadmill.h"
|
||||
#include <QSettings>
|
||||
|
||||
CharacteristicNotifier2AD2::CharacteristicNotifier2AD2(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2ad2, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2AD2::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
double normalizeWattage = Bike->wattsMetric().value();
|
||||
if (normalizeWattage < 0)
|
||||
normalizeWattage = 0;
|
||||
|
||||
if (dt == bluetoothdevice::BIKE) {
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
value.append((char)0x64); // speed, inst. cadence, resistance lvl, instant power
|
||||
value.append((char)0x02); // heart rate
|
||||
|
||||
value.append((char)(normalizeSpeed & 0xFF)); // speed
|
||||
value.append((char)(normalizeSpeed >> 8) & 0xFF); // speed
|
||||
|
||||
value.append((char)((uint16_t)(Bike->currentCadence().value() * 2) & 0xFF)); // cadence
|
||||
value.append((char)(((uint16_t)(Bike->currentCadence().value() * 2) >> 8) & 0xFF)); // cadence
|
||||
|
||||
value.append((char)Bike->currentResistance().value()); // resistance
|
||||
value.append((char)(0)); // resistance
|
||||
|
||||
value.append((char)(((uint16_t)normalizeWattage) & 0xFF)); // watts
|
||||
value.append((char)(((uint16_t)normalizeWattage) >> 8) & 0xFF); // watts
|
||||
|
||||
value.append(char(Bike->currentHeart().value())); // Actual value.
|
||||
value.append((char)0); // Bkool FTMS protocol HRM offset 1280 fix
|
||||
return CN_OK;
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
QSettings settings;
|
||||
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;
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
value.append((char)0x64); // speed, inst. cadence, resistance lvl, instant power
|
||||
value.append((char)0x02); // heart rate
|
||||
|
||||
value.append((char)(normalizeSpeed & 0xFF)); // speed
|
||||
value.append((char)(normalizeSpeed >> 8) & 0xFF); // speed
|
||||
|
||||
uint16_t cadence = 0;
|
||||
if (dt == bluetoothdevice::ELLIPTICAL)
|
||||
cadence = ((elliptical *)Bike)->currentCadence().value();
|
||||
else if (dt == bluetoothdevice::TREADMILL)
|
||||
cadence = ((treadmill *)Bike)->currentCadence().value();
|
||||
|
||||
value.append((char)((uint16_t)(cadence * cadence_multiplier) & 0xFF)); // cadence
|
||||
value.append((char)(((uint16_t)(cadence * cadence_multiplier) >> 8) & 0xFF)); // cadence
|
||||
|
||||
value.append((char)(0)); // resistance
|
||||
value.append((char)(0)); // resistance
|
||||
|
||||
value.append((char)(((uint16_t)normalizeWattage) & 0xFF)); // watts
|
||||
value.append((char)(((uint16_t)normalizeWattage) >> 8) & 0xFF); // watts
|
||||
|
||||
value.append(char(Bike->currentHeart().value())); // Actual value.
|
||||
value.append((char)0);
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
#include "characteristicnotifier2ad2.h"
|
||||
#include "devices/elliptical.h"
|
||||
#include "devices/rower.h"
|
||||
#include "devices/treadmill.h"
|
||||
#include <QSettings>
|
||||
|
||||
CharacteristicNotifier2AD2::CharacteristicNotifier2AD2(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2ad2, parent), Bike(Bike) {}
|
||||
|
||||
int CharacteristicNotifier2AD2::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
|
||||
QSettings settings;
|
||||
bool virtual_device_rower =
|
||||
settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
|
||||
bool rowerAsABike = !virtual_device_rower && dt == bluetoothdevice::ROWING;
|
||||
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;
|
||||
|
||||
|
||||
double normalizeWattage = Bike->wattsMetric().value();
|
||||
if (normalizeWattage < 0)
|
||||
normalizeWattage = 0;
|
||||
|
||||
if (dt == bluetoothdevice::BIKE || rowerAsABike) {
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
value.append((char)0x64); // speed, inst. cadence, resistance lvl, instant power
|
||||
value.append((char)0x02); // heart rate
|
||||
|
||||
value.append((char)(normalizeSpeed & 0xFF)); // speed
|
||||
value.append((char)(normalizeSpeed >> 8) & 0xFF); // speed
|
||||
|
||||
value.append((char)((uint16_t)(Bike->currentCadence().value() * cadence_multiplier) & 0xFF)); // cadence
|
||||
value.append((char)(((uint16_t)(Bike->currentCadence().value() * cadence_multiplier) >> 8) & 0xFF)); // cadence
|
||||
|
||||
value.append((char)Bike->currentResistance().value()); // resistance
|
||||
value.append((char)(0)); // resistance
|
||||
|
||||
value.append((char)(((uint16_t)normalizeWattage) & 0xFF)); // watts
|
||||
value.append((char)(((uint16_t)normalizeWattage) >> 8) & 0xFF); // watts
|
||||
|
||||
value.append(char(Bike->currentHeart().value())); // Actual value.
|
||||
value.append((char)0); // Bkool FTMS protocol HRM offset 1280 fix
|
||||
return CN_OK;
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL || dt == bluetoothdevice::ROWING) {
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
value.append((char)0x64); // speed, inst. cadence, resistance lvl, instant power
|
||||
value.append((char)0x02); // heart rate
|
||||
|
||||
value.append((char)(normalizeSpeed & 0xFF)); // speed
|
||||
value.append((char)(normalizeSpeed >> 8) & 0xFF); // speed
|
||||
|
||||
uint16_t cadence = 0;
|
||||
if (dt == bluetoothdevice::ELLIPTICAL)
|
||||
cadence = ((elliptical *)Bike)->currentCadence().value();
|
||||
else if (dt == bluetoothdevice::TREADMILL)
|
||||
cadence = ((treadmill *)Bike)->currentCadence().value();
|
||||
else if (dt == bluetoothdevice::ROWING)
|
||||
cadence = ((rower *)Bike)->currentCadence().value();
|
||||
|
||||
value.append((char)((uint16_t)(cadence * cadence_multiplier) & 0xFF)); // cadence
|
||||
value.append((char)(((uint16_t)(cadence * cadence_multiplier) >> 8) & 0xFF)); // cadence
|
||||
|
||||
value.append((char)(0)); // resistance
|
||||
value.append((char)(0)); // resistance
|
||||
|
||||
value.append((char)(((uint16_t)normalizeWattage) & 0xFF)); // watts
|
||||
value.append((char)(((uint16_t)normalizeWattage) >> 8) & 0xFF); // watts
|
||||
|
||||
value.append(char(Bike->currentHeart().value())); // Actual value.
|
||||
value.append((char)0);
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2AD2_H
|
||||
#define CHARACTERISTICNOTIFIER2AD2_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2AD2 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2AD2(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2AD2_H
|
||||
#ifndef CHARACTERISTICNOTIFIER2AD2_H
|
||||
#define CHARACTERISTICNOTIFIER2AD2_H
|
||||
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2AD2 : public CharacteristicNotifier {
|
||||
bluetoothdevice *Bike;
|
||||
|
||||
public:
|
||||
explicit CharacteristicNotifier2AD2(bluetoothdevice *Bike, QObject *parent = nullptr);
|
||||
int notify(QByteArray &out) override;
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICNOTIFIER2AD2_H
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "characteristicnotifier2ad9.h"
|
||||
#include "ftmsbike.h"
|
||||
#include "devices/ftmsbike/ftmsbike.h"
|
||||
|
||||
CharacteristicNotifier2AD9::CharacteristicNotifier2AD9(bluetoothdevice *Bike, QObject *parent)
|
||||
: CharacteristicNotifier(0x2ad9, parent), Bike(Bike) {}
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CHARACTERISTICNOTIFIER2AD9_H
|
||||
#define CHARACTERISTICNOTIFIER2AD9_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicnotifier.h"
|
||||
|
||||
class CharacteristicNotifier2AD9 : public CharacteristicNotifier {
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "bike.h"
|
||||
#include "elliptical.h"
|
||||
#include "devices/bike.h"
|
||||
#include "devices/elliptical.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
#include <QSettings>
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
#ifndef CHARACTERISTICWRITEPROCESSOR_H
|
||||
#define CHARACTERISTICWRITEPROCESSOR_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
|
||||
#define CP_INVALID -1
|
||||
#define CP_OK 0
|
||||
|
||||
class CharacteristicWriteProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
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
|
||||
#ifndef CHARACTERISTICWRITEPROCESSOR_H
|
||||
#define CHARACTERISTICWRITEPROCESSOR_H
|
||||
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
|
||||
#define CP_INVALID -1
|
||||
#define CP_OK 0
|
||||
|
||||
class CharacteristicWriteProcessor : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
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
|
||||
@@ -1,138 +1,138 @@
|
||||
#include "characteristicwriteprocessor2ad9.h"
|
||||
#include "elliptical.h"
|
||||
#include "ftmsbike.h"
|
||||
#include "treadmill.h"
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
|
||||
CharacteristicWriteProcessor2AD9::CharacteristicWriteProcessor2AD9(double bikeResistanceGain,
|
||||
uint8_t bikeResistanceOffset, bluetoothdevice *bike,
|
||||
CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent)
|
||||
: 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(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) {
|
||||
|
||||
// Set Target Resistance
|
||||
resistance_t uresistance = data.at(1);
|
||||
uresistance = uresistance / 10;
|
||||
if (force_resistance && !erg_mode) {
|
||||
Bike->changeResistance(uresistance);
|
||||
}
|
||||
qDebug() << QStringLiteral("new requested resistance ") + QString::number(uresistance) +
|
||||
QStringLiteral(" enabled ") + force_resistance;
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_SET_TARGET_RESISTANCE_LEVEL);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
} else if (cmd == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) // simulation parameter
|
||||
|
||||
{
|
||||
qDebug() << QStringLiteral("indoor bike simulation parameters");
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
|
||||
int16_t iresistance = (((uint8_t)data.at(3)) + (data.at(4) << 8));
|
||||
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
|
||||
|
||||
{
|
||||
qDebug() << QStringLiteral("erg mode");
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_SET_TARGET_POWER);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
|
||||
uint16_t power = (((uint8_t)data.at(1)) + (data.at(2) << 8));
|
||||
changePower(power);
|
||||
} else if (cmd == FTMS_START_RESUME) {
|
||||
qDebug() << QStringLiteral("start simulation!");
|
||||
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_START_RESUME);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
} else if (cmd == FTMS_REQUEST_CONTROL) {
|
||||
qDebug() << QStringLiteral("control requested");
|
||||
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((char)FTMS_REQUEST_CONTROL);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("not supported");
|
||||
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)cmd);
|
||||
reply.append((quint8)FTMS_NOT_SUPPORTED);
|
||||
}
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
char a, b;
|
||||
if ((char)data.at(0) == 0x02) {
|
||||
// Set Target Speed
|
||||
a = data.at(1);
|
||||
b = data.at(2);
|
||||
|
||||
uint16_t uspeed = a + (((uint16_t)b) << 8);
|
||||
double requestSpeed = (double)uspeed / 100.0;
|
||||
if (dt == bluetoothdevice::TREADMILL) {
|
||||
((treadmill *)Bike)->changeSpeed(requestSpeed);
|
||||
}
|
||||
qDebug() << QStringLiteral("new requested speed ") + QString::number(requestSpeed);
|
||||
} else if ((char)data.at(0) == 0x03) // Set Target Inclination
|
||||
{
|
||||
a = data.at(1);
|
||||
b = data.at(2);
|
||||
|
||||
int16_t sincline = a + (((int16_t)b) << 8);
|
||||
double requestIncline = (double)sincline / 10.0;
|
||||
if (requestIncline < 0)
|
||||
requestIncline = 0;
|
||||
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
((treadmill *)Bike)->changeInclination(requestIncline, requestIncline);
|
||||
// Resistance as incline on Sole E95s Elliptical #419
|
||||
else if (dt == bluetoothdevice::ELLIPTICAL) {
|
||||
if(((elliptical *)Bike)->inclinationAvailableByHardware())
|
||||
((elliptical *)Bike)->changeInclination(requestIncline, requestIncline);
|
||||
else
|
||||
changeSlope(requestIncline * 100.0, 33, 34);
|
||||
}
|
||||
qDebug() << "new requested incline " + QString::number(requestIncline);
|
||||
} else if ((char)data.at(0) == 0x07) // Start request
|
||||
{
|
||||
// Bike->start();
|
||||
qDebug() << QStringLiteral("request to start");
|
||||
} else if ((char)data.at(0) == 0x08) // Stop request
|
||||
{
|
||||
// Bike->stop();
|
||||
qDebug() << QStringLiteral("request to stop");
|
||||
} else if ((char)data.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) // simulation parameter
|
||||
{
|
||||
qDebug() << QStringLiteral("indoor bike simulation parameters");
|
||||
int16_t iresistance = (((uint8_t)data.at(3)) + (data.at(4) << 8));
|
||||
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) {
|
||||
notifier->answer = reply;
|
||||
}
|
||||
return CP_OK;
|
||||
} else
|
||||
return CP_INVALID;
|
||||
}
|
||||
#include "characteristicwriteprocessor2ad9.h"
|
||||
#include "devices/elliptical.h"
|
||||
#include "devices/ftmsbike/ftmsbike.h"
|
||||
#include "treadmill.h"
|
||||
#include <QSettings>
|
||||
#include <QtMath>
|
||||
|
||||
CharacteristicWriteProcessor2AD9::CharacteristicWriteProcessor2AD9(double bikeResistanceGain,
|
||||
uint8_t bikeResistanceOffset, bluetoothdevice *bike,
|
||||
CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent)
|
||||
: 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(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) {
|
||||
|
||||
// Set Target Resistance
|
||||
resistance_t uresistance = data.at(1);
|
||||
uresistance = uresistance / 10;
|
||||
if (force_resistance && !erg_mode) {
|
||||
Bike->changeResistance(uresistance);
|
||||
}
|
||||
qDebug() << QStringLiteral("new requested resistance ") + QString::number(uresistance) +
|
||||
QStringLiteral(" enabled ") + force_resistance;
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_SET_TARGET_RESISTANCE_LEVEL);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
} else if (cmd == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) // simulation parameter
|
||||
|
||||
{
|
||||
qDebug() << QStringLiteral("indoor bike simulation parameters");
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
|
||||
int16_t iresistance = (((uint8_t)data.at(3)) + (data.at(4) << 8));
|
||||
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
|
||||
|
||||
{
|
||||
qDebug() << QStringLiteral("erg mode");
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_SET_TARGET_POWER);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
|
||||
uint16_t power = (((uint8_t)data.at(1)) + (data.at(2) << 8));
|
||||
changePower(power);
|
||||
} else if (cmd == FTMS_START_RESUME) {
|
||||
qDebug() << QStringLiteral("start simulation!");
|
||||
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)FTMS_START_RESUME);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
} else if (cmd == FTMS_REQUEST_CONTROL) {
|
||||
qDebug() << QStringLiteral("control requested");
|
||||
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((char)FTMS_REQUEST_CONTROL);
|
||||
reply.append((quint8)FTMS_SUCCESS);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("not supported");
|
||||
|
||||
reply.append((quint8)FTMS_RESPONSE_CODE);
|
||||
reply.append((quint8)cmd);
|
||||
reply.append((quint8)FTMS_NOT_SUPPORTED);
|
||||
}
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
char a, b;
|
||||
if ((char)data.at(0) == 0x02) {
|
||||
// Set Target Speed
|
||||
a = data.at(1);
|
||||
b = data.at(2);
|
||||
|
||||
uint16_t uspeed = a + (((uint16_t)b) << 8);
|
||||
double requestSpeed = (double)uspeed / 100.0;
|
||||
if (dt == bluetoothdevice::TREADMILL) {
|
||||
((treadmill *)Bike)->changeSpeed(requestSpeed);
|
||||
}
|
||||
qDebug() << QStringLiteral("new requested speed ") + QString::number(requestSpeed);
|
||||
} else if ((char)data.at(0) == 0x03) // Set Target Inclination
|
||||
{
|
||||
a = data.at(1);
|
||||
b = data.at(2);
|
||||
|
||||
int16_t sincline = a + (((int16_t)b) << 8);
|
||||
double requestIncline = (double)sincline / 10.0;
|
||||
if (requestIncline < 0)
|
||||
requestIncline = 0;
|
||||
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
((treadmill *)Bike)->changeInclination(requestIncline, requestIncline);
|
||||
// Resistance as incline on Sole E95s Elliptical #419
|
||||
else if (dt == bluetoothdevice::ELLIPTICAL) {
|
||||
if(((elliptical *)Bike)->inclinationAvailableByHardware())
|
||||
((elliptical *)Bike)->changeInclination(requestIncline, requestIncline);
|
||||
else
|
||||
changeSlope(requestIncline * 100.0, 33, 34);
|
||||
}
|
||||
qDebug() << "new requested incline " + QString::number(requestIncline);
|
||||
} else if ((char)data.at(0) == 0x07) // Start request
|
||||
{
|
||||
// Bike->start();
|
||||
qDebug() << QStringLiteral("request to start");
|
||||
} else if ((char)data.at(0) == 0x08) // Stop request
|
||||
{
|
||||
// Bike->stop();
|
||||
qDebug() << QStringLiteral("request to stop");
|
||||
} else if ((char)data.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) // simulation parameter
|
||||
{
|
||||
qDebug() << QStringLiteral("indoor bike simulation parameters");
|
||||
int16_t iresistance = (((uint8_t)data.at(3)) + (data.at(4) << 8));
|
||||
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) {
|
||||
notifier->answer = reply;
|
||||
}
|
||||
return CP_OK;
|
||||
} else
|
||||
return CP_INVALID;
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
#ifndef CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
#define CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
|
||||
#include "characteristicnotifier2ad9.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
|
||||
class CharacteristicWriteProcessor2AD9 : public CharacteristicWriteProcessor {
|
||||
Q_OBJECT
|
||||
CharacteristicNotifier2AD9 *notifier = nullptr;
|
||||
|
||||
public:
|
||||
explicit CharacteristicWriteProcessor2AD9(double bikeResistanceGain, uint8_t bikeResistanceOffset,
|
||||
bluetoothdevice *bike, CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent = nullptr);
|
||||
int writeProcess(quint16 uuid, const QByteArray &data, QByteArray &out) override;
|
||||
signals:
|
||||
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
#ifndef CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
#define CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
|
||||
#include "characteristicnotifier2ad9.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
|
||||
class CharacteristicWriteProcessor2AD9 : public CharacteristicWriteProcessor {
|
||||
Q_OBJECT
|
||||
CharacteristicNotifier2AD9 *notifier = nullptr;
|
||||
|
||||
public:
|
||||
explicit CharacteristicWriteProcessor2AD9(double bikeResistanceGain, uint8_t bikeResistanceOffset,
|
||||
bluetoothdevice *bike, CharacteristicNotifier2AD9 *notifier,
|
||||
QObject *parent = nullptr);
|
||||
int writeProcess(quint16 uuid, const QByteArray &data, QByteArray &out) override;
|
||||
signals:
|
||||
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
};
|
||||
|
||||
#endif // CHARACTERISTICWRITEPROCESSOR2AD9_H
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "characteristicwriteprocessore005.h"
|
||||
#include "elliptical.h"
|
||||
#include "ftmsbike.h"
|
||||
#include "treadmill.h"
|
||||
#include "wahookickrsnapbike.h"
|
||||
#include "devices/elliptical.h"
|
||||
#include "devices/ftmsbike/ftmsbike.h"
|
||||
#include "devices/treadmill.h"
|
||||
#include "devices/wahookickrsnapbike/wahookickrsnapbike.h"
|
||||
#include <QtMath>
|
||||
|
||||
CharacteristicWriteProcessorE005::CharacteristicWriteProcessorE005(double bikeResistanceGain,
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef CHARACTERISTICWRITEPROCESSORE005_H
|
||||
#define CHARACTERISTICWRITEPROCESSORE005_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "characteristicwriteprocessor.h"
|
||||
|
||||
class CharacteristicWriteProcessorE005 : public CharacteristicWriteProcessor {
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "activiotreadmill.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualdevices/virtualbike.h"
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "keepawakehelper.h"
|
||||
#endif
|
||||
#include "virtualtreadmill.h"
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -297,6 +297,7 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' '));
|
||||
emit packetReceived();
|
||||
@@ -339,12 +340,12 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
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
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
|
||||
Distance += ((speed / (double)3600.0) /
|
||||
((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
|
||||
((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(now))));
|
||||
lastTimeCharacteristicChanged = now;
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current speed: ") + QString::number(speed));
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
|
||||
#include "treadmill.h"
|
||||
#include "devices/treadmill.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "apexbike.h"
|
||||
#include "ios/lockscreen.h"
|
||||
#include "keepawakehelper.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualdevices/virtualbike.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -129,6 +129,7 @@ void apexbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void apexbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -159,7 +160,7 @@ void apexbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
if (watts())
|
||||
KCal +=
|
||||
@@ -167,17 +168,17 @@ void apexbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
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
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
//* 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
|
||||
if (Cadence.value() > 0) {
|
||||
CrankRevs++;
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "bike.h"
|
||||
#include "devices/bike.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "bhfitnesselliptical.h"
|
||||
#include "ftmsbike.h"
|
||||
#include "virtualtreadmill.h"
|
||||
#include "devices/ftmsbike/ftmsbike.h"
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -142,6 +142,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
if (characteristic.uuid() == QBluetoothUuid::HeartRate && newValue.length() > 1) {
|
||||
Heart = (uint8_t)newValue[1];
|
||||
@@ -191,7 +192,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0),
|
||||
0 /* not useful for elliptical*/);
|
||||
}
|
||||
index += 2;
|
||||
@@ -241,7 +242,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
@@ -288,7 +289,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
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
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
@@ -301,7 +302,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
Heart = ((double)(((uint8_t)newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
@@ -326,7 +327,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled")) &&
|
||||
(!Flags.heartRate || Heart.value() == 0 || disable_hr_frommachinery)) {
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "elliptical.h"
|
||||
#include "devices/elliptical.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
#include "bike.h"
|
||||
#include "devices/bike.h"
|
||||
#include "qdebugfixup.h"
|
||||
#include <QSettings>
|
||||
|
||||
@@ -32,7 +32,8 @@ void bike::changeResistance(resistance_t resistance) {
|
||||
|
||||
void bike::changeInclination(double grade, double percentage) {
|
||||
qDebug() << QStringLiteral("bike::changeInclination") << autoResistanceEnable << grade << percentage;
|
||||
if (autoResistanceEnable) {
|
||||
lastRawRequestedInclinationValue = grade;
|
||||
if (autoResistanceEnable) {
|
||||
requestInclination = grade;
|
||||
}
|
||||
emit inclinationChanged(grade, percentage);
|
||||
@@ -116,6 +117,7 @@ void bike::clearStats() {
|
||||
Speed.clear(false);
|
||||
KCal.clear(true);
|
||||
Distance.clear(true);
|
||||
Distance1s.clear(true);
|
||||
Heart.clear(false);
|
||||
m_jouls.clear(true);
|
||||
elevationAcc = 0;
|
||||
@@ -130,6 +132,9 @@ void bike::clearStats() {
|
||||
Cadence.clear(false);
|
||||
Resistance.clear(false);
|
||||
WattKg.clear(false);
|
||||
for(int i=0; i<maxHeartZone(); i++) {
|
||||
hrZonesSeconds[i].clear(false);
|
||||
}
|
||||
}
|
||||
|
||||
void bike::setPaused(bool p) {
|
||||
@@ -140,6 +145,7 @@ void bike::setPaused(bool p) {
|
||||
Speed.setPaused(p);
|
||||
KCal.setPaused(p);
|
||||
Distance.setPaused(p);
|
||||
Distance1s.setPaused(p);
|
||||
Heart.setPaused(p);
|
||||
m_jouls.setPaused(p);
|
||||
m_watt.setPaused(p);
|
||||
@@ -152,6 +158,9 @@ void bike::setPaused(bool p) {
|
||||
RequestedCadence.setPaused(p);
|
||||
RequestedPower.setPaused(p);
|
||||
WattKg.setPaused(p);
|
||||
for(int i=0; i<maxHeartZone(); i++) {
|
||||
hrZonesSeconds[i].setPaused(p);
|
||||
}
|
||||
}
|
||||
|
||||
void bike::setLap() {
|
||||
@@ -161,6 +170,7 @@ void bike::setLap() {
|
||||
Speed.setLap(false);
|
||||
KCal.setLap(true);
|
||||
Distance.setLap(true);
|
||||
Distance1s.setLap(true);
|
||||
Heart.setLap(false);
|
||||
m_jouls.setLap(true);
|
||||
m_watt.setLap(false);
|
||||
@@ -174,6 +184,9 @@ void bike::setLap() {
|
||||
m_pelotonResistance.setLap(false);
|
||||
Cadence.setLap(false);
|
||||
Resistance.setLap(false);
|
||||
for(int i=0; i<maxHeartZone(); i++) {
|
||||
hrZonesSeconds[i].setLap(false);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t bike::metrics_override_heartrate() {
|
||||
@@ -288,6 +301,8 @@ uint16_t bike::wattFromHR(bool useSpeedAndCadence) {
|
||||
} else {
|
||||
watt = 0;
|
||||
}
|
||||
} else {
|
||||
watt = currentCadence().value() * 1.2; // random value cloned from Zwift when HR is not available
|
||||
}
|
||||
return watt;
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#ifndef BIKE_H
|
||||
#define BIKE_H
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
#include "virtualbike.h"
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "virtualdevices/virtualbike.h"
|
||||
#include <QObject>
|
||||
|
||||
class bike : public bluetoothdevice {
|
||||
@@ -12,7 +12,7 @@ class bike : public bluetoothdevice {
|
||||
public:
|
||||
bike();
|
||||
|
||||
virtualbike * VirtualBike();
|
||||
virtualbike *VirtualBike();
|
||||
|
||||
metric lastRequestedResistance();
|
||||
metric lastRequestedPelotonResistance();
|
||||
@@ -36,8 +36,8 @@ class bike : public bluetoothdevice {
|
||||
uint8_t metrics_override_heartrate() override;
|
||||
void setGears(double d);
|
||||
double gears();
|
||||
void setSpeedLimit(double speed) {m_speedLimit = speed;}
|
||||
double speedLimit() {return m_speedLimit;}
|
||||
void setSpeedLimit(double speed) { m_speedLimit = speed; }
|
||||
double speedLimit() { return m_speedLimit; }
|
||||
|
||||
/**
|
||||
* @brief currentSteeringAngle Gets a metric object to get or set the current steering angle
|
||||
@@ -46,6 +46,7 @@ class bike : public bluetoothdevice {
|
||||
*/
|
||||
metric currentSteeringAngle() { return m_steeringAngle; }
|
||||
virtual bool inclinationAvailableByHardware();
|
||||
bool ergModeSupportedAvailableByHardware() { return ergModeSupported; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void changeResistance(resistance_t res) override;
|
||||
@@ -57,6 +58,10 @@ class bike : public bluetoothdevice {
|
||||
void changeInclination(double grade, double percentage) override;
|
||||
virtual void changeSteeringAngle(double angle) { m_steeringAngle = angle; }
|
||||
virtual void resistanceFromFTMSAccessory(resistance_t res) { Q_UNUSED(res); }
|
||||
void gearUp() {QSettings settings; setGears(gears() +
|
||||
settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble());}
|
||||
void gearDown() {QSettings settings; setGears(gears() -
|
||||
settings.value(QZSettings::gears_gain, QZSettings::default_gears_gain).toDouble());}
|
||||
|
||||
Q_SIGNALS:
|
||||
void bikeStarted();
|
||||
@@ -79,6 +84,7 @@ class bike : public bluetoothdevice {
|
||||
|
||||
double m_gears = 0;
|
||||
resistance_t lastRawRequestedResistanceValue = -1;
|
||||
double lastRawRequestedInclinationValue = -100;
|
||||
uint16_t LastCrankEventTime = 0;
|
||||
double CrankRevs = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "bkoolbike.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualdevices/virtualbike.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -192,6 +192,7 @@ void bkoolbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -253,8 +254,8 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
if (cadence >= 0 && cadence < 255) {
|
||||
Cadence = cadence;
|
||||
}
|
||||
lastGoodCadence = QDateTime::currentDateTime();
|
||||
} else if (lastGoodCadence.msecsTo(QDateTime::currentDateTime()) > 2000) {
|
||||
lastGoodCadence = now;
|
||||
} else if (lastGoodCadence.msecsTo(now) > 2000) {
|
||||
Cadence = 0;
|
||||
}
|
||||
|
||||
@@ -266,7 +267,7 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
.toDouble();
|
||||
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
|
||||
// Resistance = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
// (uint16_t)((uint8_t)newValue.at(index)))); debug("Current Resistance: " +
|
||||
@@ -301,9 +302,9 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
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
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
|
||||
emit debug(QStringLiteral("Current CrankRevsRead: ") + QString::number(CrankRevsRead));
|
||||
emit debug(QStringLiteral("Last CrankEventTime: ") + QString::number(LastCrankEventTime));
|
||||
@@ -384,8 +385,8 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
if (cadence >= 0) {
|
||||
Cadence = cadence;
|
||||
}
|
||||
lastGoodCadence = QDateTime::currentDateTime();
|
||||
} else if (lastGoodCadence.msecsTo(QDateTime::currentDateTime()) > 2000) {
|
||||
lastGoodCadence = now;
|
||||
} else if (lastGoodCadence.msecsTo(now) > 2000) {
|
||||
Cadence = 0;
|
||||
}
|
||||
}
|
||||
@@ -403,12 +404,12 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(now.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())));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
// if we change this, also change the wattsFromResistance function. We can create a standard function in
|
||||
@@ -456,7 +457,7 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
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
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight
|
||||
// in kg * 3.5) / 200 ) / 60
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "bike.h"
|
||||
#include "devices/bike.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
@@ -109,8 +109,16 @@ void bluetooth::finished() {
|
||||
QSettings settings;
|
||||
QString nordictrack_2950_ip =
|
||||
settings.value(QZSettings::nordictrack_2950_ip, QZSettings::default_nordictrack_2950_ip).toString();
|
||||
QString tdf_10_ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString();
|
||||
bool fake_bike =
|
||||
settings.value(QZSettings::applewatch_fakedevice, QZSettings::default_applewatch_fakedevice).toBool();
|
||||
bool fakedevice_elliptical =
|
||||
settings.value(QZSettings::fakedevice_elliptical, QZSettings::default_fakedevice_elliptical).toBool();
|
||||
bool fakedevice_rower = settings.value(QZSettings::fakedevice_rower, QZSettings::default_fakedevice_rower).toBool();
|
||||
bool fakedevice_treadmill =
|
||||
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool();
|
||||
// wifi devices on windows
|
||||
if (!nordictrack_2950_ip.isEmpty()) {
|
||||
if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty() || fake_bike || fakedevice_elliptical || fakedevice_rower || fakedevice_treadmill) {
|
||||
// faking a bluetooth device
|
||||
qDebug() << "faking a bluetooth device for nordictrack_2950_ip";
|
||||
deviceDiscovered(QBluetoothDeviceInfo());
|
||||
@@ -344,6 +352,15 @@ void bluetooth::setLastBluetoothDevice(const QBluetoothDeviceInfo &b) {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool bluetooth::deviceHasService(const QBluetoothDeviceInfo &device, QBluetoothUuid service) {
|
||||
foreach(QBluetoothUuid s, device.serviceUuids()) {
|
||||
if(s == service) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
|
||||
QSettings settings;
|
||||
@@ -362,6 +379,9 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
settings.value(QZSettings::jll_IC400_bike, QZSettings::default_jll_IC400_bike).toBool() ||
|
||||
settings.value(QZSettings::fytter_ri08_bike, QZSettings::default_fytter_ri08_bike).toBool() ||
|
||||
settings.value(QZSettings::asviva_bike, QZSettings::default_asviva_bike).toBool() ||
|
||||
settings.value(QZSettings::enerfit_SPX_9500, QZSettings::default_enerfit_SPX_9500).toBool() ||
|
||||
settings.value(QZSettings::toorx_srx_3500, QZSettings::default_toorx_srx_3500).toBool() ||
|
||||
settings.value(QZSettings::hop_sport_hs_090h_bike, QZSettings::default_hop_sport_hs_090h_bike).toBool() ||
|
||||
settings.value(QZSettings::hertz_xr_770, QZSettings::default_hertz_xr_770).toBool()) &&
|
||||
!toorx_ftms;
|
||||
bool snode_bike = settings.value(QZSettings::snode_bike, QZSettings::default_snode_bike).toBool();
|
||||
@@ -398,6 +418,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool();
|
||||
bool pafers_treadmill = settings.value(QZSettings::pafers_treadmill, QZSettings::default_pafers_treadmill).toBool();
|
||||
QString proformtdf4ip = settings.value(QZSettings::proformtdf4ip, QZSettings::default_proformtdf4ip).toString();
|
||||
QString proformtdf1ip = settings.value(QZSettings::proformtdf1ip, QZSettings::default_proformtdf1ip).toString();
|
||||
QString proformtreadmillip =
|
||||
settings.value(QZSettings::proformtreadmillip, QZSettings::default_proformtreadmillip).toString();
|
||||
QString nordictrack_2950_ip =
|
||||
@@ -422,6 +443,10 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
bool sole_inclination =
|
||||
settings.value(QZSettings::sole_treadmill_inclination, QZSettings::default_sole_treadmill_inclination).toBool();
|
||||
QString ftms_rower = settings.value(QZSettings::ftms_rower, QZSettings::default_ftms_rower).toString();
|
||||
QString ftms_bike = settings.value(QZSettings::ftms_bike, QZSettings::default_ftms_bike).toString();
|
||||
QString ftms_treadmill = settings.value(QZSettings::ftms_treadmill, QZSettings::default_ftms_treadmill).toString();
|
||||
bool saris_trainer = settings.value(QZSettings::saris_trainer, QZSettings::default_saris_trainer).toBool();
|
||||
bool iconsole_elliptical = settings.value(QZSettings::iconsole_elliptical, QZSettings::default_iconsole_elliptical).toBool();
|
||||
|
||||
if (!heartRateBeltFound) {
|
||||
|
||||
@@ -487,7 +512,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
#endif
|
||||
|
||||
QVector<quint16> ids = device.manufacturerIds();
|
||||
qDebug() << "manufacturerData";
|
||||
qDebug() << "manufacturerData" << ids;
|
||||
foreach (quint16 id, ids) {
|
||||
qDebug() << id << device.manufacturerData(id).toHex(' ');
|
||||
|
||||
@@ -536,11 +561,20 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
}
|
||||
|
||||
emit deviceFound(device.name());
|
||||
debug(QStringLiteral("Found new device: ") + device.name() + QStringLiteral(" (") + device.address().toString() +
|
||||
')' + " " + device.majorDeviceClass() + QStringLiteral(":") + device.minorDeviceClass());
|
||||
qDebug() << QStringLiteral("Found new device: ") << device.name() << QStringLiteral(" (") << device.address().toString() <<
|
||||
')' << " " << device.majorDeviceClass() << QStringLiteral(":") << device.minorDeviceClass() << device.serviceUuids()
|
||||
#if defined(Q_OS_DARWIN) || defined(Q_OS_IOS)
|
||||
qDebug() << device.deviceUuid();
|
||||
<< device.deviceUuid();
|
||||
#endif
|
||||
;
|
||||
|
||||
// not required for mobile I guess
|
||||
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
|
||||
if(!homeformLoaded) {
|
||||
qDebug() << "homeform not yet loaded";
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (onlyDiscover)
|
||||
return;
|
||||
@@ -651,6 +685,21 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(proformWifiBike);
|
||||
} else if (!proformtdf1ip.isEmpty() && !proformTelnetBike) {
|
||||
this->stopDiscovery();
|
||||
proformTelnetBike =
|
||||
new proformtelnetbike(noWriteResistance, noHeartService, bikeResistanceOffset, bikeResistanceGain);
|
||||
emit deviceConnected(b);
|
||||
connect(proformTelnetBike, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
// connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
connect(proformTelnetBike, &proformtelnetbike::debug, this, &bluetooth::debug);
|
||||
proformTelnetBike->deviceDiscovered(b);
|
||||
// connect(this, SIGNAL(searchingStop()), cscBike, SLOT(searchingStop())); //NOTE: Commented due to #358
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive()) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(proformTelnetBike);
|
||||
#ifndef Q_OS_IOS
|
||||
} else if (!computrainerSerialPort.isEmpty() && !computrainerBike) {
|
||||
this->stopDiscovery();
|
||||
@@ -711,7 +760,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(nordictrackifitadbTreadmill);
|
||||
} else if (!tdf_10_ip.isEmpty() && !nordictrackifitadbBike) {
|
||||
this->stopDiscovery();
|
||||
nordictrackifitadbBike = new nordictrackifitadbbike(noWriteResistance, noHeartService);
|
||||
nordictrackifitadbBike = new nordictrackifitadbbike(noWriteResistance, noHeartService,
|
||||
bikeResistanceOffset, bikeResistanceGain);
|
||||
emit deviceConnected(b);
|
||||
connect(nordictrackifitadbBike, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
@@ -802,6 +852,23 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(domyosBike);
|
||||
} else if (b.name().toUpper().startsWith(QStringLiteral("FAL-SPORTS")) &&
|
||||
!trxappgateusbElliptical && ftms_bike.contains(QZSettings::default_ftms_bike) && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
trxappgateusbElliptical = new trxappgateusbelliptical(noWriteResistance, noHeartService,
|
||||
bikeResistanceOffset, bikeResistanceGain);
|
||||
emit deviceConnected(b);
|
||||
connect(trxappgateusbElliptical, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
// connect(domyosElliptical, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
connect(trxappgateusbElliptical, &trxappgateusbelliptical::debug, this, &bluetooth::debug);
|
||||
trxappgateusbElliptical->deviceDiscovered(b);
|
||||
connect(this, &bluetooth::searchingStop, trxappgateusbElliptical, &trxappgateusbelliptical::searchingStop);
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive()) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(trxappgateusbElliptical);
|
||||
} else if (b.name().startsWith(QStringLiteral("Domyos-EL")) &&
|
||||
!b.name().startsWith(QStringLiteral("DomyosBridge")) && !domyosElliptical && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -819,7 +886,10 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(domyosElliptical);
|
||||
} else if (b.name().toUpper().startsWith(QStringLiteral("YPOO-U3-")) && !ypooElliptical && filter) {
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("YPOO-U3-")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("SCH_590E")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("E35")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
(b.name().startsWith(QStringLiteral("FS-")) && iconsole_elliptical)) && !ypooElliptical && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
ypooElliptical =
|
||||
@@ -835,7 +905,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(ypooElliptical);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("NAUTILUS E"))) &&
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("NAUTILUS E")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("NAUTILUS M"))) &&
|
||||
!nautilusElliptical && // NAUTILUS E616
|
||||
filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -945,7 +1016,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(bhFitnessElliptical);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("E95S")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("E25")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("E35")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("E35")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("E55")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("E95")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("E98")) ||
|
||||
@@ -967,8 +1038,9 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
this->signalBluetoothDeviceConnected(soleElliptical);
|
||||
} else if (b.name().startsWith(QStringLiteral("Domyos")) &&
|
||||
!b.name().startsWith(QStringLiteral("DomyosBr")) && !domyos && !domyosElliptical &&
|
||||
!domyosBike && !domyosRower && filter) {
|
||||
!b.name().startsWith(QStringLiteral("DomyosBr")) &&
|
||||
!b.name().toUpper().startsWith(QStringLiteral("DOMYOS-BIKING-")) && !domyos && !domyosElliptical &&
|
||||
!domyosBike && !domyosRower && !ftmsBike && !horizonTreadmill && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
domyos = new domyostreadmill(this->pollDeviceTime, noConsole, noHeartService);
|
||||
@@ -998,7 +1070,13 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-HDSC-X21C")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-HDSY-X21C")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NACH-X21C")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-X21C"))) &&
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-X21C")) ||
|
||||
|
||||
// X23 King Smith
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NACH-MXG")) ||
|
||||
|
||||
// KingSmith Walking Pad G1
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-G1C"))) &&
|
||||
!kingsmithR2Treadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
@@ -1023,8 +1101,12 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("KINGSMITH")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("DYNAMAX")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("WALKINGPAD")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-ST-A1P")) || // KingSmith Walkingpad A1 Pro #2041
|
||||
// Poland-distributed WalkingPad R2 TRR2FB
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-SC-BLR2C")) ||
|
||||
!b.name().toUpper().compare(QStringLiteral("RE")) || // just "RE"
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-H")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-BLC")) || // Walkingpad C2 #1672
|
||||
b.name().toUpper().startsWith(
|
||||
QStringLiteral("KS-BLR"))) && // Treadmill KingSmith WalkingPad R2 Pro KS-HCR1AA
|
||||
!kingsmithR1ProTreadmill &&
|
||||
@@ -1050,7 +1132,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive())
|
||||
emit searchingStop();
|
||||
this->signalBluetoothDeviceConnected(kingsmithR1ProTreadmill);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("ZW-"))) && !shuaA5Treadmill && filter) {
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("ZW-"))) && !shuaA5Treadmill && ftms_bike.contains(QZSettings::default_ftms_bike) && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
shuaA5Treadmill = new shuaa5treadmill(noWriteResistance, noHeartService);
|
||||
@@ -1070,6 +1152,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(shuaA5Treadmill);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("TRUE")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("ASSAULT TREADMILL ")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("WDWAY")) && b.name().length() == 8) || // WdWay179
|
||||
(b.name().toUpper().startsWith(QStringLiteral("TREADMILL")) && !gem_module_inclination)) &&
|
||||
!trueTreadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1089,11 +1172,13 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive())
|
||||
emit searchingStop();
|
||||
this->signalBluetoothDeviceConnected(trueTreadmill);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("F80")) ||
|
||||
} else if (((b.name().toUpper().startsWith(QStringLiteral("F80")) && sole_inclination) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F89")) && sole_inclination) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("F65")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("TT8")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("TT8")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("F63")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("ST90")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("TRX7.5")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("S77")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F85")) && sole_inclination)) &&
|
||||
!soleF80 && filter) {
|
||||
@@ -1160,16 +1245,30 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("CT800")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("TRX4500")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("MATRIXTF50")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("T01_")) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("TF-")) &&
|
||||
horizon_treadmill_force_ftms) || // FTMS, TF-769DF2
|
||||
((b.name().toUpper().startsWith(QStringLiteral("TOORX")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")))) &&
|
||||
!toorx_ftms && toorx_ftms_treadmill) ||
|
||||
!b.name().compare(ftms_treadmill, Qt::CaseInsensitive) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("DOMYOS-TC")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("XT685")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("T118_")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("FIT-")) || // FIT-1596
|
||||
(b.name().toUpper().startsWith("SCHWINN 810")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("TT8")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("MOBVOI TM")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("TUNTURI T60-")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("KETTLER TREADMILL")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("ASSAULTRUNNER")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("CITYSPORTS-LINKER")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("CTM")) && b.name().length() >= 15) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F85")) && !sole_inclination) || // FMTS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F89")) && !sole_inclination) || // FMTS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F80")) && !sole_inclination) || // FMTS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ANPLUS-"))) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("ESANGLINKER"))) &&
|
||||
!horizonTreadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1198,7 +1297,11 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("MYRUN ")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("MERACH-U3")) // FTMS
|
||||
) &&
|
||||
!technogymmyrunTreadmill && filter) {
|
||||
!technogymmyrunTreadmill
|
||||
#ifndef Q_OS_IOS
|
||||
&& !technogymmyrunrfcommTreadmill
|
||||
#endif
|
||||
&& filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
bool technogym_myrun_treadmill_experimental =
|
||||
@@ -1258,10 +1361,11 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(technogymmyrunrfcommTreadmill);
|
||||
}
|
||||
#endif
|
||||
} else if ((b.name().toUpper().startsWith("TACX NEO") ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("TACX FLOW")) ||
|
||||
} else if ((b.name().toUpper().startsWith("TACX ") ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("THINK X")) ||
|
||||
b.address() == QBluetoothAddress("C1:14:D9:9C:FB:01") || // specific TACX NEO 2 #1707
|
||||
(b.name().toUpper().startsWith("TACX SMART BIKE"))) &&
|
||||
!b.name().toUpper().startsWith("TACX SATORI") &&
|
||||
!tacxneo2Bike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
@@ -1296,28 +1400,47 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
npeCableBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(npeCableBike);
|
||||
} else if (((b.name().startsWith("FS-") && hammerRacerS) ||
|
||||
(b.name().toUpper().startsWith("DHZ-")) || // JK fitness 577
|
||||
(b.name().toUpper().startsWith("MKSM")) || // MKSM3600036
|
||||
(b.name().toUpper().startsWith("YS_C1_")) || // Yesoul C1H
|
||||
(b.name().toUpper().startsWith("YS_G1_")) || // Yesoul S3
|
||||
(b.name().toUpper().startsWith("DS25-")) || // Bodytone DS25
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ICONSOLE+")) && toorx_ftms ) ||
|
||||
(b.name().toUpper().startsWith("DI") && b.name().length() == 2) || // Elite smart trainer #1682
|
||||
(b.name().toUpper().startsWith("DHZ-")) || // JK fitness 577
|
||||
(b.name().toUpper().startsWith("MKSM")) || // MKSM3600036
|
||||
(b.name().toUpper().startsWith("YS_C1_")) || // Yesoul C1H
|
||||
(b.name().toUpper().startsWith("YS_G1_")) || // Yesoul S3
|
||||
(b.name().toUpper().startsWith("DS25-")) || // Bodytone DS25
|
||||
(b.name().toUpper().startsWith("SCHWINN 510T")) ||
|
||||
(b.name().toUpper().startsWith("3G CARDIO ")) ||
|
||||
(b.name().toUpper().startsWith("ZWIFT HUB")) || (b.name().toUpper().startsWith("MAGNUS ")) ||
|
||||
(b.name().toUpper().startsWith("HAMMER ")) || // HAMMER 64123
|
||||
(b.name().toUpper().startsWith("HAMMER ") && !power_as_bike && !saris_trainer) || // HAMMER 64123
|
||||
(b.name().toUpper().startsWith("FLXCY-")) || // Pro FlexBike
|
||||
(b.name().toUpper().startsWith("QB-WC01")) || // Nexgim QB-C01 smart bike
|
||||
(b.name().toUpper().startsWith("XBR55")) || // Sprint XBR555
|
||||
(b.name().toUpper().startsWith("ECHO_BIKE_")) || // Rogue echo bike V3.0
|
||||
(b.name().toUpper().startsWith("EW-JS-")) || // EW-JS-4990
|
||||
(b.name().toUpper().startsWith("DT-") && b.name().length() >= 14) || // SOLE SB700
|
||||
(b.name().toUpper().startsWith("YSV") && b.name().length() == 9) || // YSV100783
|
||||
(b.name().toUpper().startsWith("URSB") && b.name().length() == 7) || // URSB005
|
||||
(b.name().toUpper().startsWith("DBF") && b.name().length() == 6) || // DBF135
|
||||
(b.name().toUpper().startsWith("KSU") && b.name().length() == 7) || // KSU1102
|
||||
(b.name().toUpper().startsWith(ftmsAccessoryName.toUpper()) &&
|
||||
settings.value(QZSettings::ss2k_peloton, QZSettings::default_ss2k_peloton)
|
||||
.toBool()) || // ss2k on a peloton bike
|
||||
(b.name().toUpper().startsWith("KICKR CORE")) ||
|
||||
((b.name().toUpper().startsWith("KICKR CORE")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
|
||||
(b.name().toUpper().startsWith("MERACH-MR667-")) ||
|
||||
(b.name().toUpper().startsWith("DS60-")) ||
|
||||
(b.name().toUpper().startsWith("BIKE-")) ||
|
||||
(b.name().toUpper().startsWith("SPAX-BK-")) ||
|
||||
(b.name().toUpper().startsWith("YSV1")) ||
|
||||
(b.name().toUpper().startsWith("ZYCLEZBIKE")) ||
|
||||
(b.name().toUpper().startsWith("DOMYOS-BIKING-")) ||
|
||||
(b.name().toUpper().startsWith("ICSE") && b.name().length() == 4) ||
|
||||
(b.name().toUpper().startsWith("CSRB") && b.name().length() == 11) ||
|
||||
(b.name().toUpper().startsWith("DU30-")) || // BodyTone du30
|
||||
(b.name().toUpper().startsWith("ZUMO")) || (b.name().toUpper().startsWith("XS08-")) ||
|
||||
(b.name().toUpper().startsWith("B94")) || (b.name().toUpper().startsWith("STAGES BIKE")) ||
|
||||
(b.name().toUpper().startsWith("SUITO")) || (b.name().toUpper().startsWith("D2RIDE")) ||
|
||||
(b.name().toUpper().startsWith("DIRETO XR")) || (b.name().toUpper().startsWith("SMB1")) ||
|
||||
(b.name().toUpper().startsWith("INRIDE"))) &&
|
||||
(b.name().toUpper().startsWith("DIRETO XR")) || (b.name().toUpper().startsWith("MERACH-667-")) ||
|
||||
!b.name().compare(ftms_bike, Qt::CaseInsensitive) || (b.name().toUpper().startsWith("SMB1")) ||
|
||||
(b.name().toUpper().startsWith("UBIKE FTMS")) || (b.name().toUpper().startsWith("INRIDE"))) &&
|
||||
!ftmsBike && !snodeBike && !fitPlusBike && !stagesBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
@@ -1330,6 +1453,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(ftmsBike);
|
||||
} else if ((b.name().toUpper().startsWith("KICKR SNAP") || b.name().toUpper().startsWith("KICKR BIKE") ||
|
||||
b.name().toUpper().startsWith("KICKR ROLLR") ||
|
||||
(b.name().toUpper().startsWith("HAMMER ") && saris_trainer) ||
|
||||
(b.name().toUpper().startsWith("WAHOO KICKR"))) &&
|
||||
!wahooKickrSnapBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1358,6 +1482,9 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
horizonGr7Bike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(horizonGr7Bike);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("STAGES ")) ||
|
||||
(b.name().toUpper().startsWith("TACX SATORI")) ||
|
||||
((b.name().toUpper().startsWith("KICKR CORE")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826)) && deviceHasService(b, QBluetoothUuid((quint16)0x1818))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("QD")) && b.name().length() == 2) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ASSIOMA")) &&
|
||||
powerSensorName.startsWith(QStringLiteral("Disabled")))) &&
|
||||
!stagesBike && !ftmsBike && filter) {
|
||||
@@ -1411,6 +1538,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-WLT")) || // KS-WLT-W1
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-ROWER")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("SF-RW")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("DFIT-L-R")) ||
|
||||
!b.name().compare(ftms_rower, Qt::CaseInsensitive) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("PM5")) &&
|
||||
b.name().toUpper().endsWith(QStringLiteral("ROW")))) &&
|
||||
@@ -1429,6 +1557,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(ftmsRower);
|
||||
} else if ((b.name().toUpper().startsWith(QLatin1String("ECH-STRIDE")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("ECH-UK-")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("ECH-FR-")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("STRIDE-")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("ECH-SD-SPT"))) &&
|
||||
!echelonStride && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1591,7 +1721,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
} else if (b.name().toUpper().startsWith(QStringLiteral("EW-BK")) && !sportsTechBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
sportsTechBike = new sportstechbike(noWriteResistance, noHeartService);
|
||||
sportsTechBike = new sportstechbike(noWriteResistance, noHeartService, bikeResistanceOffset,
|
||||
bikeResistanceGain);
|
||||
// stateFileRead();
|
||||
emit deviceConnected(b);
|
||||
connect(sportsTechBike, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
@@ -1621,7 +1752,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
// SLOT(inclinationChanged(double)));
|
||||
sportsPlusBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(sportsPlusBike);
|
||||
} else if (b.name().startsWith(yesoulbike::bluetoothName) && !yesoulBike && filter) {
|
||||
} else if ((b.name().startsWith(yesoulbike::bluetoothName) ||
|
||||
b.name().toUpper().startsWith("YS_G1M_")) && !yesoulBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
yesoulBike =
|
||||
@@ -1636,7 +1768,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
// SLOT(inclinationChanged(double)));
|
||||
yesoulBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(yesoulBike);
|
||||
} else if ((b.name().startsWith(QStringLiteral("I_EB")) || b.name().startsWith(QStringLiteral("I_SB"))) &&
|
||||
} else if ((b.name().startsWith(QStringLiteral("I_EB")) || b.name().startsWith(QStringLiteral("I_SB")) ||
|
||||
b.name().toUpper().contains(QStringLiteral("_IFIT_BIKE"))) &&
|
||||
!proformBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
@@ -1762,7 +1895,8 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
// SLOT(inclinationChanged(double)));
|
||||
mcfBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(mcfBike);
|
||||
} else if ((b.name().startsWith(QStringLiteral("TRX ROUTE KEY"))) && !toorx && filter) {
|
||||
} else if ((b.name().startsWith(QStringLiteral("TRX ROUTE KEY")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("BH-TR-"))) && !toorx && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
toorx = new toorxtreadmill();
|
||||
@@ -1831,6 +1965,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ICONSOLE+"))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("I-RUNNING"))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("DKN RUN"))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ADIDAS "))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("REEBOK")))) &&
|
||||
!trxappgateusb && !trxappgateusbBike && !toorx_bike && !toorx_ftms && !toorx_ftms_treadmill &&
|
||||
filter) {
|
||||
@@ -1845,16 +1980,20 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
trxappgateusb->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(trxappgateusb);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("TUN ")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("FITHIWAY")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("FIT HI WAY")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("PASYOU-")) ||
|
||||
((b.name().startsWith(QStringLiteral("TOORX")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-CONSOIE+")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("IBIKING+")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("ICONSOLE+")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("VIFHTR2.1")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("REEBOK"))) ||
|
||||
b.name().toUpper().contains(QStringLiteral("CR011R")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("DKN MOTION"))) &&
|
||||
(toorx_bike))) &&
|
||||
!trxappgateusb && !toorx_ftms_treadmill && !trxappgateusbBike && filter) {
|
||||
!trxappgateusb && !toorx_ftms && !toorx_ftms_treadmill && !trxappgateusbBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
trxappgateusbBike =
|
||||
@@ -1915,6 +2054,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
skandikaWiriBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(skandikaWiriBike);
|
||||
} else if (((b.name().toUpper().startsWith("RQ") && b.name().length() == 5) ||
|
||||
(b.name().toUpper().startsWith("R-Q") && b.name().length() > 6) ||
|
||||
(b.name().toUpper().startsWith("SCH130")) || // not a renpho bike an FTMS one
|
||||
((b.name().startsWith(QStringLiteral("TOORX"))) && toorx_ftms && !toorx_ftms_treadmill)) &&
|
||||
!renphoBike && !snodeBike && !fitPlusBike && filter) {
|
||||
@@ -1954,7 +2094,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(snodeBike);
|
||||
} else if (((b.name().startsWith(QStringLiteral("FS-")) && fitplus_bike) ||
|
||||
b.name().startsWith(QStringLiteral("MRK-"))) &&
|
||||
!fitPlusBike && !ftmsBike && !snodeBike && filter) {
|
||||
!fitPlusBike && !ftmsBike && !ftmsRower && !snodeBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
fitPlusBike =
|
||||
@@ -1967,13 +2107,27 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
// connect(fitPlusBike, SIGNAL(debug(QString)), this, SLOT(debug(QString)));
|
||||
fitPlusBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(fitPlusBike);
|
||||
} else if (((b.name().startsWith(QStringLiteral("FS-")) && !snode_bike && !fitplus_bike && !ftmsBike) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) || // FTMS
|
||||
} else if (b.name().toUpper().startsWith(QStringLiteral("EW-TM-")) &&
|
||||
!focusTreadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
focusTreadmill = new focustreadmill(this->pollDeviceTime, noConsole, noHeartService);
|
||||
emit deviceConnected(b);
|
||||
connect(focusTreadmill, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
connect(focusTreadmill, &focustreadmill::debug, this, &bluetooth::debug);
|
||||
focusTreadmill->deviceDiscovered(b);
|
||||
connect(this, &bluetooth::searchingStop, focusTreadmill, &focustreadmill::searchingStop);
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive())
|
||||
emit searchingStop();
|
||||
this->signalBluetoothDeviceConnected(focusTreadmill);
|
||||
} else if (((b.name().startsWith(QStringLiteral("FS-")) && !horizonTreadmill && !snode_bike && !fitplus_bike && !ftmsBike && !iconsole_elliptical) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) && !deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // FTMS
|
||||
(b.name().startsWith(QStringLiteral("SW")) && b.name().length() == 14 &&
|
||||
!b.name().contains('(') && !b.name().contains(')')) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("WINFITA"))) || // also FTMS
|
||||
(b.name().startsWith(QStringLiteral("BF70")))) &&
|
||||
!fitshowTreadmill && filter) {
|
||||
!fitshowTreadmill && !iconsole_elliptical && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
fitshowTreadmill = new fitshowtreadmill(this->pollDeviceTime, noConsole, noHeartService);
|
||||
@@ -2183,6 +2337,16 @@ void bluetooth::connectedAndDiscovered() {
|
||||
f->deviceDiscovered(b);
|
||||
wahookickrHeadWind.append(f);
|
||||
break;
|
||||
} else if (((b.name().toUpper().startsWith("ARIA")) && b.name().length() == 4) && !fitmetria_fanfit_isconnected(b.name())) {
|
||||
eliteariafan *f = new eliteariafan(this->device());
|
||||
|
||||
connect(f, &eliteariafan::debug, this, &bluetooth::debug);
|
||||
|
||||
connect(this->device(), SIGNAL(fanSpeedChanged(uint8_t)), f, SLOT(fanSpeedRequest(uint8_t)));
|
||||
|
||||
f->deviceDiscovered(b);
|
||||
eliteAriaFan.append(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2299,16 +2463,62 @@ void bluetooth::connectedAndDiscovered() {
|
||||
}
|
||||
}
|
||||
|
||||
if(settings.value(QZSettings::zwift_click, QZSettings::default_zwift_click).toBool()) {
|
||||
for (const QBluetoothDeviceInfo &b : qAsConst(devices)) {
|
||||
if (((b.name().toUpper().startsWith("ZWIFT CLICK"))) && !zwiftClickRemote && this->device() &&
|
||||
this->device()->deviceType() == bluetoothdevice::BIKE) {
|
||||
|
||||
if(b.manufacturerData(2378).size() > 0) {
|
||||
qDebug() << "this should be 9. is it? " << int(b.manufacturerData(2378).at(0));
|
||||
} else {
|
||||
qDebug() << "manufacturer not found for ZWIFT CLICK";
|
||||
}
|
||||
|
||||
zwiftClickRemote = new zwiftclickremote(this->device(), AbstractZapDevice::ZWIFT_PLAY_TYPE::NONE);
|
||||
// connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
|
||||
connect(zwiftClickRemote, &zwiftclickremote::debug, this, &bluetooth::debug);
|
||||
connect(zwiftClickRemote->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp);
|
||||
connect(zwiftClickRemote->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown);
|
||||
zwiftClickRemote->deviceDiscovered(b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(settings.value(QZSettings::zwift_play, QZSettings::default_zwift_play).toBool()) {
|
||||
for (const QBluetoothDeviceInfo &b : qAsConst(devices)) {
|
||||
if (((b.name().toUpper().startsWith("ZWIFT PLAY"))) && zwiftPlayDevice.size() < 2 && this->device() &&
|
||||
this->device()->deviceType() == bluetoothdevice::BIKE) {
|
||||
|
||||
if(b.manufacturerData(2378).size() > 0) {
|
||||
qDebug() << "this should be 3 or 2. is it? " << int(b.manufacturerData(2378).at(0));
|
||||
} else {
|
||||
qDebug() << "manufacturer not found for ZWIFT CLICK";
|
||||
}
|
||||
zwiftPlayDevice.append(new zwiftclickremote(this->device(),
|
||||
int(b.manufacturerData(2378).at(0)) == 3 ? AbstractZapDevice::ZWIFT_PLAY_TYPE::LEFT : AbstractZapDevice::ZWIFT_PLAY_TYPE::RIGHT));
|
||||
// connect(heartRateBelt, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
|
||||
connect(zwiftPlayDevice.last(), &zwiftclickremote::debug, this, &bluetooth::debug);
|
||||
connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::plus, (bike*)this->device(), &bike::gearUp);
|
||||
connect(zwiftPlayDevice.last()->playDevice, &ZwiftPlayDevice::minus, (bike*)this->device(), &bike::gearDown);
|
||||
zwiftPlayDevice.last()->deviceDiscovered(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_cadence, QZSettings::default_ant_cadence).toBool() ||
|
||||
settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative",
|
||||
"activity", "()Landroid/app/Activity;");
|
||||
KeepAwakeHelper::antObject(true)->callMethod<void>(
|
||||
"antStart", "(Landroid/app/Activity;ZZZ)V", activity.object<jobject>(),
|
||||
"antStart", "(Landroid/app/Activity;ZZZZ)V", activity.object<jobject>(),
|
||||
settings.value(QZSettings::ant_cadence, QZSettings::default_ant_cadence).toBool(),
|
||||
settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool(),
|
||||
settings.value(QZSettings::ant_garmin, QZSettings::default_ant_garmin).toBool());
|
||||
settings.value(QZSettings::ant_garmin, QZSettings::default_ant_garmin).toBool(),
|
||||
device()->deviceType() == bluetoothdevice::TREADMILL ||
|
||||
device()->deviceType() == bluetoothdevice::ELLIPTICAL);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::android_notification, QZSettings::default_android_notification).toBool()) {
|
||||
@@ -2402,6 +2612,11 @@ void bluetooth::restart() {
|
||||
delete fitshowTreadmill;
|
||||
fitshowTreadmill = nullptr;
|
||||
}
|
||||
if (focusTreadmill) {
|
||||
|
||||
delete focusTreadmill;
|
||||
focusTreadmill = nullptr;
|
||||
}
|
||||
if (horizonTreadmill) {
|
||||
|
||||
delete horizonTreadmill;
|
||||
@@ -2507,6 +2722,11 @@ void bluetooth::restart() {
|
||||
delete proformWifiBike;
|
||||
proformWifiBike = nullptr;
|
||||
}
|
||||
if (proformTelnetBike) {
|
||||
|
||||
delete proformTelnetBike;
|
||||
proformTelnetBike = nullptr;
|
||||
}
|
||||
if (proformWifiTreadmill) {
|
||||
|
||||
delete proformWifiTreadmill;
|
||||
@@ -2603,6 +2823,11 @@ void bluetooth::restart() {
|
||||
delete trxappgateusbBike;
|
||||
trxappgateusbBike = nullptr;
|
||||
}
|
||||
if (trxappgateusbElliptical) {
|
||||
|
||||
delete trxappgateusbElliptical;
|
||||
trxappgateusbElliptical = nullptr;
|
||||
}
|
||||
if (soleBike) {
|
||||
|
||||
delete soleBike;
|
||||
@@ -2853,6 +3078,14 @@ void bluetooth::restart() {
|
||||
}
|
||||
wahookickrHeadWind.clear();
|
||||
}
|
||||
if (eliteAriaFan.length()) {
|
||||
|
||||
foreach (eliteariafan *f, eliteAriaFan) {
|
||||
delete f;
|
||||
f = nullptr;
|
||||
}
|
||||
eliteAriaFan.clear();
|
||||
}
|
||||
if (cadenceSensor) {
|
||||
|
||||
// heartRateBelt->disconnectBluetooth(); // to test
|
||||
@@ -2896,6 +3129,8 @@ bluetoothdevice *bluetooth::device() {
|
||||
return domyosRower;
|
||||
} else if (fitshowTreadmill) {
|
||||
return fitshowTreadmill;
|
||||
} else if (focusTreadmill) {
|
||||
return focusTreadmill;
|
||||
} else if (domyosElliptical) {
|
||||
return domyosElliptical;
|
||||
} else if (ypooElliptical) {
|
||||
@@ -2912,6 +3147,8 @@ bluetoothdevice *bluetooth::device() {
|
||||
return cscBike;
|
||||
} else if (proformWifiBike) {
|
||||
return proformWifiBike;
|
||||
} else if (proformTelnetBike) {
|
||||
return proformTelnetBike;
|
||||
} else if (proformWifiTreadmill) {
|
||||
return proformWifiTreadmill;
|
||||
} else if (nordictrackifitadbTreadmill) {
|
||||
@@ -2950,6 +3187,8 @@ bluetoothdevice *bluetooth::device() {
|
||||
return trxappgateusb;
|
||||
} else if (trxappgateusbBike) {
|
||||
return trxappgateusbBike;
|
||||
} else if (trxappgateusbElliptical) {
|
||||
return trxappgateusbElliptical;
|
||||
} else if (soleBike) {
|
||||
return soleBike;
|
||||
} else if (keepBike) {
|
||||
@@ -3181,6 +3420,10 @@ bool bluetooth::fitmetria_fanfit_isconnected(QString name) {
|
||||
if (!name.compare(f->bluetoothDevice.name()))
|
||||
return true;
|
||||
}
|
||||
foreach (eliteariafan *f, eliteAriaFan) {
|
||||
if (!name.compare(f->bluetoothDevice.name()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -17,114 +17,121 @@
|
||||
#include <QtCore/qbytearray.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
#include "discoveryoptions.h"
|
||||
#include "devices/discoveryoptions.h"
|
||||
#include "qzsettings.h"
|
||||
|
||||
#include "activiotreadmill.h"
|
||||
#include "apexbike.h"
|
||||
#include "bhfitnesselliptical.h"
|
||||
#include "bkoolbike.h"
|
||||
#include "bluetoothdevice.h"
|
||||
#include "bowflext216treadmill.h"
|
||||
#include "bowflextreadmill.h"
|
||||
#include "chronobike.h"
|
||||
#include "devices/activiotreadmill/activiotreadmill.h"
|
||||
#include "devices/apexbike/apexbike.h"
|
||||
#include "devices/bhfitnesselliptical/bhfitnesselliptical.h"
|
||||
#include "devices/bkoolbike/bkoolbike.h"
|
||||
#include "devices/bluetoothdevice.h"
|
||||
#include "devices/bowflext216treadmill/bowflext216treadmill.h"
|
||||
#include "devices/bowflextreadmill/bowflextreadmill.h"
|
||||
#include "devices/chronobike/chronobike.h"
|
||||
#ifndef Q_OS_IOS
|
||||
#include "computrainerbike.h"
|
||||
#include "csaferower.h"
|
||||
#include "devices/computrainerbike/computrainerbike.h"
|
||||
#include "devices/csaferower/csaferower.h"
|
||||
#endif
|
||||
#include "concept2skierg.h"
|
||||
#include "cscbike.h"
|
||||
#include "domyosbike.h"
|
||||
#include "domyoselliptical.h"
|
||||
#include "domyosrower.h"
|
||||
#include "domyostreadmill.h"
|
||||
#include "devices/concept2skierg/concept2skierg.h"
|
||||
#include "devices/cscbike/cscbike.h"
|
||||
#include "devices/domyosbike/domyosbike.h"
|
||||
#include "devices/domyoselliptical/domyoselliptical.h"
|
||||
#include "devices/domyosrower/domyosrower.h"
|
||||
#include "devices/domyostreadmill/domyostreadmill.h"
|
||||
|
||||
#include "echelonconnectsport.h"
|
||||
#include "echelonrower.h"
|
||||
#include "eliterizer.h"
|
||||
#include "elitesterzosmart.h"
|
||||
#include "eslinkertreadmill.h"
|
||||
#include "fakebike.h"
|
||||
#include "fakeelliptical.h"
|
||||
#include "fakerower.h"
|
||||
#include "faketreadmill.h"
|
||||
#include "fitmetria_fanfit.h"
|
||||
#include "fitplusbike.h"
|
||||
#include "devices/echelonconnectsport/echelonconnectsport.h"
|
||||
#include "devices/echelonrower/echelonrower.h"
|
||||
#include "devices/eliteariafan/eliteariafan.h"
|
||||
#include "devices/eliterizer/eliterizer.h"
|
||||
#include "devices/elitesterzosmart/elitesterzosmart.h"
|
||||
#include "devices/eslinkertreadmill/eslinkertreadmill.h"
|
||||
#include "devices/fakebike/fakebike.h"
|
||||
#include "devices/fakeelliptical/fakeelliptical.h"
|
||||
#include "devices/fakerower/fakerower.h"
|
||||
#include "devices/faketreadmill/faketreadmill.h"
|
||||
#include "devices/fitmetria_fanfit/fitmetria_fanfit.h"
|
||||
#include "devices/fitplusbike/fitplusbike.h"
|
||||
|
||||
#include "fitshowtreadmill.h"
|
||||
#include "flywheelbike.h"
|
||||
#include "ftmsbike.h"
|
||||
#include "ftmsrower.h"
|
||||
#include "heartratebelt.h"
|
||||
#include "horizongr7bike.h"
|
||||
#include "horizontreadmill.h"
|
||||
#include "iconceptbike.h"
|
||||
#include "iconceptelliptical.h"
|
||||
#include "inspirebike.h"
|
||||
#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 "nordictrackifitadbbike.h"
|
||||
#include "nordictrackifitadbtreadmill.h"
|
||||
#include "npecablebike.h"
|
||||
#include "octaneelliptical.h"
|
||||
#include "octanetreadmill.h"
|
||||
#include "pafersbike.h"
|
||||
#include "paferstreadmill.h"
|
||||
#include "pelotonbike.h"
|
||||
#include "proformbike.h"
|
||||
#include "proformelliptical.h"
|
||||
#include "proformellipticaltrainer.h"
|
||||
#include "proformrower.h"
|
||||
#include "proformtreadmill.h"
|
||||
#include "proformwifibike.h"
|
||||
#include "proformwifitreadmill.h"
|
||||
#include "schwinn170bike.h"
|
||||
#include "schwinnic4bike.h"
|
||||
#include "devices/fitshowtreadmill/fitshowtreadmill.h"
|
||||
#include "devices/flywheelbike/flywheelbike.h"
|
||||
#include "devices/ftmsbike/ftmsbike.h"
|
||||
#include "devices/ftmsrower/ftmsrower.h"
|
||||
#include "devices/focustreadmill/focustreadmill.h"
|
||||
#include "devices/heartratebelt/heartratebelt.h"
|
||||
#include "devices/horizongr7bike/horizongr7bike.h"
|
||||
#include "devices/horizontreadmill/horizontreadmill.h"
|
||||
#include "devices/iconceptbike/iconceptbike.h"
|
||||
#include "devices/iconceptelliptical/iconceptelliptical.h"
|
||||
#include "devices/inspirebike/inspirebike.h"
|
||||
#include "devices/keepbike/keepbike.h"
|
||||
#include "devices/kingsmithr1protreadmill/kingsmithr1protreadmill.h"
|
||||
#include "devices/kingsmithr2treadmill/kingsmithr2treadmill.h"
|
||||
#include "devices/lifefitnesstreadmill/lifefitnesstreadmill.h"
|
||||
#include "devices/m3ibike/m3ibike.h"
|
||||
#include "devices/mcfbike/mcfbike.h"
|
||||
#include "devices/mepanelbike/mepanelbike.h"
|
||||
#include "devices/nautilusbike/nautilusbike.h"
|
||||
#include "devices/nautiluselliptical/nautiluselliptical.h"
|
||||
#include "devices/nautilustreadmill/nautilustreadmill.h"
|
||||
#include "devices/nordictrackelliptical/nordictrackelliptical.h"
|
||||
#include "devices/nordictrackifitadbbike/nordictrackifitadbbike.h"
|
||||
#include "devices/nordictrackifitadbtreadmill/nordictrackifitadbtreadmill.h"
|
||||
#include "devices/npecablebike/npecablebike.h"
|
||||
#include "devices/octaneelliptical/octaneelliptical.h"
|
||||
#include "devices/octanetreadmill/octanetreadmill.h"
|
||||
#include "devices/pafersbike/pafersbike.h"
|
||||
#include "devices/paferstreadmill/paferstreadmill.h"
|
||||
#include "devices/pelotonbike/pelotonbike.h"
|
||||
#include "devices/proformbike/proformbike.h"
|
||||
#include "devices/proformelliptical/proformelliptical.h"
|
||||
#include "devices/proformellipticaltrainer/proformellipticaltrainer.h"
|
||||
#include "devices/proformrower/proformrower.h"
|
||||
#include "devices/proformtreadmill/proformtreadmill.h"
|
||||
#include "devices/proformtelnetbike/proformtelnetbike.h"
|
||||
#include "devices/proformwifibike/proformwifibike.h"
|
||||
#include "devices/proformwifitreadmill/proformwifitreadmill.h"
|
||||
#include "devices/schwinn170bike/schwinn170bike.h"
|
||||
#include "devices/schwinnic4bike/schwinnic4bike.h"
|
||||
#include "signalhandler.h"
|
||||
#include "skandikawiribike.h"
|
||||
#include "smartrowrower.h"
|
||||
#include "smartspin2k.h"
|
||||
#include "snodebike.h"
|
||||
#include "strydrunpowersensor.h"
|
||||
#include "devices/skandikawiribike/skandikawiribike.h"
|
||||
#include "devices/smartrowrower/smartrowrower.h"
|
||||
#include "devices/smartspin2k/smartspin2k.h"
|
||||
#include "devices/snodebike/snodebike.h"
|
||||
#include "devices/strydrunpowersensor/strydrunpowersensor.h"
|
||||
|
||||
#include "shuaa5treadmill.h"
|
||||
#include "solebike.h"
|
||||
#include "soleelliptical.h"
|
||||
#include "solef80treadmill.h"
|
||||
#include "devices/shuaa5treadmill/shuaa5treadmill.h"
|
||||
#include "devices/solebike/solebike.h"
|
||||
#include "devices/soleelliptical/soleelliptical.h"
|
||||
#include "devices/solef80treadmill/solef80treadmill.h"
|
||||
|
||||
#include "spirittreadmill.h"
|
||||
#include "sportsplusbike.h"
|
||||
#include "sportstechbike.h"
|
||||
#include "stagesbike.h"
|
||||
#include "devices/spirittreadmill/spirittreadmill.h"
|
||||
#include "devices/sportsplusbike/sportsplusbike.h"
|
||||
#include "devices/sportstechbike/sportstechbike.h"
|
||||
#include "devices/stagesbike/stagesbike.h"
|
||||
|
||||
#include "renphobike.h"
|
||||
#include "tacxneo2.h"
|
||||
#include "technogymmyruntreadmill.h"
|
||||
#include "technogymmyruntreadmillrfcomm.h"
|
||||
#include "devices/renphobike/renphobike.h"
|
||||
#include "devices/tacxneo2/tacxneo2.h"
|
||||
#include "devices/technogymmyruntreadmill/technogymmyruntreadmill.h"
|
||||
#include "devices/technogymmyruntreadmillrfcomm/technogymmyruntreadmillrfcomm.h"
|
||||
|
||||
#include "echelonstride.h"
|
||||
#include "devices/echelonstride/echelonstride.h"
|
||||
|
||||
#include "templateinfosenderbuilder.h"
|
||||
#include "toorxtreadmill.h"
|
||||
#include "treadmill.h"
|
||||
#include "truetreadmill.h"
|
||||
#include "trxappgateusbbike.h"
|
||||
#include "trxappgateusbtreadmill.h"
|
||||
#include "ultrasportbike.h"
|
||||
#include "wahookickrheadwind.h"
|
||||
#include "wahookickrsnapbike.h"
|
||||
#include "yesoulbike.h"
|
||||
#include "ypooelliptical.h"
|
||||
#include "ziprotreadmill.h"
|
||||
#include "devices/toorxtreadmill/toorxtreadmill.h"
|
||||
#include "devices/treadmill.h"
|
||||
#include "devices/truetreadmill/truetreadmill.h"
|
||||
#include "devices/trxappgateusbbike/trxappgateusbbike.h"
|
||||
#include "devices/trxappgateusbelliptical/trxappgateusbelliptical.h"
|
||||
#include "devices/trxappgateusbtreadmill/trxappgateusbtreadmill.h"
|
||||
#include "devices/ultrasportbike/ultrasportbike.h"
|
||||
#include "devices/wahookickrheadwind/wahookickrheadwind.h"
|
||||
#include "devices/wahookickrsnapbike/wahookickrsnapbike.h"
|
||||
#include "devices/yesoulbike/yesoulbike.h"
|
||||
#include "devices/ypooelliptical/ypooelliptical.h"
|
||||
#include "devices/ziprotreadmill/ziprotreadmill.h"
|
||||
|
||||
#include "zwift_play/zwiftPlayDevice.h"
|
||||
#include "zwift_play/zwiftclickremote.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
@@ -145,6 +152,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
bluetoothdevice *heartRateDevice() { return heartRateBelt; }
|
||||
QList<QBluetoothDeviceInfo> devices;
|
||||
bool onlyDiscover = false;
|
||||
volatile bool homeformLoaded = false;
|
||||
|
||||
private:
|
||||
bool useDiscovery = false;
|
||||
@@ -156,6 +164,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
bowflextreadmill *bowflexTreadmill = nullptr;
|
||||
bowflext216treadmill *bowflexT216Treadmill = nullptr;
|
||||
fitshowtreadmill *fitshowTreadmill = nullptr;
|
||||
focustreadmill *focusTreadmill = nullptr;
|
||||
#ifndef Q_OS_IOS
|
||||
computrainerbike *computrainerBike = nullptr;
|
||||
csaferower *csafeRower = nullptr;
|
||||
@@ -175,6 +184,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
nautiluselliptical *nautilusElliptical = nullptr;
|
||||
nautilustreadmill *nautilusTreadmill = nullptr;
|
||||
trxappgateusbbike *trxappgateusbBike = nullptr;
|
||||
trxappgateusbelliptical *trxappgateusbElliptical = nullptr;
|
||||
echelonconnectsport *echelonConnectSport = nullptr;
|
||||
yesoulbike *yesoulBike = nullptr;
|
||||
flywheelbike *flywheelBike = nullptr;
|
||||
@@ -186,6 +196,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
pelotonbike *pelotonBike = nullptr;
|
||||
proformrower *proformRower = nullptr;
|
||||
proformbike *proformBike = nullptr;
|
||||
proformtelnetbike *proformTelnetBike = nullptr;
|
||||
proformwifibike *proformWifiBike = nullptr;
|
||||
proformwifitreadmill *proformWifiTreadmill = nullptr;
|
||||
proformelliptical *proformElliptical = nullptr;
|
||||
@@ -250,6 +261,9 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
faketreadmill *fakeTreadmill = nullptr;
|
||||
QList<fitmetria_fanfit *> fitmetriaFanfit;
|
||||
QList<wahookickrheadwind *> wahookickrHeadWind;
|
||||
QList<eliteariafan *> eliteAriaFan;
|
||||
QList<zwiftclickremote* > zwiftPlayDevice;
|
||||
zwiftclickremote* zwiftClickRemote = nullptr;
|
||||
QString filterDevice = QLatin1String("");
|
||||
|
||||
bool testResistance = false;
|
||||
@@ -273,6 +287,7 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
void stopDiscovery();
|
||||
|
||||
bool handleSignal(int signal) override;
|
||||
bool deviceHasService(const QBluetoothDeviceInfo &device, QBluetoothUuid service);
|
||||
void stateFileUpdate();
|
||||
void stateFileRead();
|
||||
bool heartRateBeltAvaiable();
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "bluetoothdevice.h"
|
||||
#include "devices/bluetoothdevice.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
@@ -106,6 +106,7 @@ QTime bluetoothdevice::maxPace() {
|
||||
}
|
||||
}
|
||||
|
||||
double bluetoothdevice::odometerFromStartup() { return Distance.valueRaw(); }
|
||||
double bluetoothdevice::odometer() { return Distance.value(); }
|
||||
metric bluetoothdevice::calories() { return KCal; }
|
||||
metric bluetoothdevice::jouls() { return m_jouls; }
|
||||
@@ -180,6 +181,9 @@ void bluetoothdevice::update_metrics(bool watt_calc, const double watts) {
|
||||
bool power_as_treadmill =
|
||||
settings.value(QZSettings::power_sensor_as_treadmill, QZSettings::default_power_sensor_as_treadmill).toBool();
|
||||
|
||||
if(deviceType() == bluetoothdevice::BIKE)
|
||||
_ergTable.collectData(Cadence.value(), m_watt.value(), Resistance.value());
|
||||
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
.toString()
|
||||
.startsWith(QStringLiteral("Disabled")) == false &&
|
||||
@@ -247,9 +251,18 @@ void bluetoothdevice::update_hr_from_external() {
|
||||
long appleWatchHeartRate = h.heartRate();
|
||||
h.setKcal(KCal.value());
|
||||
h.setDistance(Distance.value());
|
||||
h.setSpeed(Speed.value());
|
||||
h.setPower(m_watt.value());
|
||||
h.setCadence(Cadence.value());
|
||||
Heart = appleWatchHeartRate;
|
||||
qDebug() << "Current Heart from Apple Watch: " << QString::number(appleWatchHeartRate);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (!settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
Heart = QAndroidJniObject::callStaticMethod<jint>("org/cagnulen/qdomyoszwift/WearableController", "getHeart", "()I");
|
||||
qDebug() << "WearOS Companion Heart:" << Heart.value();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -261,6 +274,7 @@ void bluetoothdevice::clearStats() {
|
||||
Speed.clear(false);
|
||||
KCal.clear(true);
|
||||
Distance.clear(true);
|
||||
Distance1s.clear(true);
|
||||
Heart.clear(false);
|
||||
m_jouls.clear(true);
|
||||
elevationAcc = 0;
|
||||
@@ -268,6 +282,9 @@ void bluetoothdevice::clearStats() {
|
||||
WeightLoss.clear(false);
|
||||
WattKg.clear(false);
|
||||
Cadence.clear(false);
|
||||
for(int i=0; i<maxHeartZone(); i++) {
|
||||
hrZonesSeconds[i].clear(false);
|
||||
}
|
||||
}
|
||||
|
||||
void bluetoothdevice::setPaused(bool p) {
|
||||
@@ -278,12 +295,16 @@ void bluetoothdevice::setPaused(bool p) {
|
||||
Speed.setPaused(p);
|
||||
KCal.setPaused(p);
|
||||
Distance.setPaused(p);
|
||||
Distance1s.setPaused(p);
|
||||
Heart.setPaused(p);
|
||||
m_jouls.setPaused(p);
|
||||
m_watt.setPaused(p);
|
||||
WeightLoss.setPaused(p);
|
||||
WattKg.setPaused(p);
|
||||
Cadence.setPaused(p);
|
||||
for(int i=0; i<maxHeartZone(); i++) {
|
||||
hrZonesSeconds[i].setPaused(p);
|
||||
}
|
||||
}
|
||||
|
||||
void bluetoothdevice::setLap() {
|
||||
@@ -293,12 +314,16 @@ void bluetoothdevice::setLap() {
|
||||
Speed.setLap(false);
|
||||
KCal.setLap(true);
|
||||
Distance.setLap(true);
|
||||
Distance1s.setLap(true);
|
||||
Heart.setLap(false);
|
||||
m_jouls.setLap(true);
|
||||
m_watt.setLap(false);
|
||||
WeightLoss.setLap(false);
|
||||
WattKg.setLap(false);
|
||||
Cadence.setLap(false);
|
||||
for(int i=0; i<maxHeartZone(); i++) {
|
||||
hrZonesSeconds[i].setLap(false);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList bluetoothdevice::metrics() {
|
||||
@@ -447,3 +472,24 @@ void bluetoothdevice::setGPXFile(QString filename) {
|
||||
input.close();
|
||||
}
|
||||
}
|
||||
|
||||
void bluetoothdevice::setHeartZone(double hz) {
|
||||
HeartZone = hz;
|
||||
if(isPaused() == false) {
|
||||
hz = hz - 1;
|
||||
if(hz >= maxHeartZone() ) {
|
||||
hrZonesSeconds[maxHeartZone() - 1].setValue(hrZonesSeconds[maxHeartZone() - 1].value() + 1);
|
||||
} else if(hz <= 0) {
|
||||
hrZonesSeconds[0].setValue(hrZonesSeconds[0].value() + 1);
|
||||
} else {
|
||||
hrZonesSeconds[(int)hz].setValue(hrZonesSeconds[(int)hz].value() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t bluetoothdevice::secondsForHeartZone(uint8_t zone) {
|
||||
if(zone < maxHeartZone()) {
|
||||
return hrZonesSeconds[zone].value();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "definitions.h"
|
||||
#include "metric.h"
|
||||
#include "qzsettings.h"
|
||||
#include "ergtable.h"
|
||||
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QBluetoothDeviceInfo>
|
||||
@@ -22,7 +23,7 @@
|
||||
#include <QtBluetooth/qlowenergyservice.h>
|
||||
#include <QtBluetooth/qlowenergyservicedata.h>
|
||||
|
||||
#include "virtualdevice.h"
|
||||
#include "virtualdevices/virtualdevice.h"
|
||||
|
||||
#if defined(Q_OS_IOS)
|
||||
#define SAME_BLUETOOTH_DEVICE(d1, d2) (d1.deviceUuid() == d2.deviceUuid())
|
||||
@@ -100,6 +101,10 @@ class bluetoothdevice : public QObject {
|
||||
* @return
|
||||
*/
|
||||
virtual double odometer();
|
||||
virtual double odometerFromStartup();
|
||||
virtual metric currentDistance() {return Distance;}
|
||||
virtual metric currentDistance1s() {return Distance1s;}
|
||||
void addCurrentDistance1s(double distance) { Distance1s += distance; }
|
||||
|
||||
/**
|
||||
* @brief calories Gets a metric object to get and set the amount of energy expended.
|
||||
@@ -336,6 +341,18 @@ class bluetoothdevice : public QObject {
|
||||
*/
|
||||
metric currentHeartZone() { return HeartZone; }
|
||||
|
||||
/*
|
||||
* @brief maxHeartZone Gets the maximum number of heart zones.
|
||||
*/
|
||||
uint8_t maxHeartZone() { return maxhrzone; }
|
||||
|
||||
/**
|
||||
* @brief secondsForHeartZone Gets the number of seconds in the current heart zone.
|
||||
*
|
||||
* @param zone The heart zone.
|
||||
*/
|
||||
uint32_t secondsForHeartZone(uint8_t zone);
|
||||
|
||||
/**
|
||||
* @brief currentPowerZone Gets a metric object to get or set the current power zome. Units: depends on
|
||||
* implementation.
|
||||
@@ -368,7 +385,7 @@ class bluetoothdevice : public QObject {
|
||||
* This is equivalent to currentHeartZone().setvalue(hz)
|
||||
* @param hz The heart zone. Unit: depends on implementation.
|
||||
*/
|
||||
void setHeartZone(double hz) { HeartZone = hz; }
|
||||
void setHeartZone(double hz);
|
||||
|
||||
/**
|
||||
* @brief setPowerZone Set the current power zone.
|
||||
@@ -495,6 +512,7 @@ class bluetoothdevice : public QObject {
|
||||
* the length of belt traversed on a treadmill.
|
||||
*/
|
||||
metric Distance;
|
||||
metric Distance1s; // used to populate the distance on the FIT file. Since Strava is using the distance to graph it, it has to have 1s trigger.
|
||||
|
||||
/**
|
||||
* @brief FanSpeed The currently requested fan speed. Units: revolutions per second
|
||||
@@ -636,6 +654,17 @@ class bluetoothdevice : public QObject {
|
||||
*/
|
||||
metric TargetPowerZone;
|
||||
|
||||
/**
|
||||
* @brief _ergTable The current erg table
|
||||
*/
|
||||
ergTable _ergTable;
|
||||
|
||||
/**
|
||||
* @brief Collect the number of seconds in each zone for the current heart rate
|
||||
*/
|
||||
static const uint8_t maxhrzone = 5;
|
||||
metric hrZonesSeconds[maxhrzone];
|
||||
|
||||
bluetoothdevice::WORKOUT_EVENT_STATE lastState;
|
||||
|
||||
/**
|
||||
@@ -696,6 +725,10 @@ class bluetoothdevice : public QObject {
|
||||
*/
|
||||
VIRTUAL_DEVICE_MODE virtualDeviceMode = VIRTUAL_DEVICE_MODE::NONE;
|
||||
virtualdevice *virtualDevice = nullptr;
|
||||
|
||||
protected:
|
||||
// useful to understand if a power sensor device for treadmill, it's a real one like the stryd or it's a dumb one like the runpod from Zwift
|
||||
bool powerReceivedFromPowerSensor = false;
|
||||
};
|
||||
|
||||
#endif // BLUETOOTHDEVICE_H
|
||||
@@ -2,7 +2,7 @@
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "keepawakehelper.h"
|
||||
#endif
|
||||
#include "virtualtreadmill.h"
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -157,11 +157,12 @@ void bowflext216treadmill::update() {
|
||||
requestStart = -1;
|
||||
emit tapeStarted();
|
||||
}
|
||||
if (requestStop != -1) {
|
||||
if (requestStop != -1 || requestPause != -1) {
|
||||
uint8_t stop[] = {0x0a, 0x08, 0x7a, 0x00, 0x19, 0x28, 0x01, 0x32, 0x00, 0x00};
|
||||
emit debug(QStringLiteral("stopping..."));
|
||||
writeCharacteristic(stop, sizeof(stop), QStringLiteral("stop"), false, true);
|
||||
requestStop = -1;
|
||||
requestPause = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -179,11 +180,11 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
|
||||
emit debug(QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' '));
|
||||
emit debug(QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' ') + characteristic.uuid().toString());
|
||||
|
||||
emit packetReceived();
|
||||
|
||||
if (characteristic.uuid() != gattNotify3Characteristic.uuid()) {
|
||||
if (characteristic.uuid() != gattNotify3Characteristic.uuid() && !bowflex_btx116 && !bowflex_t8j) {
|
||||
if (lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()) > 5000) {
|
||||
Speed = 0;
|
||||
qDebug() << QStringLiteral("resetting speed since i'm not receiving metrics in the last 5 seconds");
|
||||
@@ -193,10 +194,12 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
return;
|
||||
}
|
||||
|
||||
if ((newValue.length() != 20))
|
||||
if ((newValue.length() != 20) && bowflex_t8j == false)
|
||||
return;
|
||||
else if ((newValue.length() != 12) && bowflex_t8j == true)
|
||||
return;
|
||||
|
||||
if (bowflex_t6 == true && newValue.at(1) != 0x00)
|
||||
if (bowflex_t6 == true && characteristic.uuid() != QBluetoothUuid(QStringLiteral("a46a4a80-9803-11e3-8f3c-0002a5d5c51b")))
|
||||
return;
|
||||
|
||||
double speed = GetSpeedFromPacket(value);
|
||||
@@ -210,8 +213,9 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/*if(heartRateBeltName.startsWith("Disabled"))
|
||||
Heart = value.at(18);*/
|
||||
if (heartRateBeltName.startsWith(QLatin1String("Disabled"))) {
|
||||
update_hr_from_external();
|
||||
}
|
||||
}
|
||||
emit debug(QStringLiteral("Current speed: ") + QString::number(speed));
|
||||
// emit debug(QStringLiteral("Current incline: ") + QString::number(incline));
|
||||
@@ -263,12 +267,16 @@ void bowflext216treadmill::characteristicChanged(const QLowEnergyCharacteristic
|
||||
}
|
||||
|
||||
double bowflext216treadmill::GetSpeedFromPacket(const QByteArray &packet) {
|
||||
if (bowflex_t6 == false) {
|
||||
uint16_t convertedData = (packet.at(7) << 8) | packet.at(6);
|
||||
if (bowflex_t8j) {
|
||||
uint16_t convertedData = (uint16_t)((uint8_t)packet.at(3)) + ((uint16_t)((uint8_t)packet.at(4)) << 8);
|
||||
double data = (double)convertedData / 100.0f;
|
||||
return data * 1.60934;
|
||||
} else if (bowflex_t6 == false) {
|
||||
uint16_t convertedData = (uint16_t)((uint8_t)packet.at(6)) + (((uint16_t)((uint8_t)packet.at(7)) << 8) & 0xFF00);
|
||||
double data = (double)convertedData / 100.0f;
|
||||
return data * 1.60934;
|
||||
} else {
|
||||
uint16_t convertedData = (uint16_t)((uint8_t)packet.at(9)) + ((uint16_t)((uint8_t)packet.at(10)) << 8);
|
||||
uint16_t convertedData = (uint16_t)((uint8_t)packet.at(9)) + (((uint16_t)((uint8_t)packet.at(10)) << 8) & 0xFF00);
|
||||
double data = (double)convertedData / 100.0f;
|
||||
return data * 1.60934;
|
||||
}
|
||||
@@ -286,7 +294,12 @@ double bowflext216treadmill::GetDistanceFromPacket(const QByteArray &packet) {
|
||||
}
|
||||
|
||||
double bowflext216treadmill::GetInclinationFromPacket(const QByteArray &packet) {
|
||||
if (bowflex_t6 == false) {
|
||||
if (bowflex_t8j) {
|
||||
uint16_t convertedData = packet.at(6);
|
||||
double data = convertedData;
|
||||
|
||||
return data;
|
||||
} else if (bowflex_t6 == false) {
|
||||
uint16_t convertedData = packet.at(4);
|
||||
double data = convertedData;
|
||||
|
||||
@@ -393,8 +406,22 @@ void bowflext216treadmill::serviceScanDone(void) {
|
||||
QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("15B7BF49-1693-481E-B877-69D33CE6BAFA"));
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
if (gattCommunicationChannelService == nullptr) {
|
||||
qDebug() << "WRONG SERVICE";
|
||||
return;
|
||||
qDebug() << "trying with the BOWFLEX BTX116 treadmill";
|
||||
bowflex_t6 = false;
|
||||
bowflex_btx116 = true;
|
||||
QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("b5c78780-cad7-11e5-b9f8-0002a5d5c51b"));
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
if (gattCommunicationChannelService == nullptr) {
|
||||
qDebug() << "trying with the BOWFLEX T8J treadmill";
|
||||
bowflex_btx116 = false;
|
||||
bowflex_t8j = true;
|
||||
QBluetoothUuid _gattCommunicationChannelServiceId(QStringLiteral("ebbe6870-d00a-4bf4-bb79-63b35bf4c6b5"));
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
if (gattCommunicationChannelService == nullptr) {
|
||||
qDebug() << "WRONG SERVICE";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,8 @@ class bowflext216treadmill : public treadmill {
|
||||
double minStepInclination() override;
|
||||
bool autoPauseWhenSpeedIsZero() override;
|
||||
bool autoStartWhenSpeedIsGreaterThenZero() override;
|
||||
bool canHandleSpeedChange() override { return false; }
|
||||
bool canHandleInclineChange() override { return false; }
|
||||
private:
|
||||
double GetSpeedFromPacket(const QByteArray &packet);
|
||||
double GetInclinationFromPacket(const QByteArray &packet);
|
||||
@@ -74,6 +76,8 @@ class bowflext216treadmill : public treadmill {
|
||||
bool initRequest = false;
|
||||
|
||||
bool bowflex_t6 = false;
|
||||
bool bowflex_btx116 = false;
|
||||
bool bowflex_t8j = false;
|
||||
|
||||
Q_SIGNALS:
|
||||
void disconnected();
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "bowflextreadmill.h"
|
||||
#include "keepawakehelper.h"
|
||||
#include "virtualtreadmill.h"
|
||||
#include "virtualdevices/virtualtreadmill.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -37,6 +37,8 @@ class bowflextreadmill : public treadmill {
|
||||
double minStepInclination() override;
|
||||
bool autoPauseWhenSpeedIsZero() override;
|
||||
bool autoStartWhenSpeedIsGreaterThenZero() override;
|
||||
bool canHandleSpeedChange() override { return false; }
|
||||
bool canHandleInclineChange() override { return false; }
|
||||
|
||||
private:
|
||||
double GetSpeedFromPacket(const QByteArray &packet);
|
||||
@@ -2,7 +2,7 @@
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "keepawakehelper.h"
|
||||
#endif
|
||||
#include "virtualbike.h"
|
||||
#include "virtualdevices/virtualbike.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QFile>
|
||||
@@ -126,6 +126,7 @@ void chronobike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void chronobike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -153,7 +154,7 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
if (watts())
|
||||
KCal +=
|
||||
@@ -161,10 +162,10 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
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
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
//* 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
@@ -190,7 +191,7 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user